| 1 | /* |
| 2 | * Single source autogenerated distributable for Duktape 2.6.0. |
| 3 | * |
| 4 | * Git commit fffa346eff06a8764b02c31d4336f63a773a95c3 (v2.6.0). |
| 5 | * Git branch v2-maintenance. |
| 6 | * |
| 7 | * See Duktape AUTHORS.rst and LICENSE.txt for copyright and |
| 8 | * licensing information. |
| 9 | */ |
| 10 | |
| 11 | /* LICENSE.txt */ |
| 12 | /* |
| 13 | * =============== |
| 14 | * Duktape license |
| 15 | * =============== |
| 16 | * |
| 17 | * (http://opensource.org/licenses/MIT) |
| 18 | * |
| 19 | * Copyright (c) 2013-2019 by Duktape authors (see AUTHORS.rst) |
| 20 | * |
| 21 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 22 | * of this software and associated documentation files (the "Software"), to deal |
| 23 | * in the Software without restriction, including without limitation the rights |
| 24 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 25 | * copies of the Software, and to permit persons to whom the Software is |
| 26 | * furnished to do so, subject to the following conditions: |
| 27 | * |
| 28 | * The above copyright notice and this permission notice shall be included in |
| 29 | * all copies or substantial portions of the Software. |
| 30 | * |
| 31 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 32 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 33 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 34 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 35 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 36 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 37 | * THE SOFTWARE. |
| 38 | */ |
| 39 | |
| 40 | /* AUTHORS.rst */ |
| 41 | /* |
| 42 | * =============== |
| 43 | * Duktape authors |
| 44 | * =============== |
| 45 | * |
| 46 | * Copyright |
| 47 | * ========= |
| 48 | * |
| 49 | * Duktape copyrights are held by its authors. Each author has a copyright |
| 50 | * to their contribution, and agrees to irrevocably license the contribution |
| 51 | * under the Duktape ``LICENSE.txt``. |
| 52 | * |
| 53 | * Authors |
| 54 | * ======= |
| 55 | * |
| 56 | * Please include an e-mail address, a link to your GitHub profile, or something |
| 57 | * similar to allow your contribution to be identified accurately. |
| 58 | * |
| 59 | * The following people have contributed code, website contents, or Wiki contents, |
| 60 | * and agreed to irrevocably license their contributions under the Duktape |
| 61 | * ``LICENSE.txt`` (in order of appearance): |
| 62 | * |
| 63 | * * Sami Vaarala <sami.vaarala@iki.fi> |
| 64 | * * Niki Dobrev |
| 65 | * * Andreas \u00d6man <andreas@lonelycoder.com> |
| 66 | * * L\u00e1szl\u00f3 Lang\u00f3 <llango.u-szeged@partner.samsung.com> |
| 67 | * * Legimet <legimet.calc@gmail.com> |
| 68 | * * Karl Skomski <karl@skomski.com> |
| 69 | * * Bruce Pascoe <fatcerberus1@gmail.com> |
| 70 | * * Ren\u00e9 Hollander <rene@rene8888.at> |
| 71 | * * Julien Hamaide (https://github.com/crazyjul) |
| 72 | * * Sebastian G\u00f6tte (https://github.com/jaseg) |
| 73 | * * Tomasz Magulski (https://github.com/magul) |
| 74 | * * \D. Bohdan (https://github.com/dbohdan) |
| 75 | * * Ond\u0159ej Jirman (https://github.com/megous) |
| 76 | * * Sa\u00fal Ibarra Corretg\u00e9 <saghul@gmail.com> |
| 77 | * * Jeremy HU <huxingyi@msn.com> |
| 78 | * * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) |
| 79 | * * Harold Brenes (https://github.com/harold-b) |
| 80 | * * Oliver Crow (https://github.com/ocrow) |
| 81 | * * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski) |
| 82 | * * Brett Vickers (https://github.com/beevik) |
| 83 | * * Dominik Okwieka (https://github.com/okitec) |
| 84 | * * Remko Tron\u00e7on (https://el-tramo.be) |
| 85 | * * Romero Malaquias (rbsm@ic.ufal.br) |
| 86 | * * Michael Drake <michael.drake@codethink.co.uk> |
| 87 | * * Steven Don (https://github.com/shdon) |
| 88 | * * Simon Stone (https://github.com/sstone1) |
| 89 | * * \J. McC. (https://github.com/jmhmccr) |
| 90 | * * Jakub Nowakowski (https://github.com/jimvonmoon) |
| 91 | * * Tommy Nguyen (https://github.com/tn0502) |
| 92 | * * Fabrice Fontaine (https://github.com/ffontaine) |
| 93 | * * Christopher Hiller (https://github.com/boneskull) |
| 94 | * * Gonzalo Diethelm (https://github.com/gonzus) |
| 95 | * * Michal Kasperek (https://github.com/michalkas) |
| 96 | * * Andrew Janke (https://github.com/apjanke) |
| 97 | * * Steve Fan (https://github.com/stevefan1999) |
| 98 | * * Edward Betts (https://github.com/edwardbetts) |
| 99 | * * Ozhan Duz (https://github.com/webfolderio) |
| 100 | * * Akos Kiss (https://github.com/akosthekiss) |
| 101 | * * TheBrokenRail (https://github.com/TheBrokenRail) |
| 102 | * * Jesse Doyle (https://github.com/jessedoyle) |
| 103 | * * Gero Kuehn (https://github.com/dc6jgk) |
| 104 | * * James Swift (https://github.com/phraemer) |
| 105 | * * Luis de Bethencourt (https://github.com/luisbg) |
| 106 | * * Ian Whyman (https://github.com/v00d00) |
| 107 | * * Rick Sayre (https://github.com/whorfin) |
| 108 | * |
| 109 | * Other contributions |
| 110 | * =================== |
| 111 | * |
| 112 | * The following people have contributed something other than code (e.g. reported |
| 113 | * bugs, provided ideas, etc; roughly in order of appearance): |
| 114 | * |
| 115 | * * Greg Burns |
| 116 | * * Anthony Rabine |
| 117 | * * Carlos Costa |
| 118 | * * Aur\u00e9lien Bouilland |
| 119 | * * Preet Desai (Pris Matic) |
| 120 | * * judofyr (http://www.reddit.com/user/judofyr) |
| 121 | * * Jason Woofenden |
| 122 | * * Micha\u0142 Przyby\u015b |
| 123 | * * Anthony Howe |
| 124 | * * Conrad Pankoff |
| 125 | * * Jim Schimpf |
| 126 | * * Rajaran Gaunker (https://github.com/zimbabao) |
| 127 | * * Andreas \u00d6man |
| 128 | * * Doug Sanden |
| 129 | * * Josh Engebretson (https://github.com/JoshEngebretson) |
| 130 | * * Remo Eichenberger (https://github.com/remoe) |
| 131 | * * Mamod Mehyar (https://github.com/mamod) |
| 132 | * * David Demelier (https://github.com/markand) |
| 133 | * * Tim Caswell (https://github.com/creationix) |
| 134 | * * Mitchell Blank Jr (https://github.com/mitchblank) |
| 135 | * * https://github.com/yushli |
| 136 | * * Seo Sanghyeon (https://github.com/sanxiyn) |
| 137 | * * Han ChoongWoo (https://github.com/tunz) |
| 138 | * * Joshua Peek (https://github.com/josh) |
| 139 | * * Bruce E. Pascoe (https://github.com/fatcerberus) |
| 140 | * * https://github.com/Kelledin |
| 141 | * * https://github.com/sstruchtrup |
| 142 | * * Michael Drake (https://github.com/tlsa) |
| 143 | * * https://github.com/chris-y |
| 144 | * * Laurent Zubiaur (https://github.com/lzubiaur) |
| 145 | * * Neil Kolban (https://github.com/nkolban) |
| 146 | * * Wilhelm Wanecek (https://github.com/wanecek) |
| 147 | * * Andrew Janke (https://github.com/apjanke) |
| 148 | * * Unamer (https://github.com/unamer) |
| 149 | * * Karl Dahlke (eklhad@gmail.com) |
| 150 | * |
| 151 | * If you are accidentally missing from this list, send me an e-mail |
| 152 | * (``sami.vaarala@iki.fi``) and I'll fix the omission. |
| 153 | */ |
| 154 | |
| 155 | #line 1 "duk_replacements.c" |
| 156 | /* |
| 157 | * Replacements for missing platform functions. |
| 158 | * |
| 159 | * Unlike the originals, fpclassify() and signbit() replacements don't |
| 160 | * work on any floating point types, only doubles. The C typing here |
| 161 | * mimics the standard prototypes. |
| 162 | */ |
| 163 | |
| 164 | /* #include duk_internal.h */ |
| 165 | #line 1 "duk_internal.h" |
| 166 | /* |
| 167 | * Top-level include file to be used for all (internal) source files. |
| 168 | * |
| 169 | * Source files should not include individual header files, as they |
| 170 | * have not been designed to be individually included. |
| 171 | */ |
| 172 | |
| 173 | #if !defined(DUK_INTERNAL_H_INCLUDED) |
| 174 | #define DUK_INTERNAL_H_INCLUDED |
| 175 | |
| 176 | /* |
| 177 | * The 'duktape.h' header provides the public API, but also handles all |
| 178 | * compiler and platform specific feature detection, Duktape feature |
| 179 | * resolution, inclusion of system headers, etc. These have been merged |
| 180 | * because the public API is also dependent on e.g. detecting appropriate |
| 181 | * C types which is quite platform/compiler specific especially for a non-C99 |
| 182 | * build. The public API is also dependent on the resolved feature set. |
| 183 | * |
| 184 | * Some actions taken by the merged header (such as including system headers) |
| 185 | * are not appropriate for building a user application. The define |
| 186 | * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some |
| 187 | * sections depending on what is being built. |
| 188 | */ |
| 189 | |
| 190 | #define DUK_COMPILING_DUKTAPE |
| 191 | #include "duktape.h" |
| 192 | |
| 193 | /* |
| 194 | * Duktape includes (other than duk_features.h) |
| 195 | * |
| 196 | * The header files expect to be included in an order which satisfies header |
| 197 | * dependencies correctly (the headers themselves don't include any other |
| 198 | * includes). Forward declarations are used to break circular struct/typedef |
| 199 | * dependencies. |
| 200 | */ |
| 201 | |
| 202 | /* #include duk_dblunion.h */ |
| 203 | #line 1 "duk_dblunion.h" |
| 204 | /* |
| 205 | * Union to access IEEE double memory representation, indexes for double |
| 206 | * memory representation, and some macros for double manipulation. |
| 207 | * |
| 208 | * Also used by packed duk_tval. Use a union for bit manipulation to |
| 209 | * minimize aliasing issues in practice. The C99 standard does not |
| 210 | * guarantee that this should work, but it's a very widely supported |
| 211 | * practice for low level manipulation. |
| 212 | * |
| 213 | * IEEE double format summary: |
| 214 | * |
| 215 | * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff |
| 216 | * A B C D E F G H |
| 217 | * |
| 218 | * s sign bit |
| 219 | * eee... exponent field |
| 220 | * fff... fraction |
| 221 | * |
| 222 | * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format. |
| 223 | * |
| 224 | * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a |
| 225 | * signaling NaN when the highest bit of the mantissa is zero, and a quiet |
| 226 | * NaN when the highest bit is set. |
| 227 | * |
| 228 | * At least three memory layouts are relevant here: |
| 229 | * |
| 230 | * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE |
| 231 | * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE |
| 232 | * D C B A H G F E Mixed endian (e.g. ARM FPA) DUK_USE_DOUBLE_ME |
| 233 | * |
| 234 | * Legacy ARM (FPA) is a special case: ARM double values are in mixed |
| 235 | * endian format while ARM duk_uint64_t values are in standard little endian |
| 236 | * format (H G F E D C B A). When a double is read as a duk_uint64_t |
| 237 | * from memory, the register will contain the (logical) value |
| 238 | * E F G H A B C D. This requires some special handling below. |
| 239 | * See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcfhgcgd.html. |
| 240 | * |
| 241 | * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to |
| 242 | * the logical (big endian) order: |
| 243 | * |
| 244 | * byte order duk_uint8_t duk_uint16_t duk_uint32_t |
| 245 | * BE 01234567 0123 01 |
| 246 | * LE 76543210 3210 10 |
| 247 | * ME (ARM) 32107654 1032 01 |
| 248 | * |
| 249 | * Some processors may alter NaN values in a floating point load+store. |
| 250 | * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a |
| 251 | * quiet one. This is catastrophic when NaN space is used in packed |
| 252 | * duk_tval values. See: misc/clang_aliasing.c. |
| 253 | */ |
| 254 | |
| 255 | #if !defined(DUK_DBLUNION_H_INCLUDED) |
| 256 | #define DUK_DBLUNION_H_INCLUDED |
| 257 | |
| 258 | /* |
| 259 | * Union for accessing double parts, also serves as packed duk_tval |
| 260 | */ |
| 261 | |
| 262 | union duk_double_union { |
| 263 | double d; |
| 264 | float f[2]; |
| 265 | #if defined(DUK_USE_64BIT_OPS) |
| 266 | duk_uint64_t ull[1]; |
| 267 | #endif |
| 268 | duk_uint32_t ui[2]; |
| 269 | duk_uint16_t us[4]; |
| 270 | duk_uint8_t uc[8]; |
| 271 | #if defined(DUK_USE_PACKED_TVAL) |
| 272 | void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */ |
| 273 | #endif |
| 274 | }; |
| 275 | |
| 276 | typedef union duk_double_union duk_double_union; |
| 277 | |
| 278 | /* |
| 279 | * Indexes of various types with respect to big endian (logical) layout |
| 280 | */ |
| 281 | |
| 282 | #if defined(DUK_USE_DOUBLE_LE) |
| 283 | #if defined(DUK_USE_64BIT_OPS) |
| 284 | #define DUK_DBL_IDX_ULL0 0 |
| 285 | #endif |
| 286 | #define DUK_DBL_IDX_UI0 1 |
| 287 | #define DUK_DBL_IDX_UI1 0 |
| 288 | #define DUK_DBL_IDX_US0 3 |
| 289 | #define DUK_DBL_IDX_US1 2 |
| 290 | #define DUK_DBL_IDX_US2 1 |
| 291 | #define DUK_DBL_IDX_US3 0 |
| 292 | #define DUK_DBL_IDX_UC0 7 |
| 293 | #define DUK_DBL_IDX_UC1 6 |
| 294 | #define DUK_DBL_IDX_UC2 5 |
| 295 | #define DUK_DBL_IDX_UC3 4 |
| 296 | #define DUK_DBL_IDX_UC4 3 |
| 297 | #define DUK_DBL_IDX_UC5 2 |
| 298 | #define DUK_DBL_IDX_UC6 1 |
| 299 | #define DUK_DBL_IDX_UC7 0 |
| 300 | #define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ |
| 301 | #define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ |
| 302 | #elif defined(DUK_USE_DOUBLE_BE) |
| 303 | #if defined(DUK_USE_64BIT_OPS) |
| 304 | #define DUK_DBL_IDX_ULL0 0 |
| 305 | #endif |
| 306 | #define DUK_DBL_IDX_UI0 0 |
| 307 | #define DUK_DBL_IDX_UI1 1 |
| 308 | #define DUK_DBL_IDX_US0 0 |
| 309 | #define DUK_DBL_IDX_US1 1 |
| 310 | #define DUK_DBL_IDX_US2 2 |
| 311 | #define DUK_DBL_IDX_US3 3 |
| 312 | #define DUK_DBL_IDX_UC0 0 |
| 313 | #define DUK_DBL_IDX_UC1 1 |
| 314 | #define DUK_DBL_IDX_UC2 2 |
| 315 | #define DUK_DBL_IDX_UC3 3 |
| 316 | #define DUK_DBL_IDX_UC4 4 |
| 317 | #define DUK_DBL_IDX_UC5 5 |
| 318 | #define DUK_DBL_IDX_UC6 6 |
| 319 | #define DUK_DBL_IDX_UC7 7 |
| 320 | #define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ |
| 321 | #define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ |
| 322 | #elif defined(DUK_USE_DOUBLE_ME) |
| 323 | #if defined(DUK_USE_64BIT_OPS) |
| 324 | #define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */ |
| 325 | #endif |
| 326 | #define DUK_DBL_IDX_UI0 0 |
| 327 | #define DUK_DBL_IDX_UI1 1 |
| 328 | #define DUK_DBL_IDX_US0 1 |
| 329 | #define DUK_DBL_IDX_US1 0 |
| 330 | #define DUK_DBL_IDX_US2 3 |
| 331 | #define DUK_DBL_IDX_US3 2 |
| 332 | #define DUK_DBL_IDX_UC0 3 |
| 333 | #define DUK_DBL_IDX_UC1 2 |
| 334 | #define DUK_DBL_IDX_UC2 1 |
| 335 | #define DUK_DBL_IDX_UC3 0 |
| 336 | #define DUK_DBL_IDX_UC4 7 |
| 337 | #define DUK_DBL_IDX_UC5 6 |
| 338 | #define DUK_DBL_IDX_UC6 5 |
| 339 | #define DUK_DBL_IDX_UC7 4 |
| 340 | #define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */ |
| 341 | #define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */ |
| 342 | #else |
| 343 | #error internal error |
| 344 | #endif |
| 345 | |
| 346 | /* |
| 347 | * Helper macros for reading/writing memory representation parts, used |
| 348 | * by duk_numconv.c and duk_tval.h. |
| 349 | */ |
| 350 | |
| 351 | #define DUK_DBLUNION_SET_DOUBLE(u,v) do { \ |
| 352 | (u)->d = (v); \ |
| 353 | } while (0) |
| 354 | |
| 355 | #define DUK_DBLUNION_SET_HIGH32(u,v) do { \ |
| 356 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ |
| 357 | } while (0) |
| 358 | |
| 359 | #if defined(DUK_USE_64BIT_OPS) |
| 360 | #if defined(DUK_USE_DOUBLE_ME) |
| 361 | #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ |
| 362 | (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ |
| 363 | } while (0) |
| 364 | #else |
| 365 | #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ |
| 366 | (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \ |
| 367 | } while (0) |
| 368 | #endif |
| 369 | #else /* DUK_USE_64BIT_OPS */ |
| 370 | #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \ |
| 371 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \ |
| 372 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \ |
| 373 | } while (0) |
| 374 | #endif /* DUK_USE_64BIT_OPS */ |
| 375 | |
| 376 | #define DUK_DBLUNION_SET_LOW32(u,v) do { \ |
| 377 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ |
| 378 | } while (0) |
| 379 | |
| 380 | #define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d) |
| 381 | #define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0]) |
| 382 | #define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1]) |
| 383 | |
| 384 | #if defined(DUK_USE_64BIT_OPS) |
| 385 | #if defined(DUK_USE_DOUBLE_ME) |
| 386 | #define DUK_DBLUNION_SET_UINT64(u,v) do { \ |
| 387 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \ |
| 388 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \ |
| 389 | } while (0) |
| 390 | #define DUK_DBLUNION_GET_UINT64(u) \ |
| 391 | ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \ |
| 392 | ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1])) |
| 393 | #else |
| 394 | #define DUK_DBLUNION_SET_UINT64(u,v) do { \ |
| 395 | (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \ |
| 396 | } while (0) |
| 397 | #define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0]) |
| 398 | #endif |
| 399 | #define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v)) |
| 400 | #define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u))) |
| 401 | #endif /* DUK_USE_64BIT_OPS */ |
| 402 | |
| 403 | /* |
| 404 | * Double NaN manipulation macros related to NaN normalization needed when |
| 405 | * using the packed duk_tval representation. NaN normalization is necessary |
| 406 | * to keep double values compatible with the duk_tval format. |
| 407 | * |
| 408 | * When packed duk_tval is used, the NaN space is used to store pointers |
| 409 | * and other tagged values in addition to NaNs. Actual NaNs are normalized |
| 410 | * to a specific quiet NaN. The macros below are used by the implementation |
| 411 | * to check and normalize NaN values when they might be created. The macros |
| 412 | * are essentially NOPs when the non-packed duk_tval representation is used. |
| 413 | * |
| 414 | * A FULL check is exact and checks all bits. A NOTFULL check is used by |
| 415 | * the packed duk_tval and works correctly for all NaNs except those that |
| 416 | * begin with 0x7ff0. Since the 'normalized NaN' values used with packed |
| 417 | * duk_tval begin with 0x7ff8, the partial check is reliable when packed |
| 418 | * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a |
| 419 | * quiet NaN regardless of its remaining lower bits. |
| 420 | * |
| 421 | * The ME variant below is specifically for ARM byte order, which has the |
| 422 | * feature that while doubles have a mixed byte order (32107654), unsigned |
| 423 | * long long values has a little endian byte order (76543210). When writing |
| 424 | * a logical double value through a ULL pointer, the 32-bit words need to be |
| 425 | * swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME. |
| 426 | * This is not full ARM support but suffices for some environments. |
| 427 | */ |
| 428 | |
| 429 | #if defined(DUK_USE_64BIT_OPS) |
| 430 | #if defined(DUK_USE_DOUBLE_ME) |
| 431 | /* Macros for 64-bit ops + mixed endian doubles. */ |
| 432 | #define DUK__DBLUNION_SET_NAN_FULL(u) do { \ |
| 433 | (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \ |
| 434 | } while (0) |
| 435 | #define DUK__DBLUNION_IS_NAN_FULL(u) \ |
| 436 | ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \ |
| 437 | ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0)) |
| 438 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ |
| 439 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000)) |
| 440 | #define DUK__DBLUNION_IS_ANYINF(u) \ |
| 441 | (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000)) |
| 442 | #define DUK__DBLUNION_IS_POSINF(u) \ |
| 443 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000)) |
| 444 | #define DUK__DBLUNION_IS_NEGINF(u) \ |
| 445 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000)) |
| 446 | #define DUK__DBLUNION_IS_ANYZERO(u) \ |
| 447 | (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000)) |
| 448 | #define DUK__DBLUNION_IS_POSZERO(u) \ |
| 449 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000)) |
| 450 | #define DUK__DBLUNION_IS_NEGZERO(u) \ |
| 451 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000)) |
| 452 | #else |
| 453 | /* Macros for 64-bit ops + big/little endian doubles. */ |
| 454 | #define DUK__DBLUNION_SET_NAN_FULL(u) do { \ |
| 455 | (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \ |
| 456 | } while (0) |
| 457 | #define DUK__DBLUNION_IS_NAN_FULL(u) \ |
| 458 | ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \ |
| 459 | ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0)) |
| 460 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ |
| 461 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000)) |
| 462 | #define DUK__DBLUNION_IS_ANYINF(u) \ |
| 463 | (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000)) |
| 464 | #define DUK__DBLUNION_IS_POSINF(u) \ |
| 465 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000)) |
| 466 | #define DUK__DBLUNION_IS_NEGINF(u) \ |
| 467 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000)) |
| 468 | #define DUK__DBLUNION_IS_ANYZERO(u) \ |
| 469 | (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000)) |
| 470 | #define DUK__DBLUNION_IS_POSZERO(u) \ |
| 471 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000)) |
| 472 | #define DUK__DBLUNION_IS_NEGZERO(u) \ |
| 473 | ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000)) |
| 474 | #endif |
| 475 | #else /* DUK_USE_64BIT_OPS */ |
| 476 | /* Macros for no 64-bit ops, any endianness. */ |
| 477 | #define DUK__DBLUNION_SET_NAN_FULL(u) do { \ |
| 478 | (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \ |
| 479 | (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \ |
| 480 | } while (0) |
| 481 | #define DUK__DBLUNION_IS_NAN_FULL(u) \ |
| 482 | ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \ |
| 483 | (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \ |
| 484 | (u)->ui[DUK_DBL_IDX_UI1] != 0)) |
| 485 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \ |
| 486 | (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \ |
| 487 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) |
| 488 | #define DUK__DBLUNION_IS_ANYINF(u) \ |
| 489 | ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \ |
| 490 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) |
| 491 | #define DUK__DBLUNION_IS_POSINF(u) \ |
| 492 | (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \ |
| 493 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) |
| 494 | #define DUK__DBLUNION_IS_NEGINF(u) \ |
| 495 | (((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \ |
| 496 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) |
| 497 | #define DUK__DBLUNION_IS_ANYZERO(u) \ |
| 498 | ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \ |
| 499 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) |
| 500 | #define DUK__DBLUNION_IS_POSZERO(u) \ |
| 501 | (((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \ |
| 502 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) |
| 503 | #define DUK__DBLUNION_IS_NEGZERO(u) \ |
| 504 | (((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \ |
| 505 | ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL)) |
| 506 | #endif /* DUK_USE_64BIT_OPS */ |
| 507 | |
| 508 | #define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \ |
| 509 | (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \ |
| 510 | } while (0) |
| 511 | |
| 512 | #define DUK__DBLUNION_IS_NAN_NOTFULL(u) \ |
| 513 | /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \ |
| 514 | ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \ |
| 515 | (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL)) |
| 516 | |
| 517 | #define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \ |
| 518 | /* E == 0x7ff, F == 8 => normalized NaN */ \ |
| 519 | ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL) |
| 520 | |
| 521 | #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \ |
| 522 | if (DUK__DBLUNION_IS_NAN_FULL((u))) { \ |
| 523 | DUK__DBLUNION_SET_NAN_FULL((u)); \ |
| 524 | } \ |
| 525 | } while (0) |
| 526 | |
| 527 | #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \ |
| 528 | /* Check must be full. */ \ |
| 529 | if (DUK__DBLUNION_IS_NAN_FULL((u))) { \ |
| 530 | DUK__DBLUNION_SET_NAN_NOTFULL((u)); \ |
| 531 | } \ |
| 532 | } while (0) |
| 533 | |
| 534 | /* Concrete macros for NaN handling used by the implementation internals. |
| 535 | * Chosen so that they match the duk_tval representation: with a packed |
| 536 | * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval |
| 537 | * these are essentially NOPs. |
| 538 | */ |
| 539 | |
| 540 | #if defined(DUK_USE_PACKED_TVAL) |
| 541 | #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u)) |
| 542 | #define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) |
| 543 | #define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u)) |
| 544 | #define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d)) |
| 545 | #if 0 |
| 546 | #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u)) |
| 547 | #define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u)) |
| 548 | #define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u)) |
| 549 | #define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d)) |
| 550 | #endif |
| 551 | #define DUK_DBLUNION_IS_NORMALIZED(u) \ |
| 552 | (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \ |
| 553 | DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */ |
| 554 | #else /* DUK_USE_PACKED_TVAL */ |
| 555 | #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */ |
| 556 | #define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */ |
| 557 | #define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */ |
| 558 | #define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */ |
| 559 | #define DUK_DBLUNION_SET_NAN(u) do { \ |
| 560 | /* in non-packed representation we don't care about which NaN is used */ \ |
| 561 | (u)->d = DUK_DOUBLE_NAN; \ |
| 562 | } while (0) |
| 563 | #endif /* DUK_USE_PACKED_TVAL */ |
| 564 | |
| 565 | #define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u)) |
| 566 | #define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u)) |
| 567 | #define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u)) |
| 568 | |
| 569 | #define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u)) |
| 570 | #define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u)) |
| 571 | #define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u)) |
| 572 | |
| 573 | /* XXX: native 64-bit byteswaps when available */ |
| 574 | |
| 575 | /* 64-bit byteswap, same operation independent of target endianness. */ |
| 576 | #define DUK_DBLUNION_BSWAP64(u) do { \ |
| 577 | duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ |
| 578 | duk__bswaptmp1 = (u)->ui[0]; \ |
| 579 | duk__bswaptmp2 = (u)->ui[1]; \ |
| 580 | duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ |
| 581 | duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ |
| 582 | (u)->ui[0] = duk__bswaptmp2; \ |
| 583 | (u)->ui[1] = duk__bswaptmp1; \ |
| 584 | } while (0) |
| 585 | |
| 586 | /* Byteswap an IEEE double in the duk_double_union from host to network |
| 587 | * order. For a big endian target this is a no-op. |
| 588 | */ |
| 589 | #if defined(DUK_USE_DOUBLE_LE) |
| 590 | #define DUK_DBLUNION_DOUBLE_HTON(u) do { \ |
| 591 | duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ |
| 592 | duk__bswaptmp1 = (u)->ui[0]; \ |
| 593 | duk__bswaptmp2 = (u)->ui[1]; \ |
| 594 | duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ |
| 595 | duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ |
| 596 | (u)->ui[0] = duk__bswaptmp2; \ |
| 597 | (u)->ui[1] = duk__bswaptmp1; \ |
| 598 | } while (0) |
| 599 | #elif defined(DUK_USE_DOUBLE_ME) |
| 600 | #define DUK_DBLUNION_DOUBLE_HTON(u) do { \ |
| 601 | duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \ |
| 602 | duk__bswaptmp1 = (u)->ui[0]; \ |
| 603 | duk__bswaptmp2 = (u)->ui[1]; \ |
| 604 | duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \ |
| 605 | duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \ |
| 606 | (u)->ui[0] = duk__bswaptmp1; \ |
| 607 | (u)->ui[1] = duk__bswaptmp2; \ |
| 608 | } while (0) |
| 609 | #elif defined(DUK_USE_DOUBLE_BE) |
| 610 | #define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0) |
| 611 | #else |
| 612 | #error internal error, double endianness insane |
| 613 | #endif |
| 614 | |
| 615 | /* Reverse operation is the same. */ |
| 616 | #define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u)) |
| 617 | |
| 618 | /* Some sign bit helpers. */ |
| 619 | #if defined(DUK_USE_64BIT_OPS) |
| 620 | #define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0) |
| 621 | #define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U)) |
| 622 | #else |
| 623 | #define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0) |
| 624 | #define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U)) |
| 625 | #endif |
| 626 | |
| 627 | #endif /* DUK_DBLUNION_H_INCLUDED */ |
| 628 | /* #include duk_fltunion.h */ |
| 629 | #line 1 "duk_fltunion.h" |
| 630 | /* |
| 631 | * Union to access IEEE float memory representation. |
| 632 | */ |
| 633 | |
| 634 | #if !defined(DUK_FLTUNION_H_INCLUDED) |
| 635 | #define DUK_FLTUNION_H_INCLUDED |
| 636 | |
| 637 | /* #include duk_internal.h -> already included */ |
| 638 | |
| 639 | union duk_float_union { |
| 640 | float f; |
| 641 | duk_uint32_t ui[1]; |
| 642 | duk_uint16_t us[2]; |
| 643 | duk_uint8_t uc[4]; |
| 644 | }; |
| 645 | |
| 646 | typedef union duk_float_union duk_float_union; |
| 647 | |
| 648 | #if defined(DUK_USE_DOUBLE_LE) || defined(DUK_USE_DOUBLE_ME) |
| 649 | #define DUK_FLT_IDX_UI0 0 |
| 650 | #define DUK_FLT_IDX_US0 1 |
| 651 | #define DUK_FLT_IDX_US1 0 |
| 652 | #define DUK_FLT_IDX_UC0 3 |
| 653 | #define DUK_FLT_IDX_UC1 2 |
| 654 | #define DUK_FLT_IDX_UC2 1 |
| 655 | #define DUK_FLT_IDX_UC3 0 |
| 656 | #elif defined(DUK_USE_DOUBLE_BE) |
| 657 | #define DUK_FLT_IDX_UI0 0 |
| 658 | #define DUK_FLT_IDX_US0 0 |
| 659 | #define DUK_FLT_IDX_US1 1 |
| 660 | #define DUK_FLT_IDX_UC0 0 |
| 661 | #define DUK_FLT_IDX_UC1 1 |
| 662 | #define DUK_FLT_IDX_UC2 2 |
| 663 | #define DUK_FLT_IDX_UC3 3 |
| 664 | #else |
| 665 | #error internal error |
| 666 | #endif |
| 667 | |
| 668 | #endif /* DUK_FLTUNION_H_INCLUDED */ |
| 669 | /* #include duk_replacements.h */ |
| 670 | #line 1 "duk_replacements.h" |
| 671 | #if !defined(DUK_REPLACEMENTS_H_INCLUDED) |
| 672 | #define DUK_REPLACEMENTS_H_INCLUDED |
| 673 | |
| 674 | #if !defined(DUK_SINGLE_FILE) |
| 675 | #if defined(DUK_USE_COMPUTED_INFINITY) |
| 676 | DUK_INTERNAL_DECL double duk_computed_infinity; |
| 677 | #endif |
| 678 | #if defined(DUK_USE_COMPUTED_NAN) |
| 679 | DUK_INTERNAL_DECL double duk_computed_nan; |
| 680 | #endif |
| 681 | #endif /* !DUK_SINGLE_FILE */ |
| 682 | |
| 683 | #if defined(DUK_USE_REPL_FPCLASSIFY) |
| 684 | DUK_INTERNAL_DECL int duk_repl_fpclassify(double x); |
| 685 | #endif |
| 686 | #if defined(DUK_USE_REPL_SIGNBIT) |
| 687 | DUK_INTERNAL_DECL int duk_repl_signbit(double x); |
| 688 | #endif |
| 689 | #if defined(DUK_USE_REPL_ISFINITE) |
| 690 | DUK_INTERNAL_DECL int duk_repl_isfinite(double x); |
| 691 | #endif |
| 692 | #if defined(DUK_USE_REPL_ISNAN) |
| 693 | DUK_INTERNAL_DECL int duk_repl_isnan(double x); |
| 694 | #endif |
| 695 | #if defined(DUK_USE_REPL_ISINF) |
| 696 | DUK_INTERNAL_DECL int duk_repl_isinf(double x); |
| 697 | #endif |
| 698 | |
| 699 | #endif /* DUK_REPLACEMENTS_H_INCLUDED */ |
| 700 | /* #include duk_jmpbuf.h */ |
| 701 | #line 1 "duk_jmpbuf.h" |
| 702 | /* |
| 703 | * Wrapper for jmp_buf. |
| 704 | * |
| 705 | * This is used because jmp_buf is an array type for backward compatibility. |
| 706 | * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc, |
| 707 | * behave more intuitively. |
| 708 | * |
| 709 | * http://en.wikipedia.org/wiki/Setjmp.h#Member_types |
| 710 | */ |
| 711 | |
| 712 | #if !defined(DUK_JMPBUF_H_INCLUDED) |
| 713 | #define DUK_JMPBUF_H_INCLUDED |
| 714 | |
| 715 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 716 | struct duk_jmpbuf { |
| 717 | duk_small_int_t dummy; /* unused */ |
| 718 | }; |
| 719 | #else |
| 720 | struct duk_jmpbuf { |
| 721 | DUK_JMPBUF_TYPE jb; |
| 722 | }; |
| 723 | #endif |
| 724 | |
| 725 | #endif /* DUK_JMPBUF_H_INCLUDED */ |
| 726 | /* #include duk_exception.h */ |
| 727 | #line 1 "duk_exception.h" |
| 728 | /* |
| 729 | * Exceptions for Duktape internal throws when C++ exceptions are used |
| 730 | * for long control transfers. |
| 731 | */ |
| 732 | |
| 733 | #if !defined(DUK_EXCEPTION_H_INCLUDED) |
| 734 | #define DUK_EXCEPTION_H_INCLUDED |
| 735 | |
| 736 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 737 | /* Internal exception used as a setjmp-longjmp replacement. User code should |
| 738 | * NEVER see or catch this exception, so it doesn't inherit from any base |
| 739 | * class which should minimize the chance of user code accidentally catching |
| 740 | * the exception. |
| 741 | */ |
| 742 | class duk_internal_exception { |
| 743 | /* intentionally empty */ |
| 744 | }; |
| 745 | |
| 746 | /* Fatal error, thrown as a specific C++ exception with C++ exceptions |
| 747 | * enabled. It is unsafe to continue; doing so may cause crashes or memory |
| 748 | * leaks. This is intended to be either uncaught, or caught by user code |
| 749 | * aware of the "unsafe to continue" semantics. |
| 750 | */ |
| 751 | class duk_fatal_exception : public virtual std::runtime_error { |
| 752 | public: |
| 753 | duk_fatal_exception(const char *message) : std::runtime_error(message) {} |
| 754 | }; |
| 755 | #endif |
| 756 | |
| 757 | #endif /* DUK_EXCEPTION_H_INCLUDED */ |
| 758 | /* #include duk_forwdecl.h */ |
| 759 | #line 1 "duk_forwdecl.h" |
| 760 | /* |
| 761 | * Forward declarations for all Duktape structures. |
| 762 | */ |
| 763 | |
| 764 | #if !defined(DUK_FORWDECL_H_INCLUDED) |
| 765 | #define DUK_FORWDECL_H_INCLUDED |
| 766 | |
| 767 | /* |
| 768 | * Forward declarations |
| 769 | */ |
| 770 | |
| 771 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 772 | class duk_internal_exception; |
| 773 | #else |
| 774 | struct duk_jmpbuf; |
| 775 | #endif |
| 776 | |
| 777 | /* duk_tval intentionally skipped */ |
| 778 | struct duk_heaphdr; |
| 779 | struct duk_heaphdr_string; |
| 780 | struct duk_harray; |
| 781 | struct duk_hstring; |
| 782 | struct duk_hstring_external; |
| 783 | struct duk_hobject; |
| 784 | struct duk_hcompfunc; |
| 785 | struct duk_hnatfunc; |
| 786 | struct duk_hboundfunc; |
| 787 | struct duk_hthread; |
| 788 | struct duk_hbufobj; |
| 789 | struct duk_hdecenv; |
| 790 | struct duk_hobjenv; |
| 791 | struct duk_hproxy; |
| 792 | struct duk_hbuffer; |
| 793 | struct duk_hbuffer_fixed; |
| 794 | struct duk_hbuffer_dynamic; |
| 795 | struct duk_hbuffer_external; |
| 796 | |
| 797 | struct duk_propaccessor; |
| 798 | union duk_propvalue; |
| 799 | struct duk_propdesc; |
| 800 | |
| 801 | struct duk_heap; |
| 802 | struct duk_breakpoint; |
| 803 | |
| 804 | struct duk_activation; |
| 805 | struct duk_catcher; |
| 806 | struct duk_ljstate; |
| 807 | struct duk_strcache_entry; |
| 808 | struct duk_litcache_entry; |
| 809 | struct duk_strtab_entry; |
| 810 | |
| 811 | #if defined(DUK_USE_DEBUG) |
| 812 | struct duk_fixedbuffer; |
| 813 | #endif |
| 814 | |
| 815 | struct duk_bitdecoder_ctx; |
| 816 | struct duk_bitencoder_ctx; |
| 817 | struct duk_bufwriter_ctx; |
| 818 | |
| 819 | struct duk_token; |
| 820 | struct duk_re_token; |
| 821 | struct duk_lexer_point; |
| 822 | struct duk_lexer_ctx; |
| 823 | struct duk_lexer_codepoint; |
| 824 | |
| 825 | struct duk_compiler_instr; |
| 826 | struct duk_compiler_func; |
| 827 | struct duk_compiler_ctx; |
| 828 | |
| 829 | struct duk_re_matcher_ctx; |
| 830 | struct duk_re_compiler_ctx; |
| 831 | |
| 832 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 833 | /* no typedef */ |
| 834 | #else |
| 835 | typedef struct duk_jmpbuf duk_jmpbuf; |
| 836 | #endif |
| 837 | |
| 838 | /* duk_tval intentionally skipped */ |
| 839 | typedef struct duk_heaphdr duk_heaphdr; |
| 840 | typedef struct duk_heaphdr_string duk_heaphdr_string; |
| 841 | typedef struct duk_harray duk_harray; |
| 842 | typedef struct duk_hstring duk_hstring; |
| 843 | typedef struct duk_hstring_external duk_hstring_external; |
| 844 | typedef struct duk_hobject duk_hobject; |
| 845 | typedef struct duk_hcompfunc duk_hcompfunc; |
| 846 | typedef struct duk_hnatfunc duk_hnatfunc; |
| 847 | typedef struct duk_hboundfunc duk_hboundfunc; |
| 848 | typedef struct duk_hthread duk_hthread; |
| 849 | typedef struct duk_hbufobj duk_hbufobj; |
| 850 | typedef struct duk_hdecenv duk_hdecenv; |
| 851 | typedef struct duk_hobjenv duk_hobjenv; |
| 852 | typedef struct duk_hproxy duk_hproxy; |
| 853 | typedef struct duk_hbuffer duk_hbuffer; |
| 854 | typedef struct duk_hbuffer_fixed duk_hbuffer_fixed; |
| 855 | typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic; |
| 856 | typedef struct duk_hbuffer_external duk_hbuffer_external; |
| 857 | |
| 858 | typedef struct duk_propaccessor duk_propaccessor; |
| 859 | typedef union duk_propvalue duk_propvalue; |
| 860 | typedef struct duk_propdesc duk_propdesc; |
| 861 | |
| 862 | typedef struct duk_heap duk_heap; |
| 863 | typedef struct duk_breakpoint duk_breakpoint; |
| 864 | |
| 865 | typedef struct duk_activation duk_activation; |
| 866 | typedef struct duk_catcher duk_catcher; |
| 867 | typedef struct duk_ljstate duk_ljstate; |
| 868 | typedef struct duk_strcache_entry duk_strcache_entry; |
| 869 | typedef struct duk_litcache_entry duk_litcache_entry; |
| 870 | typedef struct duk_strtab_entry duk_strtab_entry; |
| 871 | |
| 872 | #if defined(DUK_USE_DEBUG) |
| 873 | typedef struct duk_fixedbuffer duk_fixedbuffer; |
| 874 | #endif |
| 875 | |
| 876 | typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx; |
| 877 | typedef struct duk_bitencoder_ctx duk_bitencoder_ctx; |
| 878 | typedef struct duk_bufwriter_ctx duk_bufwriter_ctx; |
| 879 | |
| 880 | typedef struct duk_token duk_token; |
| 881 | typedef struct duk_re_token duk_re_token; |
| 882 | typedef struct duk_lexer_point duk_lexer_point; |
| 883 | typedef struct duk_lexer_ctx duk_lexer_ctx; |
| 884 | typedef struct duk_lexer_codepoint duk_lexer_codepoint; |
| 885 | |
| 886 | typedef struct duk_compiler_instr duk_compiler_instr; |
| 887 | typedef struct duk_compiler_func duk_compiler_func; |
| 888 | typedef struct duk_compiler_ctx duk_compiler_ctx; |
| 889 | |
| 890 | typedef struct duk_re_matcher_ctx duk_re_matcher_ctx; |
| 891 | typedef struct duk_re_compiler_ctx duk_re_compiler_ctx; |
| 892 | |
| 893 | #endif /* DUK_FORWDECL_H_INCLUDED */ |
| 894 | /* #include duk_tval.h */ |
| 895 | #line 1 "duk_tval.h" |
| 896 | /* |
| 897 | * Tagged type definition (duk_tval) and accessor macros. |
| 898 | * |
| 899 | * Access all fields through the accessor macros, as the representation |
| 900 | * is quite tricky. |
| 901 | * |
| 902 | * There are two packed type alternatives: an 8-byte representation |
| 903 | * based on an IEEE double (preferred for compactness), and a 12-byte |
| 904 | * representation (portability). The latter is needed also in e.g. |
| 905 | * 64-bit environments (it usually pads to 16 bytes per value). |
| 906 | * |
| 907 | * Selecting the tagged type format involves many trade-offs (memory |
| 908 | * use, size and performance of generated code, portability, etc). |
| 909 | * |
| 910 | * NB: because macro arguments are often expressions, macros should |
| 911 | * avoid evaluating their argument more than once. |
| 912 | */ |
| 913 | |
| 914 | #if !defined(DUK_TVAL_H_INCLUDED) |
| 915 | #define DUK_TVAL_H_INCLUDED |
| 916 | |
| 917 | /* sanity */ |
| 918 | #if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE) |
| 919 | #error unsupported: cannot determine byte order variant |
| 920 | #endif |
| 921 | |
| 922 | #if defined(DUK_USE_PACKED_TVAL) |
| 923 | /* ======================================================================== */ |
| 924 | |
| 925 | /* |
| 926 | * Packed 8-byte representation |
| 927 | */ |
| 928 | |
| 929 | /* use duk_double_union as duk_tval directly */ |
| 930 | typedef union duk_double_union duk_tval; |
| 931 | typedef struct { |
| 932 | duk_uint16_t a; |
| 933 | duk_uint16_t b; |
| 934 | duk_uint16_t c; |
| 935 | duk_uint16_t d; |
| 936 | } duk_tval_unused; |
| 937 | |
| 938 | /* tags */ |
| 939 | #define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */ |
| 940 | /* avoid tag 0xfff0, no risk of confusion with negative infinity */ |
| 941 | #define DUK_TAG_MIN 0xfff1UL |
| 942 | #if defined(DUK_USE_FASTINT) |
| 943 | #define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */ |
| 944 | #endif |
| 945 | #define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */ |
| 946 | #define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */ |
| 947 | #define DUK_TAG_NULL 0xfff4UL /* embed: nothing */ |
| 948 | #define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */ |
| 949 | /* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */ |
| 950 | #define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */ |
| 951 | #define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */ |
| 952 | #define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */ |
| 953 | #define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */ |
| 954 | #define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */ |
| 955 | #define DUK_TAG_MAX 0xfffaUL |
| 956 | |
| 957 | /* for convenience */ |
| 958 | #define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL |
| 959 | #define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL |
| 960 | |
| 961 | #define DUK_TVAL_IS_VALID_TAG(tv) \ |
| 962 | (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) |
| 963 | |
| 964 | /* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */ |
| 965 | #define DUK_TVAL_UNUSED_INITIALIZER() \ |
| 966 | { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED } |
| 967 | |
| 968 | /* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */ |
| 969 | #if defined(DUK_USE_64BIT_OPS) |
| 970 | #if defined(DUK_USE_DOUBLE_ME) |
| 971 | #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ |
| 972 | (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \ |
| 973 | } while (0) |
| 974 | #else |
| 975 | #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ |
| 976 | (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \ |
| 977 | } while (0) |
| 978 | #endif |
| 979 | #else /* DUK_USE_64BIT_OPS */ |
| 980 | #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \ |
| 981 | duk_tval *duk__tv; \ |
| 982 | duk__tv = (tv); \ |
| 983 | duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \ |
| 984 | duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \ |
| 985 | } while (0) |
| 986 | #endif /* DUK_USE_64BIT_OPS */ |
| 987 | |
| 988 | #if defined(DUK_USE_64BIT_OPS) |
| 989 | /* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */ |
| 990 | #if defined(DUK_USE_DOUBLE_ME) |
| 991 | #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ |
| 992 | (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \ |
| 993 | ((duk_uint64_t) (flags)) | \ |
| 994 | (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \ |
| 995 | } while (0) |
| 996 | #else |
| 997 | #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ |
| 998 | (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \ |
| 999 | (((duk_uint64_t) (flags)) << 32) | \ |
| 1000 | ((duk_uint64_t) (duk_uint32_t) (fp)); \ |
| 1001 | } while (0) |
| 1002 | #endif |
| 1003 | #else /* DUK_USE_64BIT_OPS */ |
| 1004 | #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ |
| 1005 | duk_tval *duk__tv; \ |
| 1006 | duk__tv = (tv); \ |
| 1007 | duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \ |
| 1008 | duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \ |
| 1009 | } while (0) |
| 1010 | #endif /* DUK_USE_64BIT_OPS */ |
| 1011 | |
| 1012 | #if defined(DUK_USE_FASTINT) |
| 1013 | /* Note: masking is done for 'i' to deal with negative numbers correctly */ |
| 1014 | #if defined(DUK_USE_DOUBLE_ME) |
| 1015 | #define DUK__TVAL_SET_I48(tv,i) do { \ |
| 1016 | duk_tval *duk__tv; \ |
| 1017 | duk__tv = (tv); \ |
| 1018 | duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \ |
| 1019 | duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ |
| 1020 | } while (0) |
| 1021 | #define DUK__TVAL_SET_U32(tv,i) do { \ |
| 1022 | duk_tval *duk__tv; \ |
| 1023 | duk__tv = (tv); \ |
| 1024 | duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \ |
| 1025 | duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \ |
| 1026 | } while (0) |
| 1027 | #else |
| 1028 | #define DUK__TVAL_SET_I48(tv,i) do { \ |
| 1029 | (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \ |
| 1030 | } while (0) |
| 1031 | #define DUK__TVAL_SET_U32(tv,i) do { \ |
| 1032 | (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \ |
| 1033 | } while (0) |
| 1034 | #endif |
| 1035 | |
| 1036 | /* This needs to go through a cast because sign extension is needed. */ |
| 1037 | #define DUK__TVAL_SET_I32(tv,i) do { \ |
| 1038 | duk_int64_t duk__tmp = (duk_int64_t) (i); \ |
| 1039 | DUK_TVAL_SET_I48((tv), duk__tmp); \ |
| 1040 | } while (0) |
| 1041 | |
| 1042 | /* XXX: Clumsy sign extend and masking of 16 topmost bits. */ |
| 1043 | #if defined(DUK_USE_DOUBLE_ME) |
| 1044 | #define DUK__TVAL_GET_FASTINT(tv) (((duk_int64_t) ((((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (tv)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16) |
| 1045 | #else |
| 1046 | #define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16) |
| 1047 | #endif |
| 1048 | #define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1]) |
| 1049 | #define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1]) |
| 1050 | #endif /* DUK_USE_FASTINT */ |
| 1051 | |
| 1052 | #define DUK_TVAL_SET_UNDEFINED(tv) do { \ |
| 1053 | (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \ |
| 1054 | } while (0) |
| 1055 | #define DUK_TVAL_SET_UNUSED(tv) do { \ |
| 1056 | (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \ |
| 1057 | } while (0) |
| 1058 | #define DUK_TVAL_SET_NULL(tv) do { \ |
| 1059 | (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \ |
| 1060 | } while (0) |
| 1061 | |
| 1062 | #define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val))) |
| 1063 | |
| 1064 | #define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv)) |
| 1065 | |
| 1066 | /* Assumes that caller has normalized NaNs, otherwise trouble ahead. */ |
| 1067 | #if defined(DUK_USE_FASTINT) |
| 1068 | #define DUK_TVAL_SET_DOUBLE(tv,d) do { \ |
| 1069 | duk_double_t duk__dblval; \ |
| 1070 | duk__dblval = (d); \ |
| 1071 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ |
| 1072 | DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ |
| 1073 | } while (0) |
| 1074 | #define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i)) |
| 1075 | #define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i)) |
| 1076 | #define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i)) |
| 1077 | #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d)) |
| 1078 | #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d)) |
| 1079 | #define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) |
| 1080 | #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ |
| 1081 | duk_tval *duk__tv; \ |
| 1082 | duk_double_t duk__d; \ |
| 1083 | duk__tv = (tv); \ |
| 1084 | if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ |
| 1085 | duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ |
| 1086 | DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ |
| 1087 | } \ |
| 1088 | } while (0) |
| 1089 | #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ |
| 1090 | duk_tval *duk__tv; \ |
| 1091 | duk_double_t duk__d; \ |
| 1092 | duk__tv = (tv); \ |
| 1093 | if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ |
| 1094 | duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ |
| 1095 | DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ |
| 1096 | } \ |
| 1097 | } while (0) |
| 1098 | #else /* DUK_USE_FASTINT */ |
| 1099 | #define DUK_TVAL_SET_DOUBLE(tv,d) do { \ |
| 1100 | duk_double_t duk__dblval; \ |
| 1101 | duk__dblval = (d); \ |
| 1102 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \ |
| 1103 | DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \ |
| 1104 | } while (0) |
| 1105 | #define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */ |
| 1106 | #define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) |
| 1107 | #define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) |
| 1108 | #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) |
| 1109 | #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) |
| 1110 | #define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d)) |
| 1111 | #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) |
| 1112 | #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) |
| 1113 | #endif /* DUK_USE_FASTINT */ |
| 1114 | |
| 1115 | #define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */ |
| 1116 | |
| 1117 | #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags)) |
| 1118 | #define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING) |
| 1119 | #define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT) |
| 1120 | #define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER) |
| 1121 | #define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER) |
| 1122 | |
| 1123 | #define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) |
| 1124 | |
| 1125 | /* getters */ |
| 1126 | #define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1]) |
| 1127 | #if defined(DUK_USE_FASTINT) |
| 1128 | #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) |
| 1129 | #define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv)) |
| 1130 | #define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv)) |
| 1131 | #define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv)) |
| 1132 | #define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv)) |
| 1133 | #else |
| 1134 | #define DUK_TVAL_GET_NUMBER(tv) ((tv)->d) |
| 1135 | #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d) |
| 1136 | #endif |
| 1137 | #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ |
| 1138 | (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \ |
| 1139 | (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \ |
| 1140 | } while (0) |
| 1141 | #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1])) |
| 1142 | #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL) |
| 1143 | #define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1]) |
| 1144 | #define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1]) |
| 1145 | #define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1]) |
| 1146 | #define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1]) |
| 1147 | #define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1]) |
| 1148 | |
| 1149 | /* decoding */ |
| 1150 | #define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0]) |
| 1151 | |
| 1152 | #define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED) |
| 1153 | #define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED) |
| 1154 | #define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL) |
| 1155 | #define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN) |
| 1156 | #define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE) |
| 1157 | #define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE) |
| 1158 | #define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC) |
| 1159 | #define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING) |
| 1160 | #define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT) |
| 1161 | #define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER) |
| 1162 | #define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER) |
| 1163 | #if defined(DUK_USE_FASTINT) |
| 1164 | /* 0xfff0 is -Infinity */ |
| 1165 | #define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) |
| 1166 | #define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT) |
| 1167 | #define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL) |
| 1168 | #else |
| 1169 | #define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL) |
| 1170 | #define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) |
| 1171 | #endif |
| 1172 | |
| 1173 | /* This is performance critical because it appears in every DECREF. */ |
| 1174 | #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING) |
| 1175 | |
| 1176 | #if defined(DUK_USE_FASTINT) |
| 1177 | DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv); |
| 1178 | #endif |
| 1179 | |
| 1180 | #else /* DUK_USE_PACKED_TVAL */ |
| 1181 | /* ======================================================================== */ |
| 1182 | |
| 1183 | /* |
| 1184 | * Portable 12-byte representation |
| 1185 | */ |
| 1186 | |
| 1187 | /* Note: not initializing all bytes is normally not an issue: Duktape won't |
| 1188 | * read or use the uninitialized bytes so valgrind won't issue warnings. |
| 1189 | * In some special cases a harmless valgrind warning may be issued though. |
| 1190 | * For example, the DumpHeap debugger command writes out a compiled function's |
| 1191 | * 'data' area as is, including any uninitialized bytes, which causes a |
| 1192 | * valgrind warning. |
| 1193 | */ |
| 1194 | |
| 1195 | typedef struct duk_tval_struct duk_tval; |
| 1196 | |
| 1197 | struct duk_tval_struct { |
| 1198 | duk_small_uint_t t; |
| 1199 | duk_small_uint_t ; |
| 1200 | union { |
| 1201 | duk_double_t d; |
| 1202 | duk_small_int_t i; |
| 1203 | #if defined(DUK_USE_FASTINT) |
| 1204 | duk_int64_t fi; /* if present, forces 16-byte duk_tval */ |
| 1205 | #endif |
| 1206 | void *voidptr; |
| 1207 | duk_hstring *hstring; |
| 1208 | duk_hobject *hobject; |
| 1209 | duk_hcompfunc *hcompfunc; |
| 1210 | duk_hnatfunc *hnatfunc; |
| 1211 | duk_hthread *hthread; |
| 1212 | duk_hbuffer *hbuffer; |
| 1213 | duk_heaphdr *heaphdr; |
| 1214 | duk_c_function lightfunc; |
| 1215 | } v; |
| 1216 | }; |
| 1217 | |
| 1218 | typedef struct { |
| 1219 | duk_small_uint_t t; |
| 1220 | duk_small_uint_t ; |
| 1221 | /* The rest of the fields don't matter except for debug dumps and such |
| 1222 | * for which a partial initializer may trigger out-ot-bounds memory |
| 1223 | * reads. Include a double field which is usually as large or larger |
| 1224 | * than pointers (not always however). |
| 1225 | */ |
| 1226 | duk_double_t d; |
| 1227 | } duk_tval_unused; |
| 1228 | |
| 1229 | #define DUK_TVAL_UNUSED_INITIALIZER() \ |
| 1230 | { DUK_TAG_UNUSED, 0, 0.0 } |
| 1231 | |
| 1232 | #define DUK_TAG_MIN 0 |
| 1233 | #define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */ |
| 1234 | #if defined(DUK_USE_FASTINT) |
| 1235 | #define DUK_TAG_FASTINT 1 |
| 1236 | #endif |
| 1237 | #define DUK_TAG_UNDEFINED 2 |
| 1238 | #define DUK_TAG_NULL 3 |
| 1239 | #define DUK_TAG_BOOLEAN 4 |
| 1240 | #define DUK_TAG_POINTER 5 |
| 1241 | #define DUK_TAG_LIGHTFUNC 6 |
| 1242 | #define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */ |
| 1243 | #define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */ |
| 1244 | #define DUK_TAG_OBJECT 9 |
| 1245 | #define DUK_TAG_BUFFER 10 |
| 1246 | #define DUK_TAG_MAX 10 |
| 1247 | |
| 1248 | #define DUK_TVAL_IS_VALID_TAG(tv) \ |
| 1249 | (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN) |
| 1250 | |
| 1251 | /* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code |
| 1252 | * to support the 8-byte representation. Further, it is a non-heap-allocated |
| 1253 | * type so it should come before DUK_TAG_STRING. Finally, it should not break |
| 1254 | * the tag value ranges covered by case-clauses in a switch-case. |
| 1255 | */ |
| 1256 | |
| 1257 | /* setters */ |
| 1258 | #define DUK_TVAL_SET_UNDEFINED(tv) do { \ |
| 1259 | duk_tval *duk__tv; \ |
| 1260 | duk__tv = (tv); \ |
| 1261 | duk__tv->t = DUK_TAG_UNDEFINED; \ |
| 1262 | } while (0) |
| 1263 | |
| 1264 | #define DUK_TVAL_SET_UNUSED(tv) do { \ |
| 1265 | duk_tval *duk__tv; \ |
| 1266 | duk__tv = (tv); \ |
| 1267 | duk__tv->t = DUK_TAG_UNUSED; \ |
| 1268 | } while (0) |
| 1269 | |
| 1270 | #define DUK_TVAL_SET_NULL(tv) do { \ |
| 1271 | duk_tval *duk__tv; \ |
| 1272 | duk__tv = (tv); \ |
| 1273 | duk__tv->t = DUK_TAG_NULL; \ |
| 1274 | } while (0) |
| 1275 | |
| 1276 | #define DUK_TVAL_SET_BOOLEAN(tv,val) do { \ |
| 1277 | duk_tval *duk__tv; \ |
| 1278 | duk__tv = (tv); \ |
| 1279 | duk__tv->t = DUK_TAG_BOOLEAN; \ |
| 1280 | duk__tv->v.i = (duk_small_int_t) (val); \ |
| 1281 | } while (0) |
| 1282 | |
| 1283 | #if defined(DUK_USE_FASTINT) |
| 1284 | #define DUK_TVAL_SET_DOUBLE(tv,val) do { \ |
| 1285 | duk_tval *duk__tv; \ |
| 1286 | duk_double_t duk__dblval; \ |
| 1287 | duk__dblval = (val); \ |
| 1288 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ |
| 1289 | duk__tv = (tv); \ |
| 1290 | duk__tv->t = DUK_TAG_NUMBER; \ |
| 1291 | duk__tv->v.d = duk__dblval; \ |
| 1292 | } while (0) |
| 1293 | #define DUK_TVAL_SET_I48(tv,val) do { \ |
| 1294 | duk_tval *duk__tv; \ |
| 1295 | duk__tv = (tv); \ |
| 1296 | duk__tv->t = DUK_TAG_FASTINT; \ |
| 1297 | duk__tv->v.fi = (val); \ |
| 1298 | } while (0) |
| 1299 | #define DUK_TVAL_SET_U32(tv,val) do { \ |
| 1300 | duk_tval *duk__tv; \ |
| 1301 | duk__tv = (tv); \ |
| 1302 | duk__tv->t = DUK_TAG_FASTINT; \ |
| 1303 | duk__tv->v.fi = (duk_int64_t) (val); \ |
| 1304 | } while (0) |
| 1305 | #define DUK_TVAL_SET_I32(tv,val) do { \ |
| 1306 | duk_tval *duk__tv; \ |
| 1307 | duk__tv = (tv); \ |
| 1308 | duk__tv->t = DUK_TAG_FASTINT; \ |
| 1309 | duk__tv->v.fi = (duk_int64_t) (val); \ |
| 1310 | } while (0) |
| 1311 | #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ |
| 1312 | duk_tval_set_number_chkfast_fast((tv), (d)) |
| 1313 | #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ |
| 1314 | duk_tval_set_number_chkfast_slow((tv), (d)) |
| 1315 | #define DUK_TVAL_SET_NUMBER(tv,val) \ |
| 1316 | DUK_TVAL_SET_DOUBLE((tv), (val)) |
| 1317 | #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \ |
| 1318 | duk_tval *duk__tv; \ |
| 1319 | duk_double_t duk__d; \ |
| 1320 | duk__tv = (tv); \ |
| 1321 | if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ |
| 1322 | duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ |
| 1323 | DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \ |
| 1324 | } \ |
| 1325 | } while (0) |
| 1326 | #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \ |
| 1327 | duk_tval *duk__tv; \ |
| 1328 | duk_double_t duk__d; \ |
| 1329 | duk__tv = (tv); \ |
| 1330 | if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \ |
| 1331 | duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \ |
| 1332 | DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \ |
| 1333 | } \ |
| 1334 | } while (0) |
| 1335 | #else /* DUK_USE_FASTINT */ |
| 1336 | #define DUK_TVAL_SET_DOUBLE(tv,d) \ |
| 1337 | DUK_TVAL_SET_NUMBER((tv), (d)) |
| 1338 | #define DUK_TVAL_SET_I48(tv,val) \ |
| 1339 | DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */ |
| 1340 | #define DUK_TVAL_SET_U32(tv,val) \ |
| 1341 | DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) |
| 1342 | #define DUK_TVAL_SET_I32(tv,val) \ |
| 1343 | DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) |
| 1344 | #define DUK_TVAL_SET_NUMBER(tv,val) do { \ |
| 1345 | duk_tval *duk__tv; \ |
| 1346 | duk_double_t duk__dblval; \ |
| 1347 | duk__dblval = (val); \ |
| 1348 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \ |
| 1349 | duk__tv = (tv); \ |
| 1350 | duk__tv->t = DUK_TAG_NUMBER; \ |
| 1351 | duk__tv->v.d = duk__dblval; \ |
| 1352 | } while (0) |
| 1353 | #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \ |
| 1354 | DUK_TVAL_SET_NUMBER((tv), (d)) |
| 1355 | #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \ |
| 1356 | DUK_TVAL_SET_NUMBER((tv), (d)) |
| 1357 | #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0) |
| 1358 | #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0) |
| 1359 | #endif /* DUK_USE_FASTINT */ |
| 1360 | |
| 1361 | #define DUK_TVAL_SET_FASTINT(tv,i) \ |
| 1362 | DUK_TVAL_SET_I48((tv), (i)) /* alias */ |
| 1363 | |
| 1364 | #define DUK_TVAL_SET_POINTER(tv,hptr) do { \ |
| 1365 | duk_tval *duk__tv; \ |
| 1366 | duk__tv = (tv); \ |
| 1367 | duk__tv->t = DUK_TAG_POINTER; \ |
| 1368 | duk__tv->v.voidptr = (hptr); \ |
| 1369 | } while (0) |
| 1370 | |
| 1371 | #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \ |
| 1372 | duk_tval *duk__tv; \ |
| 1373 | duk__tv = (tv); \ |
| 1374 | duk__tv->t = DUK_TAG_LIGHTFUNC; \ |
| 1375 | duk__tv->v_extra = (flags); \ |
| 1376 | duk__tv->v.lightfunc = (duk_c_function) (fp); \ |
| 1377 | } while (0) |
| 1378 | |
| 1379 | #define DUK_TVAL_SET_STRING(tv,hptr) do { \ |
| 1380 | duk_tval *duk__tv; \ |
| 1381 | duk__tv = (tv); \ |
| 1382 | duk__tv->t = DUK_TAG_STRING; \ |
| 1383 | duk__tv->v.hstring = (hptr); \ |
| 1384 | } while (0) |
| 1385 | |
| 1386 | #define DUK_TVAL_SET_OBJECT(tv,hptr) do { \ |
| 1387 | duk_tval *duk__tv; \ |
| 1388 | duk__tv = (tv); \ |
| 1389 | duk__tv->t = DUK_TAG_OBJECT; \ |
| 1390 | duk__tv->v.hobject = (hptr); \ |
| 1391 | } while (0) |
| 1392 | |
| 1393 | #define DUK_TVAL_SET_BUFFER(tv,hptr) do { \ |
| 1394 | duk_tval *duk__tv; \ |
| 1395 | duk__tv = (tv); \ |
| 1396 | duk__tv->t = DUK_TAG_BUFFER; \ |
| 1397 | duk__tv->v.hbuffer = (hptr); \ |
| 1398 | } while (0) |
| 1399 | |
| 1400 | #define DUK_TVAL_SET_NAN(tv) do { \ |
| 1401 | /* in non-packed representation we don't care about which NaN is used */ \ |
| 1402 | duk_tval *duk__tv; \ |
| 1403 | duk__tv = (tv); \ |
| 1404 | duk__tv->t = DUK_TAG_NUMBER; \ |
| 1405 | duk__tv->v.d = DUK_DOUBLE_NAN; \ |
| 1406 | } while (0) |
| 1407 | |
| 1408 | #define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0) |
| 1409 | |
| 1410 | /* getters */ |
| 1411 | #define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_uint_t) (tv)->v.i) |
| 1412 | #if defined(DUK_USE_FASTINT) |
| 1413 | #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) |
| 1414 | #define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi) |
| 1415 | #define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi)) |
| 1416 | #define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi)) |
| 1417 | #if 0 |
| 1418 | #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ |
| 1419 | (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \ |
| 1420 | DUK_TVAL_GET_DOUBLE((tv))) |
| 1421 | #define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv)) |
| 1422 | #else |
| 1423 | /* This seems reasonable overall. */ |
| 1424 | #define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \ |
| 1425 | duk_tval_get_number_unpacked_fastint((tv)) : \ |
| 1426 | DUK_TVAL_GET_DOUBLE((tv))) |
| 1427 | #endif |
| 1428 | #else |
| 1429 | #define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d) |
| 1430 | #define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d) |
| 1431 | #endif /* DUK_USE_FASTINT */ |
| 1432 | #define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr) |
| 1433 | #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \ |
| 1434 | (out_flags) = (duk_uint32_t) (tv)->v_extra; \ |
| 1435 | (out_fp) = (tv)->v.lightfunc; \ |
| 1436 | } while (0) |
| 1437 | #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc) |
| 1438 | #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_small_uint_t) ((tv)->v_extra)) |
| 1439 | #define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring) |
| 1440 | #define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject) |
| 1441 | #define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer) |
| 1442 | #define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr) |
| 1443 | |
| 1444 | /* decoding */ |
| 1445 | #define DUK_TVAL_GET_TAG(tv) ((tv)->t) |
| 1446 | #define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED) |
| 1447 | #define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED) |
| 1448 | #define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL) |
| 1449 | #define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN) |
| 1450 | #define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0)) |
| 1451 | #define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0)) |
| 1452 | #if defined(DUK_USE_FASTINT) |
| 1453 | #define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER) |
| 1454 | #define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT) |
| 1455 | #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \ |
| 1456 | (tv)->t == DUK_TAG_FASTINT) |
| 1457 | #else |
| 1458 | #define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER) |
| 1459 | #define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv)) |
| 1460 | #endif /* DUK_USE_FASTINT */ |
| 1461 | #define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER) |
| 1462 | #define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC) |
| 1463 | #define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING) |
| 1464 | #define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT) |
| 1465 | #define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER) |
| 1466 | |
| 1467 | /* This is performance critical because it's needed for every DECREF. |
| 1468 | * Take advantage of the fact that the first heap allocated tag is 8, |
| 1469 | * so that bit 3 is set for all heap allocated tags (and never set for |
| 1470 | * non-heap-allocated tags). |
| 1471 | */ |
| 1472 | #if 0 |
| 1473 | #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING) |
| 1474 | #endif |
| 1475 | #define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08) |
| 1476 | |
| 1477 | #if defined(DUK_USE_FASTINT) |
| 1478 | #if 0 |
| 1479 | DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv); |
| 1480 | #endif |
| 1481 | DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv); |
| 1482 | #endif |
| 1483 | |
| 1484 | #endif /* DUK_USE_PACKED_TVAL */ |
| 1485 | |
| 1486 | /* |
| 1487 | * Convenience (independent of representation) |
| 1488 | */ |
| 1489 | |
| 1490 | #define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1) |
| 1491 | #define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0) |
| 1492 | |
| 1493 | #define DUK_TVAL_STRING_IS_SYMBOL(tv) \ |
| 1494 | DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv))) |
| 1495 | |
| 1496 | /* Lightfunc flags packing and unpacking. */ |
| 1497 | /* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##. |
| 1498 | * Avoid signed shifts due to portability limitations. |
| 1499 | */ |
| 1500 | #define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \ |
| 1501 | ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8)) |
| 1502 | #define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \ |
| 1503 | (((lf_flags) >> 4) & 0x0fU) |
| 1504 | #define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \ |
| 1505 | ((lf_flags) & 0x0fU) |
| 1506 | #define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \ |
| 1507 | ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs) |
| 1508 | |
| 1509 | #define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */ |
| 1510 | #define DUK_LFUNC_NARGS_MIN 0x00 |
| 1511 | #define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */ |
| 1512 | #define DUK_LFUNC_LENGTH_MIN 0x00 |
| 1513 | #define DUK_LFUNC_LENGTH_MAX 0x0f |
| 1514 | #define DUK_LFUNC_MAGIC_MIN (-0x80) |
| 1515 | #define DUK_LFUNC_MAGIC_MAX 0x7f |
| 1516 | |
| 1517 | /* fastint constants etc */ |
| 1518 | #if defined(DUK_USE_FASTINT) |
| 1519 | #define DUK_FASTINT_MIN (DUK_I64_CONSTANT(-0x800000000000)) |
| 1520 | #define DUK_FASTINT_MAX (DUK_I64_CONSTANT(0x7fffffffffff)) |
| 1521 | #define DUK_FASTINT_BITS 48 |
| 1522 | |
| 1523 | DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x); |
| 1524 | DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x); |
| 1525 | #endif |
| 1526 | |
| 1527 | #if defined(DUK_USE_ASSERTIONS) |
| 1528 | DUK_INTERNAL_DECL void duk_tval_assert_valid(duk_tval *tv); |
| 1529 | #define DUK_TVAL_ASSERT_VALID(tv) do { duk_tval_assert_valid((tv)); } while (0) |
| 1530 | #else |
| 1531 | #define DUK_TVAL_ASSERT_VALID(tv) do {} while (0) |
| 1532 | #endif |
| 1533 | |
| 1534 | #endif /* DUK_TVAL_H_INCLUDED */ |
| 1535 | /* #include duk_builtins.h */ |
| 1536 | #line 1 "duk_builtins.h" |
| 1537 | /* |
| 1538 | * Automatically generated by genbuiltins.py, do not edit! |
| 1539 | */ |
| 1540 | |
| 1541 | #if !defined(DUK_BUILTINS_H_INCLUDED) |
| 1542 | #define DUK_BUILTINS_H_INCLUDED |
| 1543 | |
| 1544 | #if defined(DUK_USE_ROM_STRINGS) |
| 1545 | #error ROM support not enabled, rerun configure.py with --rom-support |
| 1546 | #else /* DUK_USE_ROM_STRINGS */ |
| 1547 | #define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */ |
| 1548 | #define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED) |
| 1549 | #define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED) |
| 1550 | #define DUK_STRIDX_UC_NULL 1 /* 'Null' */ |
| 1551 | #define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL) |
| 1552 | #define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL) |
| 1553 | #define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */ |
| 1554 | #define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL) |
| 1555 | #define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL) |
| 1556 | #define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */ |
| 1557 | #define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS) |
| 1558 | #define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS) |
| 1559 | #define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */ |
| 1560 | #define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT) |
| 1561 | #define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT) |
| 1562 | #define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */ |
| 1563 | #define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION) |
| 1564 | #define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION) |
| 1565 | #define DUK_STRIDX_UC_ARRAY 6 /* 'Array' */ |
| 1566 | #define DUK_HEAP_STRING_UC_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARRAY) |
| 1567 | #define DUK_HTHREAD_STRING_UC_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARRAY) |
| 1568 | #define DUK_STRIDX_UC_STRING 7 /* 'String' */ |
| 1569 | #define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING) |
| 1570 | #define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING) |
| 1571 | #define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */ |
| 1572 | #define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN) |
| 1573 | #define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN) |
| 1574 | #define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */ |
| 1575 | #define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER) |
| 1576 | #define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER) |
| 1577 | #define DUK_STRIDX_UC_DATE 10 /* 'Date' */ |
| 1578 | #define DUK_HEAP_STRING_UC_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_DATE) |
| 1579 | #define DUK_HTHREAD_STRING_UC_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_DATE) |
| 1580 | #define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */ |
| 1581 | #define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP) |
| 1582 | #define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP) |
| 1583 | #define DUK_STRIDX_UC_ERROR 12 /* 'Error' */ |
| 1584 | #define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR) |
| 1585 | #define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR) |
| 1586 | #define DUK_STRIDX_MATH 13 /* 'Math' */ |
| 1587 | #define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH) |
| 1588 | #define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH) |
| 1589 | #define DUK_STRIDX_JSON 14 /* 'JSON' */ |
| 1590 | #define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON) |
| 1591 | #define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON) |
| 1592 | #define DUK_STRIDX_EMPTY_STRING 15 /* '' */ |
| 1593 | #define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING) |
| 1594 | #define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING) |
| 1595 | #define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */ |
| 1596 | #define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER) |
| 1597 | #define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER) |
| 1598 | #define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */ |
| 1599 | #define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW) |
| 1600 | #define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW) |
| 1601 | #define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */ |
| 1602 | #define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY) |
| 1603 | #define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY) |
| 1604 | #define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */ |
| 1605 | #define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY) |
| 1606 | #define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY) |
| 1607 | #define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */ |
| 1608 | #define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY) |
| 1609 | #define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY) |
| 1610 | #define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */ |
| 1611 | #define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY) |
| 1612 | #define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY) |
| 1613 | #define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */ |
| 1614 | #define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY) |
| 1615 | #define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY) |
| 1616 | #define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */ |
| 1617 | #define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY) |
| 1618 | #define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY) |
| 1619 | #define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */ |
| 1620 | #define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY) |
| 1621 | #define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY) |
| 1622 | #define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */ |
| 1623 | #define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY) |
| 1624 | #define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY) |
| 1625 | #define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */ |
| 1626 | #define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY) |
| 1627 | #define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY) |
| 1628 | #define DUK_STRIDX_GLOBAL 27 /* 'global' */ |
| 1629 | #define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL) |
| 1630 | #define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL) |
| 1631 | #define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */ |
| 1632 | #define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV) |
| 1633 | #define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV) |
| 1634 | #define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */ |
| 1635 | #define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV) |
| 1636 | #define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV) |
| 1637 | #define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */ |
| 1638 | #define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER) |
| 1639 | #define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER) |
| 1640 | #define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */ |
| 1641 | #define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER) |
| 1642 | #define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER) |
| 1643 | #define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */ |
| 1644 | #define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD) |
| 1645 | #define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD) |
| 1646 | #define DUK_STRIDX_EVAL 33 /* 'eval' */ |
| 1647 | #define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL) |
| 1648 | #define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL) |
| 1649 | #define DUK_STRIDX_VALUE 34 /* 'value' */ |
| 1650 | #define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE) |
| 1651 | #define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE) |
| 1652 | #define DUK_STRIDX_WRITABLE 35 /* 'writable' */ |
| 1653 | #define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE) |
| 1654 | #define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE) |
| 1655 | #define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */ |
| 1656 | #define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE) |
| 1657 | #define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE) |
| 1658 | #define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */ |
| 1659 | #define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE) |
| 1660 | #define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE) |
| 1661 | #define DUK_STRIDX_JOIN 38 /* 'join' */ |
| 1662 | #define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN) |
| 1663 | #define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN) |
| 1664 | #define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */ |
| 1665 | #define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING) |
| 1666 | #define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING) |
| 1667 | #define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */ |
| 1668 | #define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF) |
| 1669 | #define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF) |
| 1670 | #define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */ |
| 1671 | #define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING) |
| 1672 | #define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING) |
| 1673 | #define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */ |
| 1674 | #define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING) |
| 1675 | #define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING) |
| 1676 | #define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */ |
| 1677 | #define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING) |
| 1678 | #define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING) |
| 1679 | #define DUK_STRIDX_SOURCE 44 /* 'source' */ |
| 1680 | #define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE) |
| 1681 | #define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE) |
| 1682 | #define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */ |
| 1683 | #define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE) |
| 1684 | #define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE) |
| 1685 | #define DUK_STRIDX_MULTILINE 46 /* 'multiline' */ |
| 1686 | #define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE) |
| 1687 | #define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE) |
| 1688 | #define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */ |
| 1689 | #define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX) |
| 1690 | #define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX) |
| 1691 | #define DUK_STRIDX_FLAGS 48 /* 'flags' */ |
| 1692 | #define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS) |
| 1693 | #define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS) |
| 1694 | #define DUK_STRIDX_INDEX 49 /* 'index' */ |
| 1695 | #define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX) |
| 1696 | #define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX) |
| 1697 | #define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */ |
| 1698 | #define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE) |
| 1699 | #define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE) |
| 1700 | #define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */ |
| 1701 | #define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR) |
| 1702 | #define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR) |
| 1703 | #define DUK_STRIDX_MESSAGE 52 /* 'message' */ |
| 1704 | #define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE) |
| 1705 | #define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE) |
| 1706 | #define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */ |
| 1707 | #define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN) |
| 1708 | #define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN) |
| 1709 | #define DUK_STRIDX_LC_NUMBER 54 /* 'number' */ |
| 1710 | #define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER) |
| 1711 | #define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER) |
| 1712 | #define DUK_STRIDX_LC_STRING 55 /* 'string' */ |
| 1713 | #define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING) |
| 1714 | #define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING) |
| 1715 | #define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */ |
| 1716 | #define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL) |
| 1717 | #define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL) |
| 1718 | #define DUK_STRIDX_LC_OBJECT 57 /* 'object' */ |
| 1719 | #define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT) |
| 1720 | #define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT) |
| 1721 | #define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */ |
| 1722 | #define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED) |
| 1723 | #define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED) |
| 1724 | #define DUK_STRIDX_NAN 59 /* 'NaN' */ |
| 1725 | #define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN) |
| 1726 | #define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN) |
| 1727 | #define DUK_STRIDX_INFINITY 60 /* 'Infinity' */ |
| 1728 | #define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY) |
| 1729 | #define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY) |
| 1730 | #define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */ |
| 1731 | #define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY) |
| 1732 | #define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY) |
| 1733 | #define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */ |
| 1734 | #define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO) |
| 1735 | #define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO) |
| 1736 | #define DUK_STRIDX_COMMA 63 /* ',' */ |
| 1737 | #define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA) |
| 1738 | #define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA) |
| 1739 | #define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */ |
| 1740 | #define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE) |
| 1741 | #define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE) |
| 1742 | #define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */ |
| 1743 | #define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS) |
| 1744 | #define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS) |
| 1745 | #define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */ |
| 1746 | #define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE) |
| 1747 | #define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE) |
| 1748 | #define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */ |
| 1749 | #define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS) |
| 1750 | #define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS) |
| 1751 | #define DUK_STRIDX_CALLEE 68 /* 'callee' */ |
| 1752 | #define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE) |
| 1753 | #define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE) |
| 1754 | #define DUK_STRIDX_CALLER 69 /* 'caller' */ |
| 1755 | #define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER) |
| 1756 | #define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER) |
| 1757 | #define DUK_STRIDX_APPLY 70 /* 'apply' */ |
| 1758 | #define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY) |
| 1759 | #define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY) |
| 1760 | #define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */ |
| 1761 | #define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT) |
| 1762 | #define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT) |
| 1763 | #define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */ |
| 1764 | #define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY) |
| 1765 | #define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY) |
| 1766 | #define DUK_STRIDX_GET 73 /* 'get' */ |
| 1767 | #define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET) |
| 1768 | #define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET) |
| 1769 | #define DUK_STRIDX_HAS 74 /* 'has' */ |
| 1770 | #define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS) |
| 1771 | #define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS) |
| 1772 | #define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */ |
| 1773 | #define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS) |
| 1774 | #define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS) |
| 1775 | #define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE 76 /* '\x81Symbol.toPrimitive\xff' */ |
| 1776 | #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE) |
| 1777 | #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE) |
| 1778 | #define DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE 77 /* '\x81Symbol.hasInstance\xff' */ |
| 1779 | #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE) |
| 1780 | #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE) |
| 1781 | #define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG 78 /* '\x81Symbol.toStringTag\xff' */ |
| 1782 | #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG) |
| 1783 | #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG) |
| 1784 | #define DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE 79 /* '\x81Symbol.isConcatSpreadable\xff' */ |
| 1785 | #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE) |
| 1786 | #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE) |
| 1787 | #define DUK_STRIDX_SET_PROTOTYPE_OF 80 /* 'setPrototypeOf' */ |
| 1788 | #define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF) |
| 1789 | #define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF) |
| 1790 | #define DUK_STRIDX___PROTO__ 81 /* '__proto__' */ |
| 1791 | #define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__) |
| 1792 | #define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__) |
| 1793 | #define DUK_STRIDX_TO_STRING 82 /* 'toString' */ |
| 1794 | #define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING) |
| 1795 | #define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING) |
| 1796 | #define DUK_STRIDX_TO_JSON 83 /* 'toJSON' */ |
| 1797 | #define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON) |
| 1798 | #define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON) |
| 1799 | #define DUK_STRIDX_TYPE 84 /* 'type' */ |
| 1800 | #define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE) |
| 1801 | #define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE) |
| 1802 | #define DUK_STRIDX_DATA 85 /* 'data' */ |
| 1803 | #define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA) |
| 1804 | #define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA) |
| 1805 | #define DUK_STRIDX_LC_BUFFER 86 /* 'buffer' */ |
| 1806 | #define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER) |
| 1807 | #define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER) |
| 1808 | #define DUK_STRIDX_LENGTH 87 /* 'length' */ |
| 1809 | #define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH) |
| 1810 | #define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH) |
| 1811 | #define DUK_STRIDX_SET 88 /* 'set' */ |
| 1812 | #define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET) |
| 1813 | #define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET) |
| 1814 | #define DUK_STRIDX_STACK 89 /* 'stack' */ |
| 1815 | #define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK) |
| 1816 | #define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK) |
| 1817 | #define DUK_STRIDX_PC 90 /* 'pc' */ |
| 1818 | #define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC) |
| 1819 | #define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC) |
| 1820 | #define DUK_STRIDX_LINE_NUMBER 91 /* 'lineNumber' */ |
| 1821 | #define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER) |
| 1822 | #define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER) |
| 1823 | #define DUK_STRIDX_INT_TRACEDATA 92 /* '\x82Tracedata' */ |
| 1824 | #define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA) |
| 1825 | #define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA) |
| 1826 | #define DUK_STRIDX_NAME 93 /* 'name' */ |
| 1827 | #define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME) |
| 1828 | #define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME) |
| 1829 | #define DUK_STRIDX_FILE_NAME 94 /* 'fileName' */ |
| 1830 | #define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME) |
| 1831 | #define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME) |
| 1832 | #define DUK_STRIDX_LC_POINTER 95 /* 'pointer' */ |
| 1833 | #define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER) |
| 1834 | #define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER) |
| 1835 | #define DUK_STRIDX_INT_TARGET 96 /* '\x82Target' */ |
| 1836 | #define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET) |
| 1837 | #define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET) |
| 1838 | #define DUK_STRIDX_INT_NEXT 97 /* '\x82Next' */ |
| 1839 | #define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT) |
| 1840 | #define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT) |
| 1841 | #define DUK_STRIDX_INT_BYTECODE 98 /* '\x82Bytecode' */ |
| 1842 | #define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE) |
| 1843 | #define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE) |
| 1844 | #define DUK_STRIDX_INT_FORMALS 99 /* '\x82Formals' */ |
| 1845 | #define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS) |
| 1846 | #define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS) |
| 1847 | #define DUK_STRIDX_INT_VARMAP 100 /* '\x82Varmap' */ |
| 1848 | #define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP) |
| 1849 | #define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP) |
| 1850 | #define DUK_STRIDX_INT_SOURCE 101 /* '\x82Source' */ |
| 1851 | #define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE) |
| 1852 | #define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE) |
| 1853 | #define DUK_STRIDX_INT_PC2LINE 102 /* '\x82Pc2line' */ |
| 1854 | #define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE) |
| 1855 | #define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE) |
| 1856 | #define DUK_STRIDX_INT_MAP 103 /* '\x82Map' */ |
| 1857 | #define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP) |
| 1858 | #define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP) |
| 1859 | #define DUK_STRIDX_INT_VARENV 104 /* '\x82Varenv' */ |
| 1860 | #define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV) |
| 1861 | #define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV) |
| 1862 | #define DUK_STRIDX_INT_FINALIZER 105 /* '\x82Finalizer' */ |
| 1863 | #define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER) |
| 1864 | #define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER) |
| 1865 | #define DUK_STRIDX_INT_VALUE 106 /* '\x82Value' */ |
| 1866 | #define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE) |
| 1867 | #define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE) |
| 1868 | #define DUK_STRIDX_COMPILE 107 /* 'compile' */ |
| 1869 | #define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE) |
| 1870 | #define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE) |
| 1871 | #define DUK_STRIDX_INPUT 108 /* 'input' */ |
| 1872 | #define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT) |
| 1873 | #define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT) |
| 1874 | #define DUK_STRIDX_ERR_CREATE 109 /* 'errCreate' */ |
| 1875 | #define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE) |
| 1876 | #define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE) |
| 1877 | #define DUK_STRIDX_ERR_THROW 110 /* 'errThrow' */ |
| 1878 | #define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW) |
| 1879 | #define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW) |
| 1880 | #define DUK_STRIDX_ENV 111 /* 'env' */ |
| 1881 | #define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV) |
| 1882 | #define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV) |
| 1883 | #define DUK_STRIDX_HEX 112 /* 'hex' */ |
| 1884 | #define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX) |
| 1885 | #define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX) |
| 1886 | #define DUK_STRIDX_BASE64 113 /* 'base64' */ |
| 1887 | #define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64) |
| 1888 | #define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64) |
| 1889 | #define DUK_STRIDX_JX 114 /* 'jx' */ |
| 1890 | #define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX) |
| 1891 | #define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX) |
| 1892 | #define DUK_STRIDX_JC 115 /* 'jc' */ |
| 1893 | #define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC) |
| 1894 | #define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC) |
| 1895 | #define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */ |
| 1896 | #define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED) |
| 1897 | #define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED) |
| 1898 | #define DUK_STRIDX_JSON_EXT_NAN 117 /* '{"_nan":true}' */ |
| 1899 | #define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN) |
| 1900 | #define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN) |
| 1901 | #define DUK_STRIDX_JSON_EXT_POSINF 118 /* '{"_inf":true}' */ |
| 1902 | #define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF) |
| 1903 | #define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF) |
| 1904 | #define DUK_STRIDX_JSON_EXT_NEGINF 119 /* '{"_ninf":true}' */ |
| 1905 | #define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF) |
| 1906 | #define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF) |
| 1907 | #define DUK_STRIDX_JSON_EXT_FUNCTION1 120 /* '{"_func":true}' */ |
| 1908 | #define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1) |
| 1909 | #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1) |
| 1910 | #define DUK_STRIDX_JSON_EXT_FUNCTION2 121 /* '{_func:true}' */ |
| 1911 | #define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2) |
| 1912 | #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2) |
| 1913 | #define DUK_STRIDX_BREAK 122 /* 'break' */ |
| 1914 | #define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK) |
| 1915 | #define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK) |
| 1916 | #define DUK_STRIDX_CASE 123 /* 'case' */ |
| 1917 | #define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE) |
| 1918 | #define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE) |
| 1919 | #define DUK_STRIDX_CATCH 124 /* 'catch' */ |
| 1920 | #define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH) |
| 1921 | #define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH) |
| 1922 | #define DUK_STRIDX_CONTINUE 125 /* 'continue' */ |
| 1923 | #define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE) |
| 1924 | #define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE) |
| 1925 | #define DUK_STRIDX_DEBUGGER 126 /* 'debugger' */ |
| 1926 | #define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER) |
| 1927 | #define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER) |
| 1928 | #define DUK_STRIDX_DEFAULT 127 /* 'default' */ |
| 1929 | #define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT) |
| 1930 | #define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT) |
| 1931 | #define DUK_STRIDX_DELETE 128 /* 'delete' */ |
| 1932 | #define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE) |
| 1933 | #define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE) |
| 1934 | #define DUK_STRIDX_DO 129 /* 'do' */ |
| 1935 | #define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO) |
| 1936 | #define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO) |
| 1937 | #define DUK_STRIDX_ELSE 130 /* 'else' */ |
| 1938 | #define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE) |
| 1939 | #define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE) |
| 1940 | #define DUK_STRIDX_FINALLY 131 /* 'finally' */ |
| 1941 | #define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY) |
| 1942 | #define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY) |
| 1943 | #define DUK_STRIDX_FOR 132 /* 'for' */ |
| 1944 | #define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR) |
| 1945 | #define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR) |
| 1946 | #define DUK_STRIDX_LC_FUNCTION 133 /* 'function' */ |
| 1947 | #define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION) |
| 1948 | #define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION) |
| 1949 | #define DUK_STRIDX_IF 134 /* 'if' */ |
| 1950 | #define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF) |
| 1951 | #define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF) |
| 1952 | #define DUK_STRIDX_IN 135 /* 'in' */ |
| 1953 | #define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN) |
| 1954 | #define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN) |
| 1955 | #define DUK_STRIDX_INSTANCEOF 136 /* 'instanceof' */ |
| 1956 | #define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF) |
| 1957 | #define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF) |
| 1958 | #define DUK_STRIDX_NEW 137 /* 'new' */ |
| 1959 | #define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW) |
| 1960 | #define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW) |
| 1961 | #define DUK_STRIDX_RETURN 138 /* 'return' */ |
| 1962 | #define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN) |
| 1963 | #define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN) |
| 1964 | #define DUK_STRIDX_SWITCH 139 /* 'switch' */ |
| 1965 | #define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH) |
| 1966 | #define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH) |
| 1967 | #define DUK_STRIDX_THIS 140 /* 'this' */ |
| 1968 | #define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS) |
| 1969 | #define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS) |
| 1970 | #define DUK_STRIDX_THROW 141 /* 'throw' */ |
| 1971 | #define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW) |
| 1972 | #define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW) |
| 1973 | #define DUK_STRIDX_TRY 142 /* 'try' */ |
| 1974 | #define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY) |
| 1975 | #define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY) |
| 1976 | #define DUK_STRIDX_TYPEOF 143 /* 'typeof' */ |
| 1977 | #define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF) |
| 1978 | #define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF) |
| 1979 | #define DUK_STRIDX_VAR 144 /* 'var' */ |
| 1980 | #define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR) |
| 1981 | #define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR) |
| 1982 | #define DUK_STRIDX_CONST 145 /* 'const' */ |
| 1983 | #define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST) |
| 1984 | #define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST) |
| 1985 | #define DUK_STRIDX_VOID 146 /* 'void' */ |
| 1986 | #define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID) |
| 1987 | #define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID) |
| 1988 | #define DUK_STRIDX_WHILE 147 /* 'while' */ |
| 1989 | #define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE) |
| 1990 | #define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE) |
| 1991 | #define DUK_STRIDX_WITH 148 /* 'with' */ |
| 1992 | #define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH) |
| 1993 | #define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH) |
| 1994 | #define DUK_STRIDX_CLASS 149 /* 'class' */ |
| 1995 | #define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS) |
| 1996 | #define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS) |
| 1997 | #define DUK_STRIDX_ENUM 150 /* 'enum' */ |
| 1998 | #define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM) |
| 1999 | #define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM) |
| 2000 | #define DUK_STRIDX_EXPORT 151 /* 'export' */ |
| 2001 | #define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT) |
| 2002 | #define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT) |
| 2003 | #define DUK_STRIDX_EXTENDS 152 /* 'extends' */ |
| 2004 | #define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS) |
| 2005 | #define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS) |
| 2006 | #define DUK_STRIDX_IMPORT 153 /* 'import' */ |
| 2007 | #define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT) |
| 2008 | #define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT) |
| 2009 | #define DUK_STRIDX_SUPER 154 /* 'super' */ |
| 2010 | #define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER) |
| 2011 | #define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER) |
| 2012 | #define DUK_STRIDX_LC_NULL 155 /* 'null' */ |
| 2013 | #define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL) |
| 2014 | #define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL) |
| 2015 | #define DUK_STRIDX_TRUE 156 /* 'true' */ |
| 2016 | #define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE) |
| 2017 | #define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE) |
| 2018 | #define DUK_STRIDX_FALSE 157 /* 'false' */ |
| 2019 | #define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE) |
| 2020 | #define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE) |
| 2021 | #define DUK_STRIDX_IMPLEMENTS 158 /* 'implements' */ |
| 2022 | #define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS) |
| 2023 | #define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS) |
| 2024 | #define DUK_STRIDX_INTERFACE 159 /* 'interface' */ |
| 2025 | #define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE) |
| 2026 | #define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE) |
| 2027 | #define DUK_STRIDX_LET 160 /* 'let' */ |
| 2028 | #define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET) |
| 2029 | #define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET) |
| 2030 | #define DUK_STRIDX_PACKAGE 161 /* 'package' */ |
| 2031 | #define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE) |
| 2032 | #define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE) |
| 2033 | #define DUK_STRIDX_PRIVATE 162 /* 'private' */ |
| 2034 | #define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE) |
| 2035 | #define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE) |
| 2036 | #define DUK_STRIDX_PROTECTED 163 /* 'protected' */ |
| 2037 | #define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED) |
| 2038 | #define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED) |
| 2039 | #define DUK_STRIDX_PUBLIC 164 /* 'public' */ |
| 2040 | #define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC) |
| 2041 | #define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC) |
| 2042 | #define DUK_STRIDX_STATIC 165 /* 'static' */ |
| 2043 | #define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC) |
| 2044 | #define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC) |
| 2045 | #define DUK_STRIDX_YIELD 166 /* 'yield' */ |
| 2046 | #define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD) |
| 2047 | #define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD) |
| 2048 | |
| 2049 | #define DUK_HEAP_NUM_STRINGS 167 |
| 2050 | #define DUK_STRIDX_START_RESERVED 122 |
| 2051 | #define DUK_STRIDX_START_STRICT_RESERVED 158 |
| 2052 | #define DUK_STRIDX_END_RESERVED 167 /* exclusive endpoint */ |
| 2053 | |
| 2054 | /* To convert a heap stridx to a token number, subtract |
| 2055 | * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED. |
| 2056 | */ |
| 2057 | #if !defined(DUK_SINGLE_FILE) |
| 2058 | DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[972]; |
| 2059 | #endif /* !DUK_SINGLE_FILE */ |
| 2060 | #define DUK_STRDATA_MAX_STRLEN 27 |
| 2061 | #define DUK_STRDATA_DATA_LENGTH 972 |
| 2062 | #endif /* DUK_USE_ROM_STRINGS */ |
| 2063 | |
| 2064 | #if defined(DUK_USE_ROM_OBJECTS) |
| 2065 | #error RAM support not enabled, rerun configure.py with --ram-support |
| 2066 | #else /* DUK_USE_ROM_OBJECTS */ |
| 2067 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx); |
| 2068 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx); |
| 2069 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx); |
| 2070 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx); |
| 2071 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx); |
| 2072 | DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx); |
| 2073 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx); |
| 2074 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx); |
| 2075 | DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx); |
| 2076 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx); |
| 2077 | DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx); |
| 2078 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx); |
| 2079 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx); |
| 2080 | DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx); |
| 2081 | DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx); |
| 2082 | DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx); |
| 2083 | DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx); |
| 2084 | DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx); |
| 2085 | DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx); |
| 2086 | DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx); |
| 2087 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx); |
| 2088 | DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx); |
| 2089 | DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx); |
| 2090 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx); |
| 2091 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx); |
| 2092 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx); |
| 2093 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx); |
| 2094 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx); |
| 2095 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx); |
| 2096 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx); |
| 2097 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx); |
| 2098 | DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx); |
| 2099 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx); |
| 2100 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx); |
| 2101 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx); |
| 2102 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx); |
| 2103 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx); |
| 2104 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx); |
| 2105 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx); |
| 2106 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx); |
| 2107 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx); |
| 2108 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx); |
| 2109 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx); |
| 2110 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx); |
| 2111 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx); |
| 2112 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx); |
| 2113 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx); |
| 2114 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx); |
| 2115 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx); |
| 2116 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx); |
| 2117 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx); |
| 2118 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx); |
| 2119 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx); |
| 2120 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx); |
| 2121 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx); |
| 2122 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx); |
| 2123 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx); |
| 2124 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_hasinstance(duk_context *ctx); |
| 2125 | DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx); |
| 2126 | DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx); |
| 2127 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx); |
| 2128 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx); |
| 2129 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx); |
| 2130 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx); |
| 2131 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx); |
| 2132 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx); |
| 2133 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx); |
| 2134 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx); |
| 2135 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx); |
| 2136 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx); |
| 2137 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx); |
| 2138 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx); |
| 2139 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx); |
| 2140 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx); |
| 2141 | DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx); |
| 2142 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx); |
| 2143 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx); |
| 2144 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx); |
| 2145 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx); |
| 2146 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx); |
| 2147 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx); |
| 2148 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx); |
| 2149 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx); |
| 2150 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx); |
| 2151 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx); |
| 2152 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx); |
| 2153 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx); |
| 2154 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx); |
| 2155 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx); |
| 2156 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx); |
| 2157 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx); |
| 2158 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx); |
| 2159 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx); |
| 2160 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx); |
| 2161 | DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx); |
| 2162 | DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx); |
| 2163 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_check_shared(duk_context *ctx); |
| 2164 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx); |
| 2165 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx); |
| 2166 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx); |
| 2167 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx); |
| 2168 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx); |
| 2169 | DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx); |
| 2170 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx); |
| 2171 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx); |
| 2172 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx); |
| 2173 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx); |
| 2174 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx); |
| 2175 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx); |
| 2176 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx); |
| 2177 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx); |
| 2178 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx); |
| 2179 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx); |
| 2180 | DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_toprimitive(duk_context *ctx); |
| 2181 | DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx); |
| 2182 | DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx); |
| 2183 | DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx); |
| 2184 | DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx); |
| 2185 | DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx); |
| 2186 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx); |
| 2187 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx); |
| 2188 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx); |
| 2189 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx); |
| 2190 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx); |
| 2191 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx); |
| 2192 | DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx); |
| 2193 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx); |
| 2194 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx); |
| 2195 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx); |
| 2196 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx); |
| 2197 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx); |
| 2198 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx); |
| 2199 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx); |
| 2200 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx); |
| 2201 | DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx); |
| 2202 | DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx); |
| 2203 | DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx); |
| 2204 | DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx); |
| 2205 | DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx); |
| 2206 | DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx); |
| 2207 | DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx); |
| 2208 | DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx); |
| 2209 | DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx); |
| 2210 | DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx); |
| 2211 | DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx); |
| 2212 | DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx); |
| 2213 | DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx); |
| 2214 | DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx); |
| 2215 | DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx); |
| 2216 | DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx); |
| 2217 | DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx); |
| 2218 | DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx); |
| 2219 | DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx); |
| 2220 | DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx); |
| 2221 | DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_key_for(duk_context *ctx); |
| 2222 | DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_tostring_shared(duk_context *ctx); |
| 2223 | DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_toprimitive(duk_context *ctx); |
| 2224 | DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx); |
| 2225 | DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx); |
| 2226 | DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx); |
| 2227 | DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx); |
| 2228 | DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx); |
| 2229 | DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx); |
| 2230 | DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx); |
| 2231 | DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx); |
| 2232 | DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx); |
| 2233 | DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx); |
| 2234 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx); |
| 2235 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx); |
| 2236 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx); |
| 2237 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx); |
| 2238 | DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx); |
| 2239 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx); |
| 2240 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx); |
| 2241 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx); |
| 2242 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx); |
| 2243 | DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx); |
| 2244 | DUK_INTERNAL_DECL duk_ret_t duk_bi_cbor_encode(duk_context *ctx); |
| 2245 | DUK_INTERNAL_DECL duk_ret_t duk_bi_cbor_decode(duk_context *ctx); |
| 2246 | DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx); |
| 2247 | DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx); |
| 2248 | DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx); |
| 2249 | DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx); |
| 2250 | DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx); |
| 2251 | #if !defined(DUK_SINGLE_FILE) |
| 2252 | DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[185]; |
| 2253 | #endif /* !DUK_SINGLE_FILE */ |
| 2254 | #define DUK_BIDX_GLOBAL 0 |
| 2255 | #define DUK_BIDX_GLOBAL_ENV 1 |
| 2256 | #define DUK_BIDX_OBJECT_CONSTRUCTOR 2 |
| 2257 | #define DUK_BIDX_OBJECT_PROTOTYPE 3 |
| 2258 | #define DUK_BIDX_FUNCTION_CONSTRUCTOR 4 |
| 2259 | #define DUK_BIDX_FUNCTION_PROTOTYPE 5 |
| 2260 | #define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE 6 |
| 2261 | #define DUK_BIDX_ARRAY_CONSTRUCTOR 7 |
| 2262 | #define DUK_BIDX_ARRAY_PROTOTYPE 8 |
| 2263 | #define DUK_BIDX_STRING_CONSTRUCTOR 9 |
| 2264 | #define DUK_BIDX_STRING_PROTOTYPE 10 |
| 2265 | #define DUK_BIDX_BOOLEAN_CONSTRUCTOR 11 |
| 2266 | #define DUK_BIDX_BOOLEAN_PROTOTYPE 12 |
| 2267 | #define DUK_BIDX_NUMBER_CONSTRUCTOR 13 |
| 2268 | #define DUK_BIDX_NUMBER_PROTOTYPE 14 |
| 2269 | #define DUK_BIDX_DATE_CONSTRUCTOR 15 |
| 2270 | #define DUK_BIDX_DATE_PROTOTYPE 16 |
| 2271 | #define DUK_BIDX_REGEXP_CONSTRUCTOR 17 |
| 2272 | #define DUK_BIDX_REGEXP_PROTOTYPE 18 |
| 2273 | #define DUK_BIDX_ERROR_CONSTRUCTOR 19 |
| 2274 | #define DUK_BIDX_ERROR_PROTOTYPE 20 |
| 2275 | #define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 21 |
| 2276 | #define DUK_BIDX_EVAL_ERROR_PROTOTYPE 22 |
| 2277 | #define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 23 |
| 2278 | #define DUK_BIDX_RANGE_ERROR_PROTOTYPE 24 |
| 2279 | #define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 25 |
| 2280 | #define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 26 |
| 2281 | #define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 27 |
| 2282 | #define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 28 |
| 2283 | #define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 29 |
| 2284 | #define DUK_BIDX_TYPE_ERROR_PROTOTYPE 30 |
| 2285 | #define DUK_BIDX_URI_ERROR_CONSTRUCTOR 31 |
| 2286 | #define DUK_BIDX_URI_ERROR_PROTOTYPE 32 |
| 2287 | #define DUK_BIDX_TYPE_ERROR_THROWER 33 |
| 2288 | #define DUK_BIDX_DUKTAPE 34 |
| 2289 | #define DUK_BIDX_THREAD_PROTOTYPE 35 |
| 2290 | #define DUK_BIDX_POINTER_PROTOTYPE 36 |
| 2291 | #define DUK_BIDX_DOUBLE_ERROR 37 |
| 2292 | #define DUK_BIDX_SYMBOL_PROTOTYPE 38 |
| 2293 | #define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 39 |
| 2294 | #define DUK_BIDX_DATAVIEW_PROTOTYPE 40 |
| 2295 | #define DUK_BIDX_INT8ARRAY_PROTOTYPE 41 |
| 2296 | #define DUK_BIDX_UINT8ARRAY_PROTOTYPE 42 |
| 2297 | #define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 43 |
| 2298 | #define DUK_BIDX_INT16ARRAY_PROTOTYPE 44 |
| 2299 | #define DUK_BIDX_UINT16ARRAY_PROTOTYPE 45 |
| 2300 | #define DUK_BIDX_INT32ARRAY_PROTOTYPE 46 |
| 2301 | #define DUK_BIDX_UINT32ARRAY_PROTOTYPE 47 |
| 2302 | #define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 48 |
| 2303 | #define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 49 |
| 2304 | #define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50 |
| 2305 | #define DUK_NUM_BUILTINS 51 |
| 2306 | #define DUK_NUM_BIDX_BUILTINS 51 |
| 2307 | #define DUK_NUM_ALL_BUILTINS 80 |
| 2308 | #if defined(DUK_USE_DOUBLE_LE) |
| 2309 | #if !defined(DUK_SINGLE_FILE) |
| 2310 | DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281]; |
| 2311 | #endif /* !DUK_SINGLE_FILE */ |
| 2312 | #define DUK_BUILTINS_DATA_LENGTH 4281 |
| 2313 | #elif defined(DUK_USE_DOUBLE_BE) |
| 2314 | #if !defined(DUK_SINGLE_FILE) |
| 2315 | DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281]; |
| 2316 | #endif /* !DUK_SINGLE_FILE */ |
| 2317 | #define DUK_BUILTINS_DATA_LENGTH 4281 |
| 2318 | #elif defined(DUK_USE_DOUBLE_ME) |
| 2319 | #if !defined(DUK_SINGLE_FILE) |
| 2320 | DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281]; |
| 2321 | #endif /* !DUK_SINGLE_FILE */ |
| 2322 | #define DUK_BUILTINS_DATA_LENGTH 4281 |
| 2323 | #else |
| 2324 | #error invalid endianness defines |
| 2325 | #endif |
| 2326 | #endif /* DUK_USE_ROM_OBJECTS */ |
| 2327 | #endif /* DUK_BUILTINS_H_INCLUDED */ |
| 2328 | #line 45 "duk_internal.h" |
| 2329 | |
| 2330 | /* #include duk_util.h */ |
| 2331 | #line 1 "duk_util.h" |
| 2332 | /* |
| 2333 | * Utilities |
| 2334 | */ |
| 2335 | |
| 2336 | #if !defined(DUK_UTIL_H_INCLUDED) |
| 2337 | #define DUK_UTIL_H_INCLUDED |
| 2338 | |
| 2339 | #if defined(DUK_USE_GET_RANDOM_DOUBLE) |
| 2340 | #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata) |
| 2341 | #else |
| 2342 | #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr) |
| 2343 | #endif |
| 2344 | |
| 2345 | /* |
| 2346 | * Some useful constants |
| 2347 | */ |
| 2348 | |
| 2349 | #define DUK_DOUBLE_2TO32 4294967296.0 |
| 2350 | #define DUK_DOUBLE_2TO31 2147483648.0 |
| 2351 | #define DUK_DOUBLE_LOG2E 1.4426950408889634 |
| 2352 | #define DUK_DOUBLE_LOG10E 0.4342944819032518 |
| 2353 | |
| 2354 | /* |
| 2355 | * Endian conversion |
| 2356 | */ |
| 2357 | |
| 2358 | #if defined(DUK_USE_INTEGER_LE) |
| 2359 | #define DUK_HTON32(x) DUK_BSWAP32((x)) |
| 2360 | #define DUK_NTOH32(x) DUK_BSWAP32((x)) |
| 2361 | #define DUK_HTON16(x) DUK_BSWAP16((x)) |
| 2362 | #define DUK_NTOH16(x) DUK_BSWAP16((x)) |
| 2363 | #elif defined(DUK_USE_INTEGER_BE) |
| 2364 | #define DUK_HTON32(x) (x) |
| 2365 | #define DUK_NTOH32(x) (x) |
| 2366 | #define DUK_HTON16(x) (x) |
| 2367 | #define DUK_NTOH16(x) (x) |
| 2368 | #else |
| 2369 | #error internal error, endianness defines broken |
| 2370 | #endif |
| 2371 | |
| 2372 | /* |
| 2373 | * Bitstream decoder |
| 2374 | */ |
| 2375 | |
| 2376 | struct duk_bitdecoder_ctx { |
| 2377 | const duk_uint8_t *data; |
| 2378 | duk_size_t offset; |
| 2379 | duk_size_t length; |
| 2380 | duk_uint32_t currval; |
| 2381 | duk_small_int_t currbits; |
| 2382 | }; |
| 2383 | |
| 2384 | #define DUK_BD_BITPACKED_STRING_MAXLEN 256 |
| 2385 | |
| 2386 | /* |
| 2387 | * Bitstream encoder |
| 2388 | */ |
| 2389 | |
| 2390 | struct duk_bitencoder_ctx { |
| 2391 | duk_uint8_t *data; |
| 2392 | duk_size_t offset; |
| 2393 | duk_size_t length; |
| 2394 | duk_uint32_t currval; |
| 2395 | duk_small_int_t currbits; |
| 2396 | duk_small_int_t truncated; |
| 2397 | }; |
| 2398 | |
| 2399 | /* |
| 2400 | * Raw write/read macros for big endian, unaligned basic values. |
| 2401 | * Caller ensures there's enough space. The INC macro variants |
| 2402 | * update the pointer argument automatically. |
| 2403 | */ |
| 2404 | |
| 2405 | #define DUK_RAW_WRITE_U8(ptr,val) do { \ |
| 2406 | *(ptr) = (duk_uint8_t) (val); \ |
| 2407 | } while (0) |
| 2408 | #define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be((ptr), (duk_uint16_t) (val)) |
| 2409 | #define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be((ptr), (duk_uint32_t) (val)) |
| 2410 | #define DUK_RAW_WRITE_FLOAT_BE(ptr,val) duk_raw_write_float_be((ptr), (duk_float_t) (val)) |
| 2411 | #define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be((ptr), (duk_double_t) (val)) |
| 2412 | #define DUK_RAW_WRITE_XUTF8(ptr,val) duk_raw_write_xutf8((ptr), (duk_ucodepoint_t) (val)) |
| 2413 | |
| 2414 | #define DUK_RAW_WRITEINC_U8(ptr,val) do { \ |
| 2415 | *(ptr)++ = (duk_uint8_t) (val); \ |
| 2416 | } while (0) |
| 2417 | #define DUK_RAW_WRITEINC_U16_BE(ptr,val) duk_raw_writeinc_u16_be(&(ptr), (duk_uint16_t) (val)) |
| 2418 | #define DUK_RAW_WRITEINC_U32_BE(ptr,val) duk_raw_writeinc_u32_be(&(ptr), (duk_uint32_t) (val)) |
| 2419 | #define DUK_RAW_WRITEINC_FLOAT_BE(ptr,val) duk_raw_writeinc_float_be(&(ptr), (duk_float_t) (val)) |
| 2420 | #define DUK_RAW_WRITEINC_DOUBLE_BE(ptr,val) duk_raw_writeinc_double_be(&(ptr), (duk_double_t) (val)) |
| 2421 | #define DUK_RAW_WRITEINC_XUTF8(ptr,val) duk_raw_writeinc_xutf8(&(ptr), (duk_ucodepoint_t) (val)) |
| 2422 | #define DUK_RAW_WRITEINC_CESU8(ptr,val) duk_raw_writeinc_cesu8(&(ptr), (duk_ucodepoint_t) (val)) |
| 2423 | |
| 2424 | #define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr))) |
| 2425 | #define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be((ptr)); |
| 2426 | #define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be((ptr)); |
| 2427 | #define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be((ptr)); |
| 2428 | |
| 2429 | #define DUK_RAW_READINC_U8(ptr) ((duk_uint8_t) (*(ptr)++)) |
| 2430 | #define DUK_RAW_READINC_U16_BE(ptr) duk_raw_readinc_u16_be(&(ptr)); |
| 2431 | #define DUK_RAW_READINC_U32_BE(ptr) duk_raw_readinc_u32_be(&(ptr)); |
| 2432 | #define DUK_RAW_READINC_DOUBLE_BE(ptr) duk_raw_readinc_double_be(&(ptr)); |
| 2433 | |
| 2434 | /* |
| 2435 | * Double and float byte order operations. |
| 2436 | */ |
| 2437 | |
| 2438 | DUK_INTERNAL_DECL void duk_dblunion_host_to_little(duk_double_union *u); |
| 2439 | DUK_INTERNAL_DECL void duk_dblunion_little_to_host(duk_double_union *u); |
| 2440 | DUK_INTERNAL_DECL void duk_dblunion_host_to_big(duk_double_union *u); |
| 2441 | DUK_INTERNAL_DECL void duk_dblunion_big_to_host(duk_double_union *u); |
| 2442 | DUK_INTERNAL_DECL void duk_fltunion_host_to_big(duk_float_union *u); |
| 2443 | DUK_INTERNAL_DECL void duk_fltunion_big_to_host(duk_float_union *u); |
| 2444 | |
| 2445 | /* |
| 2446 | * Buffer writer (dynamic buffer only) |
| 2447 | * |
| 2448 | * Helper for writing to a dynamic buffer with a concept of a "slack" area |
| 2449 | * to reduce resizes. You can ensure there is enough space beforehand and |
| 2450 | * then write for a while without further checks, relying on a stable data |
| 2451 | * pointer. Slack handling is automatic so call sites only indicate how |
| 2452 | * much data they need right now. |
| 2453 | * |
| 2454 | * There are several ways to write using bufwriter. The best approach |
| 2455 | * depends mainly on how much performance matters over code footprint. |
| 2456 | * The key issues are (1) ensuring there is space and (2) keeping the |
| 2457 | * pointers consistent. Fast code should ensure space for multiple writes |
| 2458 | * with one ensure call. Fastest inner loop code can temporarily borrow |
| 2459 | * the 'p' pointer but must write it back eventually. |
| 2460 | * |
| 2461 | * Be careful to ensure all macro arguments (other than static pointers like |
| 2462 | * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if |
| 2463 | * necessary (if that's not possible, there should be a note near the macro). |
| 2464 | * Buffer write arguments often contain arithmetic etc so this is |
| 2465 | * particularly important here. |
| 2466 | */ |
| 2467 | |
| 2468 | /* XXX: Migrate bufwriter and other read/write helpers to its own header? */ |
| 2469 | |
| 2470 | struct duk_bufwriter_ctx { |
| 2471 | duk_uint8_t *p; |
| 2472 | duk_uint8_t *p_base; |
| 2473 | duk_uint8_t *p_limit; |
| 2474 | duk_hbuffer_dynamic *buf; |
| 2475 | }; |
| 2476 | |
| 2477 | #if defined(DUK_USE_PREFER_SIZE) |
| 2478 | #define DUK_BW_SLACK_ADD 64 |
| 2479 | #define DUK_BW_SLACK_SHIFT 4 /* 2^4 -> 1/16 = 6.25% slack */ |
| 2480 | #else |
| 2481 | #define DUK_BW_SLACK_ADD 64 |
| 2482 | #define DUK_BW_SLACK_SHIFT 2 /* 2^2 -> 1/4 = 25% slack */ |
| 2483 | #endif |
| 2484 | |
| 2485 | /* Initialization and finalization (compaction), converting to other types. */ |
| 2486 | |
| 2487 | #define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \ |
| 2488 | duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \ |
| 2489 | } while (0) |
| 2490 | #define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \ |
| 2491 | duk_bw_init((thr), (bw_ctx), (buf)); \ |
| 2492 | } while (0) |
| 2493 | #define DUK_BW_COMPACT(thr,bw_ctx) do { \ |
| 2494 | /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \ |
| 2495 | duk_bw_compact((thr), (bw_ctx)); \ |
| 2496 | } while (0) |
| 2497 | #define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \ |
| 2498 | duk_push_lstring((thr), \ |
| 2499 | (const char *) (bw_ctx)->p_base, \ |
| 2500 | (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ |
| 2501 | } while (0) |
| 2502 | |
| 2503 | /* Pointers may be NULL for a while when 'buf' size is zero and before any |
| 2504 | * ENSURE calls have been made. Once an ENSURE has been made, the pointers |
| 2505 | * are required to be non-NULL so that it's always valid to use memcpy() and |
| 2506 | * memmove(), even for zero size. |
| 2507 | */ |
| 2508 | #if defined(DUK_USE_ASSERTIONS) |
| 2509 | DUK_INTERNAL_DECL void duk_bw_assert_valid(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx); |
| 2510 | #define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) (duk_bw_assert_valid((thr), (bw_ctx))) |
| 2511 | #define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { duk_bw_assert_valid((thr), (bw_ctx)); } while (0) |
| 2512 | #else |
| 2513 | #define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) DUK_ASSERT_EXPR(1) |
| 2514 | #define DUK_BW_ASSERT_VALID(thr,bw_ctx) do {} while (0) |
| 2515 | #endif |
| 2516 | |
| 2517 | /* Working with the pointer and current size. */ |
| 2518 | |
| 2519 | #define DUK_BW_GET_PTR(thr,bw_ctx) \ |
| 2520 | ((bw_ctx)->p) |
| 2521 | #define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \ |
| 2522 | (bw_ctx)->p = (ptr); \ |
| 2523 | } while (0) |
| 2524 | #define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \ |
| 2525 | (bw_ctx)->p += (delta); \ |
| 2526 | } while (0) |
| 2527 | #define DUK_BW_GET_BASEPTR(thr,bw_ctx) \ |
| 2528 | ((bw_ctx)->p_base) |
| 2529 | #define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \ |
| 2530 | ((bw_ctx)->p_limit) |
| 2531 | #define DUK_BW_GET_SIZE(thr,bw_ctx) \ |
| 2532 | ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)) |
| 2533 | #define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \ |
| 2534 | DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \ |
| 2535 | (bw_ctx)->p = (bw_ctx)->p_base + (sz); \ |
| 2536 | } while (0) |
| 2537 | #define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \ |
| 2538 | /* Reset to zero size, keep current limit. */ \ |
| 2539 | (bw_ctx)->p = (bw_ctx)->p_base; \ |
| 2540 | } while (0) |
| 2541 | #define DUK_BW_GET_BUFFER(thr,bw_ctx) \ |
| 2542 | ((bw_ctx)->buf) |
| 2543 | |
| 2544 | /* Ensuring (reserving) space. */ |
| 2545 | |
| 2546 | #define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \ |
| 2547 | duk_size_t duk__sz, duk__space; \ |
| 2548 | DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \ |
| 2549 | duk__sz = (sz); \ |
| 2550 | duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \ |
| 2551 | if (duk__space < duk__sz) { \ |
| 2552 | (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \ |
| 2553 | } \ |
| 2554 | } while (0) |
| 2555 | /* NOTE: Multiple evaluation of 'ptr' in this macro. */ |
| 2556 | /* XXX: Rework to use an always-inline function? */ |
| 2557 | #define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \ |
| 2558 | (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \ |
| 2559 | (ptr) : \ |
| 2560 | ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz)))) |
| 2561 | #define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \ |
| 2562 | DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p) |
| 2563 | #define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \ |
| 2564 | (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \ |
| 2565 | DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz))) |
| 2566 | #define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \ |
| 2567 | DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \ |
| 2568 | } while (0) |
| 2569 | |
| 2570 | /* Miscellaneous. */ |
| 2571 | |
| 2572 | #define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \ |
| 2573 | (bw_ctx)->p = (ptr); \ |
| 2574 | duk_bw_compact((thr), (bw_ctx)); \ |
| 2575 | } while (0) |
| 2576 | |
| 2577 | /* Fast write calls which assume you control the slack beforehand. |
| 2578 | * Multibyte write variants exist and use a temporary write pointer |
| 2579 | * because byte writes alias with anything: with a stored pointer |
| 2580 | * explicit pointer load/stores get generated (e.g. gcc -Os). |
| 2581 | */ |
| 2582 | |
| 2583 | #define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \ |
| 2584 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \ |
| 2585 | *(bw_ctx)->p++ = (duk_uint8_t) (val); \ |
| 2586 | } while (0) |
| 2587 | #define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \ |
| 2588 | duk_uint8_t *duk__p; \ |
| 2589 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \ |
| 2590 | duk__p = (bw_ctx)->p; \ |
| 2591 | *duk__p++ = (duk_uint8_t) (val1); \ |
| 2592 | *duk__p++ = (duk_uint8_t) (val2); \ |
| 2593 | (bw_ctx)->p = duk__p; \ |
| 2594 | } while (0) |
| 2595 | #define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \ |
| 2596 | duk_uint8_t *duk__p; \ |
| 2597 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \ |
| 2598 | duk__p = (bw_ctx)->p; \ |
| 2599 | *duk__p++ = (duk_uint8_t) (val1); \ |
| 2600 | *duk__p++ = (duk_uint8_t) (val2); \ |
| 2601 | *duk__p++ = (duk_uint8_t) (val3); \ |
| 2602 | (bw_ctx)->p = duk__p; \ |
| 2603 | } while (0) |
| 2604 | #define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ |
| 2605 | duk_uint8_t *duk__p; \ |
| 2606 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \ |
| 2607 | duk__p = (bw_ctx)->p; \ |
| 2608 | *duk__p++ = (duk_uint8_t) (val1); \ |
| 2609 | *duk__p++ = (duk_uint8_t) (val2); \ |
| 2610 | *duk__p++ = (duk_uint8_t) (val3); \ |
| 2611 | *duk__p++ = (duk_uint8_t) (val4); \ |
| 2612 | (bw_ctx)->p = duk__p; \ |
| 2613 | } while (0) |
| 2614 | #define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ |
| 2615 | duk_uint8_t *duk__p; \ |
| 2616 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \ |
| 2617 | duk__p = (bw_ctx)->p; \ |
| 2618 | *duk__p++ = (duk_uint8_t) (val1); \ |
| 2619 | *duk__p++ = (duk_uint8_t) (val2); \ |
| 2620 | *duk__p++ = (duk_uint8_t) (val3); \ |
| 2621 | *duk__p++ = (duk_uint8_t) (val4); \ |
| 2622 | *duk__p++ = (duk_uint8_t) (val5); \ |
| 2623 | (bw_ctx)->p = duk__p; \ |
| 2624 | } while (0) |
| 2625 | #define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ |
| 2626 | duk_uint8_t *duk__p; \ |
| 2627 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \ |
| 2628 | duk__p = (bw_ctx)->p; \ |
| 2629 | *duk__p++ = (duk_uint8_t) (val1); \ |
| 2630 | *duk__p++ = (duk_uint8_t) (val2); \ |
| 2631 | *duk__p++ = (duk_uint8_t) (val3); \ |
| 2632 | *duk__p++ = (duk_uint8_t) (val4); \ |
| 2633 | *duk__p++ = (duk_uint8_t) (val5); \ |
| 2634 | *duk__p++ = (duk_uint8_t) (val6); \ |
| 2635 | (bw_ctx)->p = duk__p; \ |
| 2636 | } while (0) |
| 2637 | #define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \ |
| 2638 | duk_ucodepoint_t duk__cp; \ |
| 2639 | duk_small_int_t duk__enc_len; \ |
| 2640 | duk__cp = (duk_ucodepoint_t) (cp); \ |
| 2641 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \ |
| 2642 | duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \ |
| 2643 | (bw_ctx)->p += duk__enc_len; \ |
| 2644 | } while (0) |
| 2645 | #define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \ |
| 2646 | duk_ucodepoint_t duk__cp; \ |
| 2647 | duk_small_int_t duk__enc_len; \ |
| 2648 | duk__cp = (duk_ucodepoint_t) (cp); \ |
| 2649 | DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \ |
| 2650 | duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \ |
| 2651 | (bw_ctx)->p += duk__enc_len; \ |
| 2652 | } while (0) |
| 2653 | /* XXX: add temporary duk__p pointer here too; sharing */ |
| 2654 | /* XXX: avoid unsafe variants */ |
| 2655 | #define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \ |
| 2656 | const void *duk__valptr; \ |
| 2657 | duk_size_t duk__valsz; \ |
| 2658 | duk__valptr = (const void *) (valptr); \ |
| 2659 | duk__valsz = (duk_size_t) (valsz); \ |
| 2660 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ |
| 2661 | (bw_ctx)->p += duk__valsz; \ |
| 2662 | } while (0) |
| 2663 | #define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \ |
| 2664 | const duk_uint8_t *duk__val; \ |
| 2665 | duk_size_t duk__val_len; \ |
| 2666 | duk__val = (const duk_uint8_t *) (val); \ |
| 2667 | duk__val_len = DUK_STRLEN((const char *) duk__val); \ |
| 2668 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ |
| 2669 | (bw_ctx)->p += duk__val_len; \ |
| 2670 | } while (0) |
| 2671 | #define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \ |
| 2672 | duk_size_t duk__val_len; \ |
| 2673 | duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ |
| 2674 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ |
| 2675 | (bw_ctx)->p += duk__val_len; \ |
| 2676 | } while (0) |
| 2677 | #define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \ |
| 2678 | duk_size_t duk__val_len; \ |
| 2679 | duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ |
| 2680 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ |
| 2681 | (bw_ctx)->p += duk__val_len; \ |
| 2682 | } while (0) |
| 2683 | #define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \ |
| 2684 | duk_size_t duk__val_len; \ |
| 2685 | duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ |
| 2686 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ |
| 2687 | (bw_ctx)->p += duk__val_len; \ |
| 2688 | } while (0) |
| 2689 | #define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ |
| 2690 | duk_size_t duk__val_len; \ |
| 2691 | duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ |
| 2692 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ |
| 2693 | (bw_ctx)->p += duk__val_len; \ |
| 2694 | } while (0) |
| 2695 | |
| 2696 | /* Append bytes from a slice already in the buffer. */ |
| 2697 | #define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \ |
| 2698 | duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len)) |
| 2699 | |
| 2700 | /* Insert bytes in the middle of the buffer from an external buffer. */ |
| 2701 | #define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \ |
| 2702 | duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len)) |
| 2703 | |
| 2704 | /* Insert bytes in the middle of the buffer from a slice already |
| 2705 | * in the buffer. Source offset is interpreted "before" the operation. |
| 2706 | */ |
| 2707 | #define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \ |
| 2708 | duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len)) |
| 2709 | |
| 2710 | /* Insert a reserved area somewhere in the buffer; caller fills it. |
| 2711 | * Evaluates to a (duk_uint_t *) pointing to the start of the reserved |
| 2712 | * area for convenience. |
| 2713 | */ |
| 2714 | #define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \ |
| 2715 | duk_bw_insert_raw_area((thr), (bw), (off), (len)) |
| 2716 | |
| 2717 | /* Remove a slice from inside buffer. */ |
| 2718 | #define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \ |
| 2719 | duk_bw_remove_raw_slice((thr), (bw), (off), (len)) |
| 2720 | |
| 2721 | /* Safe write calls which will ensure space first. */ |
| 2722 | |
| 2723 | #define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \ |
| 2724 | DUK_BW_ENSURE((thr), (bw_ctx), 1); \ |
| 2725 | DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \ |
| 2726 | } while (0) |
| 2727 | #define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \ |
| 2728 | DUK_BW_ENSURE((thr), (bw_ctx), 2); \ |
| 2729 | DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \ |
| 2730 | } while (0) |
| 2731 | #define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \ |
| 2732 | DUK_BW_ENSURE((thr), (bw_ctx), 3); \ |
| 2733 | DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \ |
| 2734 | } while (0) |
| 2735 | #define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \ |
| 2736 | DUK_BW_ENSURE((thr), (bw_ctx), 4); \ |
| 2737 | DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \ |
| 2738 | } while (0) |
| 2739 | #define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \ |
| 2740 | DUK_BW_ENSURE((thr), (bw_ctx), 5); \ |
| 2741 | DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \ |
| 2742 | } while (0) |
| 2743 | #define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \ |
| 2744 | DUK_BW_ENSURE((thr), (bw_ctx), 6); \ |
| 2745 | DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \ |
| 2746 | } while (0) |
| 2747 | #define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \ |
| 2748 | DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \ |
| 2749 | DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \ |
| 2750 | } while (0) |
| 2751 | #define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \ |
| 2752 | DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \ |
| 2753 | DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \ |
| 2754 | } while (0) |
| 2755 | /* XXX: add temporary duk__p pointer here too; sharing */ |
| 2756 | /* XXX: avoid unsafe */ |
| 2757 | #define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \ |
| 2758 | const void *duk__valptr; \ |
| 2759 | duk_size_t duk__valsz; \ |
| 2760 | duk__valptr = (const void *) (valptr); \ |
| 2761 | duk__valsz = (duk_size_t) (valsz); \ |
| 2762 | DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \ |
| 2763 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \ |
| 2764 | (bw_ctx)->p += duk__valsz; \ |
| 2765 | } while (0) |
| 2766 | #define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \ |
| 2767 | const duk_uint8_t *duk__val; \ |
| 2768 | duk_size_t duk__val_len; \ |
| 2769 | duk__val = (const duk_uint8_t *) (val); \ |
| 2770 | duk__val_len = DUK_STRLEN((const char *) duk__val); \ |
| 2771 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ |
| 2772 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \ |
| 2773 | (bw_ctx)->p += duk__val_len; \ |
| 2774 | } while (0) |
| 2775 | #define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \ |
| 2776 | duk_size_t duk__val_len; \ |
| 2777 | duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \ |
| 2778 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ |
| 2779 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \ |
| 2780 | (bw_ctx)->p += duk__val_len; \ |
| 2781 | } while (0) |
| 2782 | #define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \ |
| 2783 | duk_size_t duk__val_len; \ |
| 2784 | duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \ |
| 2785 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ |
| 2786 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ |
| 2787 | (bw_ctx)->p += duk__val_len; \ |
| 2788 | } while (0) |
| 2789 | #define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \ |
| 2790 | duk_size_t duk__val_len; \ |
| 2791 | duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \ |
| 2792 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ |
| 2793 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ |
| 2794 | (bw_ctx)->p += duk__val_len; \ |
| 2795 | } while (0) |
| 2796 | #define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \ |
| 2797 | duk_size_t duk__val_len; \ |
| 2798 | duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \ |
| 2799 | DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \ |
| 2800 | duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \ |
| 2801 | (bw_ctx)->p += duk__val_len; \ |
| 2802 | } while (0) |
| 2803 | |
| 2804 | #define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \ |
| 2805 | duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len)) |
| 2806 | #define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \ |
| 2807 | duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len)) |
| 2808 | #define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \ |
| 2809 | duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len)) |
| 2810 | #define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \ |
| 2811 | /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \ |
| 2812 | duk_bw_insert_ensure_area((thr), (bw), (off), (len)) |
| 2813 | #define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \ |
| 2814 | /* No difference between raw/ensure because the buffer shrinks. */ \ |
| 2815 | DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len)) |
| 2816 | |
| 2817 | /* |
| 2818 | * Externs and prototypes |
| 2819 | */ |
| 2820 | |
| 2821 | #if !defined(DUK_SINGLE_FILE) |
| 2822 | DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36]; |
| 2823 | DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16]; |
| 2824 | DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256]; |
| 2825 | #if defined(DUK_USE_HEX_FASTPATH) |
| 2826 | DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256]; |
| 2827 | DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256]; |
| 2828 | #endif |
| 2829 | #endif /* !DUK_SINGLE_FILE */ |
| 2830 | |
| 2831 | /* Note: assumes that duk_util_probe_steps size is 32 */ |
| 2832 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 2833 | #if !defined(DUK_SINGLE_FILE) |
| 2834 | DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32]; |
| 2835 | #endif /* !DUK_SINGLE_FILE */ |
| 2836 | #endif |
| 2837 | |
| 2838 | #if defined(DUK_USE_STRHASH_DENSE) |
| 2839 | DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed); |
| 2840 | #endif |
| 2841 | |
| 2842 | DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits); |
| 2843 | DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx); |
| 2844 | DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value); |
| 2845 | DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value); |
| 2846 | DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx); |
| 2847 | DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out); |
| 2848 | |
| 2849 | DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits); |
| 2850 | DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx); |
| 2851 | |
| 2852 | #if !defined(DUK_USE_GET_RANDOM_DOUBLE) |
| 2853 | DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr); |
| 2854 | DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr); |
| 2855 | #endif |
| 2856 | |
| 2857 | DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf); |
| 2858 | DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size); |
| 2859 | DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz); |
| 2860 | DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx); |
| 2861 | DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); |
| 2862 | DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len); |
| 2863 | DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); |
| 2864 | DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len); |
| 2865 | DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); |
| 2866 | DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len); |
| 2867 | DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); |
| 2868 | DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); |
| 2869 | DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len); |
| 2870 | /* No duk_bw_remove_ensure_slice(), functionality would be identical. */ |
| 2871 | |
| 2872 | DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(const duk_uint8_t *p); |
| 2873 | DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(const duk_uint8_t *p); |
| 2874 | DUK_INTERNAL_DECL duk_float_t duk_raw_read_float_be(const duk_uint8_t *p); |
| 2875 | DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(const duk_uint8_t *p); |
| 2876 | DUK_INTERNAL_DECL duk_uint16_t duk_raw_readinc_u16_be(const duk_uint8_t **p); |
| 2877 | DUK_INTERNAL_DECL duk_uint32_t duk_raw_readinc_u32_be(const duk_uint8_t **p); |
| 2878 | DUK_INTERNAL_DECL duk_float_t duk_raw_readinc_float_be(const duk_uint8_t **p); |
| 2879 | DUK_INTERNAL_DECL duk_double_t duk_raw_readinc_double_be(const duk_uint8_t **p); |
| 2880 | DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t *p, duk_uint16_t val); |
| 2881 | DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t *p, duk_uint32_t val); |
| 2882 | DUK_INTERNAL_DECL void duk_raw_write_float_be(duk_uint8_t *p, duk_float_t val); |
| 2883 | DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t *p, duk_double_t val); |
| 2884 | DUK_INTERNAL_DECL duk_small_int_t duk_raw_write_xutf8(duk_uint8_t *p, duk_ucodepoint_t val); |
| 2885 | DUK_INTERNAL_DECL duk_small_int_t duk_raw_write_cesu8(duk_uint8_t *p, duk_ucodepoint_t val); |
| 2886 | DUK_INTERNAL_DECL void duk_raw_writeinc_u16_be(duk_uint8_t **p, duk_uint16_t val); |
| 2887 | DUK_INTERNAL_DECL void duk_raw_writeinc_u32_be(duk_uint8_t **p, duk_uint32_t val); |
| 2888 | DUK_INTERNAL_DECL void duk_raw_writeinc_float_be(duk_uint8_t **p, duk_float_t val); |
| 2889 | DUK_INTERNAL_DECL void duk_raw_writeinc_double_be(duk_uint8_t **p, duk_double_t val); |
| 2890 | DUK_INTERNAL_DECL void duk_raw_writeinc_xutf8(duk_uint8_t **p, duk_ucodepoint_t val); |
| 2891 | DUK_INTERNAL_DECL void duk_raw_writeinc_cesu8(duk_uint8_t **p, duk_ucodepoint_t val); |
| 2892 | |
| 2893 | #if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ |
| 2894 | DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len); |
| 2895 | #endif |
| 2896 | |
| 2897 | /* memcpy(), memmove() etc wrappers. The plain variants like duk_memcpy() |
| 2898 | * assume C99+ and 'src' and 'dst' pointers must be non-NULL even when the |
| 2899 | * operation size is zero. The unsafe variants like duk_memcpy_safe() deal |
| 2900 | * with the zero size case explicitly, and allow NULL pointers in that case |
| 2901 | * (which is undefined behavior in C99+). For the majority of actual targets |
| 2902 | * a NULL pointer with a zero length is fine in practice. These wrappers are |
| 2903 | * macros to force inlining; because there are hundreds of call sites, even a |
| 2904 | * few extra bytes per call site adds up to ~1kB footprint. |
| 2905 | */ |
| 2906 | #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 2907 | #define duk_memcpy(dst,src,len) do { \ |
| 2908 | void *duk__dst = (dst); \ |
| 2909 | const void *duk__src = (src); \ |
| 2910 | duk_size_t duk__len = (len); \ |
| 2911 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 2912 | DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ |
| 2913 | (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ |
| 2914 | } while (0) |
| 2915 | #define duk_memcpy_unsafe(dst,src,len) duk_memcpy((dst), (src), (len)) |
| 2916 | #define duk_memmove(dst,src,len) do { \ |
| 2917 | void *duk__dst = (dst); \ |
| 2918 | const void *duk__src = (src); \ |
| 2919 | duk_size_t duk__len = (len); \ |
| 2920 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 2921 | DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ |
| 2922 | (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ |
| 2923 | } while (0) |
| 2924 | #define duk_memmove_unsafe(dst,src,len) duk_memmove((dst), (src), (len)) |
| 2925 | #define duk_memset(dst,val,len) do { \ |
| 2926 | void *duk__dst = (dst); \ |
| 2927 | duk_small_int_t duk__val = (val); \ |
| 2928 | duk_size_t duk__len = (len); \ |
| 2929 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 2930 | (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ |
| 2931 | } while (0) |
| 2932 | #define duk_memset_unsafe(dst,val,len) duk_memset((dst), (val), (len)) |
| 2933 | #define duk_memzero(dst,len) do { \ |
| 2934 | void *duk__dst = (dst); \ |
| 2935 | duk_size_t duk__len = (len); \ |
| 2936 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 2937 | (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ |
| 2938 | } while (0) |
| 2939 | #define duk_memzero_unsafe(dst,len) duk_memzero((dst), (len)) |
| 2940 | #else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ |
| 2941 | #define duk_memcpy(dst,src,len) do { \ |
| 2942 | void *duk__dst = (dst); \ |
| 2943 | const void *duk__src = (src); \ |
| 2944 | duk_size_t duk__len = (len); \ |
| 2945 | DUK_ASSERT(duk__dst != NULL); \ |
| 2946 | DUK_ASSERT(duk__src != NULL); \ |
| 2947 | (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ |
| 2948 | } while (0) |
| 2949 | #define duk_memcpy_unsafe(dst,src,len) do { \ |
| 2950 | void *duk__dst = (dst); \ |
| 2951 | const void *duk__src = (src); \ |
| 2952 | duk_size_t duk__len = (len); \ |
| 2953 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 2954 | DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ |
| 2955 | if (DUK_LIKELY(duk__len > 0U)) { \ |
| 2956 | DUK_ASSERT(duk__dst != NULL); \ |
| 2957 | DUK_ASSERT(duk__src != NULL); \ |
| 2958 | (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \ |
| 2959 | } \ |
| 2960 | } while (0) |
| 2961 | #define duk_memmove(dst,src,len) do { \ |
| 2962 | void *duk__dst = (dst); \ |
| 2963 | const void *duk__src = (src); \ |
| 2964 | duk_size_t duk__len = (len); \ |
| 2965 | DUK_ASSERT(duk__dst != NULL); \ |
| 2966 | DUK_ASSERT(duk__src != NULL); \ |
| 2967 | (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ |
| 2968 | } while (0) |
| 2969 | #define duk_memmove_unsafe(dst,src,len) do { \ |
| 2970 | void *duk__dst = (dst); \ |
| 2971 | const void *duk__src = (src); \ |
| 2972 | duk_size_t duk__len = (len); \ |
| 2973 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 2974 | DUK_ASSERT(duk__src != NULL || duk__len == 0U); \ |
| 2975 | if (DUK_LIKELY(duk__len > 0U)) { \ |
| 2976 | DUK_ASSERT(duk__dst != NULL); \ |
| 2977 | DUK_ASSERT(duk__src != NULL); \ |
| 2978 | (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \ |
| 2979 | } \ |
| 2980 | } while (0) |
| 2981 | #define duk_memset(dst,val,len) do { \ |
| 2982 | void *duk__dst = (dst); \ |
| 2983 | duk_small_int_t duk__val = (val); \ |
| 2984 | duk_size_t duk__len = (len); \ |
| 2985 | DUK_ASSERT(duk__dst != NULL); \ |
| 2986 | (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ |
| 2987 | } while (0) |
| 2988 | #define duk_memset_unsafe(dst,val,len) do { \ |
| 2989 | void *duk__dst = (dst); \ |
| 2990 | duk_small_int_t duk__val = (val); \ |
| 2991 | duk_size_t duk__len = (len); \ |
| 2992 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 2993 | if (DUK_LIKELY(duk__len > 0U)) { \ |
| 2994 | DUK_ASSERT(duk__dst != NULL); \ |
| 2995 | (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \ |
| 2996 | } \ |
| 2997 | } while (0) |
| 2998 | #define duk_memzero(dst,len) do { \ |
| 2999 | void *duk__dst = (dst); \ |
| 3000 | duk_size_t duk__len = (len); \ |
| 3001 | DUK_ASSERT(duk__dst != NULL); \ |
| 3002 | (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ |
| 3003 | } while (0) |
| 3004 | #define duk_memzero_unsafe(dst,len) do { \ |
| 3005 | void *duk__dst = (dst); \ |
| 3006 | duk_size_t duk__len = (len); \ |
| 3007 | DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \ |
| 3008 | if (DUK_LIKELY(duk__len > 0U)) { \ |
| 3009 | DUK_ASSERT(duk__dst != NULL); \ |
| 3010 | (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \ |
| 3011 | } \ |
| 3012 | } while (0) |
| 3013 | #endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ |
| 3014 | |
| 3015 | DUK_INTERNAL_DECL duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len); |
| 3016 | DUK_INTERNAL_DECL duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len); |
| 3017 | |
| 3018 | DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival); |
| 3019 | DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival); |
| 3020 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x); |
| 3021 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x); |
| 3022 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x); |
| 3023 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x); |
| 3024 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x); |
| 3025 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x); |
| 3026 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x); |
| 3027 | DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x); |
| 3028 | DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x); |
| 3029 | DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y); |
| 3030 | DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y); |
| 3031 | DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y); |
| 3032 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_finite(duk_double_t x); |
| 3033 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_integer(duk_double_t x); |
| 3034 | DUK_INTERNAL_DECL duk_bool_t duk_double_is_safe_integer(duk_double_t x); |
| 3035 | |
| 3036 | DUK_INTERNAL_DECL duk_double_t duk_double_div(duk_double_t x, duk_double_t y); |
| 3037 | DUK_INTERNAL_DECL duk_int_t duk_double_to_int_t(duk_double_t x); |
| 3038 | DUK_INTERNAL_DECL duk_uint_t duk_double_to_uint_t(duk_double_t x); |
| 3039 | DUK_INTERNAL_DECL duk_int32_t duk_double_to_int32_t(duk_double_t x); |
| 3040 | DUK_INTERNAL_DECL duk_uint32_t duk_double_to_uint32_t(duk_double_t x); |
| 3041 | DUK_INTERNAL_DECL duk_float_t duk_double_to_float_t(duk_double_t x); |
| 3042 | DUK_INTERNAL_DECL duk_bool_t duk_double_equals(duk_double_t x, duk_double_t y); |
| 3043 | DUK_INTERNAL_DECL duk_bool_t duk_float_equals(duk_float_t x, duk_float_t y); |
| 3044 | |
| 3045 | /* |
| 3046 | * Miscellaneous |
| 3047 | */ |
| 3048 | |
| 3049 | /* Example: x = 0x10 = 0b00010000 |
| 3050 | * x - 1 = 0x0f = 0b00001111 |
| 3051 | * x & (x - 1) == 0 |
| 3052 | * |
| 3053 | * x = 0x07 = 0b00000111 |
| 3054 | * x - 1 = 0x06 = 0b00000110 |
| 3055 | * x & (x - 1) != 0 |
| 3056 | * |
| 3057 | * However, incorrectly true for x == 0 so check for that explicitly. |
| 3058 | */ |
| 3059 | #define DUK_IS_POWER_OF_TWO(x) \ |
| 3060 | ((x) != 0U && ((x) & ((x) - 1U)) == 0U) |
| 3061 | |
| 3062 | #endif /* DUK_UTIL_H_INCLUDED */ |
| 3063 | /* #include duk_strings.h */ |
| 3064 | #line 1 "duk_strings.h" |
| 3065 | /* |
| 3066 | * Shared string macros. |
| 3067 | * |
| 3068 | * Using shared macros helps minimize strings data size because it's easy |
| 3069 | * to check if an existing string could be used. String constants don't |
| 3070 | * need to be all defined here; defining a string here makes sense if there's |
| 3071 | * a high chance the string could be reused. Also, using macros allows |
| 3072 | * a call site express the exact string needed, but the macro may map to an |
| 3073 | * approximate string to reduce unique string count. Macros can also be |
| 3074 | * more easily tuned for low memory targets than #if defined()s throughout |
| 3075 | * the code base. |
| 3076 | * |
| 3077 | * Because format strings behave differently in the call site (they need to |
| 3078 | * be followed by format arguments), they use a special prefix DUK_STR_FMT_. |
| 3079 | * |
| 3080 | * On some compilers using explicit shared strings is preferable; on others |
| 3081 | * it may be better to use straight literals because the compiler will combine |
| 3082 | * them anyway, and such strings won't end up unnecessarily in a symbol table. |
| 3083 | */ |
| 3084 | |
| 3085 | #if !defined(DUK_ERRMSG_H_INCLUDED) |
| 3086 | #define DUK_ERRMSG_H_INCLUDED |
| 3087 | |
| 3088 | /* Mostly API and built-in method related */ |
| 3089 | #define DUK_STR_INTERNAL_ERROR "internal error" |
| 3090 | #define DUK_STR_UNSUPPORTED "unsupported" |
| 3091 | #define DUK_STR_INVALID_COUNT "invalid count" |
| 3092 | #define DUK_STR_INVALID_ARGS "invalid args" |
| 3093 | #define DUK_STR_INVALID_STATE "invalid state" |
| 3094 | #define DUK_STR_INVALID_INPUT "invalid input" |
| 3095 | #define DUK_STR_INVALID_LENGTH "invalid length" |
| 3096 | #define DUK_STR_NOT_CONSTRUCTABLE "not constructable" |
| 3097 | #define DUK_STR_CONSTRUCT_ONLY "constructor requires 'new'" |
| 3098 | #define DUK_STR_NOT_CALLABLE "not callable" |
| 3099 | #define DUK_STR_NOT_EXTENSIBLE "not extensible" |
| 3100 | #define DUK_STR_NOT_WRITABLE "not writable" |
| 3101 | #define DUK_STR_NOT_CONFIGURABLE "not configurable" |
| 3102 | #define DUK_STR_INVALID_CONTEXT "invalid context" |
| 3103 | #define DUK_STR_INVALID_INDEX "invalid args" |
| 3104 | #define DUK_STR_PUSH_BEYOND_ALLOC_STACK "cannot push beyond allocated stack" |
| 3105 | #define DUK_STR_NOT_UNDEFINED "unexpected type" |
| 3106 | #define DUK_STR_NOT_NULL "unexpected type" |
| 3107 | #define DUK_STR_NOT_BOOLEAN "unexpected type" |
| 3108 | #define DUK_STR_NOT_NUMBER "unexpected type" |
| 3109 | #define DUK_STR_NOT_STRING "unexpected type" |
| 3110 | #define DUK_STR_NOT_OBJECT "unexpected type" |
| 3111 | #define DUK_STR_NOT_POINTER "unexpected type" |
| 3112 | #define DUK_STR_NOT_BUFFER "not buffer" /* still in use with verbose messages */ |
| 3113 | #define DUK_STR_UNEXPECTED_TYPE "unexpected type" |
| 3114 | #define DUK_STR_NOT_THREAD "unexpected type" |
| 3115 | #define DUK_STR_NOT_COMPFUNC "unexpected type" |
| 3116 | #define DUK_STR_NOT_NATFUNC "unexpected type" |
| 3117 | #define DUK_STR_NOT_C_FUNCTION "unexpected type" |
| 3118 | #define DUK_STR_NOT_FUNCTION "unexpected type" |
| 3119 | #define DUK_STR_NOT_REGEXP "unexpected type" |
| 3120 | #define DUK_STR_TOPRIMITIVE_FAILED "coercion to primitive failed" |
| 3121 | #define DUK_STR_NUMBER_OUTSIDE_RANGE "number outside range" |
| 3122 | #define DUK_STR_NOT_OBJECT_COERCIBLE "not object coercible" |
| 3123 | #define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL "cannot number coerce Symbol" |
| 3124 | #define DUK_STR_CANNOT_STRING_COERCE_SYMBOL "cannot string coerce Symbol" |
| 3125 | #define DUK_STR_STRING_TOO_LONG "string too long" |
| 3126 | #define DUK_STR_BUFFER_TOO_LONG "buffer too long" |
| 3127 | #define DUK_STR_ALLOC_FAILED "alloc failed" |
| 3128 | #define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type" |
| 3129 | #define DUK_STR_BASE64_ENCODE_FAILED "base64 encode failed" |
| 3130 | #define DUK_STR_SOURCE_DECODE_FAILED "source decode failed" |
| 3131 | #define DUK_STR_UTF8_DECODE_FAILED "utf-8 decode failed" |
| 3132 | #define DUK_STR_BASE64_DECODE_FAILED "base64 decode failed" |
| 3133 | #define DUK_STR_HEX_DECODE_FAILED "hex decode failed" |
| 3134 | #define DUK_STR_INVALID_BYTECODE "invalid bytecode" |
| 3135 | #define DUK_STR_NO_SOURCECODE "no sourcecode" |
| 3136 | #define DUK_STR_RESULT_TOO_LONG "result too long" |
| 3137 | #define DUK_STR_INVALID_CFUNC_RC "invalid C function rc" |
| 3138 | #define DUK_STR_INVALID_INSTANCEOF_RVAL "invalid instanceof rval" |
| 3139 | #define DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO "instanceof rval has no .prototype" |
| 3140 | |
| 3141 | /* JSON */ |
| 3142 | #define DUK_STR_FMT_PTR "%p" |
| 3143 | #define DUK_STR_FMT_INVALID_JSON "invalid json (at offset %ld)" |
| 3144 | #define DUK_STR_CYCLIC_INPUT "cyclic input" |
| 3145 | |
| 3146 | /* Generic codec */ |
| 3147 | #define DUK_STR_DEC_RECLIMIT "decode recursion limit" |
| 3148 | #define DUK_STR_ENC_RECLIMIT "encode recursion limit" |
| 3149 | |
| 3150 | /* Object property access */ |
| 3151 | #define DUK_STR_INVALID_BASE "invalid base value" |
| 3152 | #define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'" |
| 3153 | #define DUK_STR_PROXY_REJECTED "proxy rejected" |
| 3154 | #define DUK_STR_INVALID_ARRAY_LENGTH "invalid array length" |
| 3155 | #define DUK_STR_SETTER_UNDEFINED "setter undefined" |
| 3156 | #define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor" |
| 3157 | |
| 3158 | /* Proxy */ |
| 3159 | #define DUK_STR_PROXY_REVOKED "proxy revoked" |
| 3160 | #define DUK_STR_INVALID_TRAP_RESULT "invalid trap result" |
| 3161 | |
| 3162 | /* Variables */ |
| 3163 | |
| 3164 | /* Lexer */ |
| 3165 | #define DUK_STR_INVALID_ESCAPE "invalid escape" |
| 3166 | #define DUK_STR_UNTERMINATED_STRING "unterminated string" |
| 3167 | #define "unterminated comment" |
| 3168 | #define DUK_STR_UNTERMINATED_REGEXP "unterminated regexp" |
| 3169 | #define DUK_STR_TOKEN_LIMIT "token limit" |
| 3170 | #define DUK_STR_REGEXP_SUPPORT_DISABLED "regexp support disabled" |
| 3171 | #define DUK_STR_INVALID_NUMBER_LITERAL "invalid number literal" |
| 3172 | #define DUK_STR_INVALID_TOKEN "invalid token" |
| 3173 | |
| 3174 | /* Compiler */ |
| 3175 | #define DUK_STR_PARSE_ERROR "parse error" |
| 3176 | #define DUK_STR_DUPLICATE_LABEL "duplicate label" |
| 3177 | #define DUK_STR_INVALID_LABEL "invalid label" |
| 3178 | #define DUK_STR_INVALID_ARRAY_LITERAL "invalid array literal" |
| 3179 | #define DUK_STR_INVALID_OBJECT_LITERAL "invalid object literal" |
| 3180 | #define DUK_STR_INVALID_VAR_DECLARATION "invalid variable declaration" |
| 3181 | #define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier" |
| 3182 | #define DUK_STR_INVALID_EXPRESSION "invalid expression" |
| 3183 | #define DUK_STR_INVALID_LVALUE "invalid lvalue" |
| 3184 | #define DUK_STR_INVALID_NEWTARGET "invalid new.target" |
| 3185 | #define DUK_STR_EXPECTED_IDENTIFIER "expected identifier" |
| 3186 | #define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed" |
| 3187 | #define DUK_STR_INVALID_FOR "invalid for statement" |
| 3188 | #define DUK_STR_INVALID_SWITCH "invalid switch statement" |
| 3189 | #define DUK_STR_INVALID_BREAK_CONT_LABEL "invalid break/continue label" |
| 3190 | #define DUK_STR_INVALID_RETURN "invalid return" |
| 3191 | #define DUK_STR_INVALID_TRY "invalid try" |
| 3192 | #define DUK_STR_INVALID_THROW "invalid throw" |
| 3193 | #define DUK_STR_WITH_IN_STRICT_MODE "with in strict mode" |
| 3194 | #define DUK_STR_FUNC_STMT_NOT_ALLOWED "function statement not allowed" |
| 3195 | #define DUK_STR_UNTERMINATED_STMT "unterminated statement" |
| 3196 | #define DUK_STR_INVALID_ARG_NAME "invalid argument name" |
| 3197 | #define DUK_STR_INVALID_FUNC_NAME "invalid function name" |
| 3198 | #define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name" |
| 3199 | #define DUK_STR_FUNC_NAME_REQUIRED "function name required" |
| 3200 | |
| 3201 | /* RegExp */ |
| 3202 | #define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier" |
| 3203 | #define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom" |
| 3204 | #define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)" |
| 3205 | #define DUK_STR_QUANTIFIER_TOO_MANY_COPIES "quantifier requires too many atom copies" |
| 3206 | #define DUK_STR_UNEXPECTED_CLOSING_PAREN "unexpected closing parenthesis" |
| 3207 | #define DUK_STR_UNEXPECTED_END_OF_PATTERN "unexpected end of pattern" |
| 3208 | #define DUK_STR_UNEXPECTED_REGEXP_TOKEN "unexpected token in regexp" |
| 3209 | #define DUK_STR_INVALID_REGEXP_FLAGS "invalid regexp flags" |
| 3210 | #define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape" |
| 3211 | #define DUK_STR_INVALID_BACKREFS "invalid backreference(s)" |
| 3212 | #define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character" |
| 3213 | #define DUK_STR_INVALID_REGEXP_GROUP "invalid regexp group" |
| 3214 | #define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class" |
| 3215 | #define DUK_STR_INVALID_RANGE "invalid range" |
| 3216 | |
| 3217 | /* Limits */ |
| 3218 | #define DUK_STR_VALSTACK_LIMIT "valstack limit" |
| 3219 | #define DUK_STR_CALLSTACK_LIMIT "callstack limit" |
| 3220 | #define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit" |
| 3221 | #define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit" |
| 3222 | #define DUK_STR_NATIVE_STACK_LIMIT "C stack depth limit" |
| 3223 | #define DUK_STR_COMPILER_RECURSION_LIMIT "compiler recursion limit" |
| 3224 | #define DUK_STR_BYTECODE_LIMIT "bytecode limit" |
| 3225 | #define DUK_STR_REG_LIMIT "register limit" |
| 3226 | #define DUK_STR_TEMP_LIMIT "temp limit" |
| 3227 | #define DUK_STR_CONST_LIMIT "const limit" |
| 3228 | #define DUK_STR_FUNC_LIMIT "function limit" |
| 3229 | #define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT "regexp compiler recursion limit" |
| 3230 | #define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT "regexp executor recursion limit" |
| 3231 | #define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT "regexp step limit" |
| 3232 | |
| 3233 | #endif /* DUK_ERRMSG_H_INCLUDED */ |
| 3234 | /* #include duk_js_bytecode.h */ |
| 3235 | #line 1 "duk_js_bytecode.h" |
| 3236 | /* |
| 3237 | * ECMAScript bytecode |
| 3238 | */ |
| 3239 | |
| 3240 | #if !defined(DUK_JS_BYTECODE_H_INCLUDED) |
| 3241 | #define DUK_JS_BYTECODE_H_INCLUDED |
| 3242 | |
| 3243 | /* |
| 3244 | * Bytecode instruction layout |
| 3245 | * =========================== |
| 3246 | * |
| 3247 | * Instructions are unsigned 32-bit integers divided as follows: |
| 3248 | * |
| 3249 | * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! |
| 3250 | * !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! |
| 3251 | * +-----------------------------------------------+---------------+ |
| 3252 | * ! C ! B ! A ! OP ! |
| 3253 | * +-----------------------------------------------+---------------+ |
| 3254 | * |
| 3255 | * OP (8 bits): opcode (DUK_OP_*), access should be fastest |
| 3256 | * consecutive opcodes allocated when opcode needs flags |
| 3257 | * A (8 bits): typically a target register number |
| 3258 | * B (8 bits): typically first source register/constant number |
| 3259 | * C (8 bits): typically second source register/constant number |
| 3260 | * |
| 3261 | * Some instructions combine BC or ABC together for larger parameter values. |
| 3262 | * Signed integers (e.g. jump offsets) are encoded as unsigned, with an |
| 3263 | * opcode specific bias. |
| 3264 | * |
| 3265 | * Some opcodes have flags which are handled by allocating consecutive |
| 3266 | * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A' |
| 3267 | * field when there's room for the specific opcode. |
| 3268 | * |
| 3269 | * For example, if three flags were needed, they could be allocated from |
| 3270 | * the opcode field as follows: |
| 3271 | * |
| 3272 | * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! |
| 3273 | * !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! |
| 3274 | * +-----------------------------------------------+---------------+ |
| 3275 | * ! C ! B ! A ! OP !Z!Y!X! |
| 3276 | * +-----------------------------------------------+---------------+ |
| 3277 | * |
| 3278 | * Some opcodes accept a reg/const argument which is handled by allocating |
| 3279 | * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The |
| 3280 | * following convention is shared by most opcodes, so that the compiler |
| 3281 | * can handle reg/const flagging without opcode specific code paths: |
| 3282 | * |
| 3283 | * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! ! |
| 3284 | * !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! |
| 3285 | * +-----------------------------------------------+---------------+ |
| 3286 | * ! C ! B ! A ! OP !Y!X! |
| 3287 | * +-----------------------------------------------+---------------+ |
| 3288 | * |
| 3289 | * X 1=B is const, 0=B is reg |
| 3290 | * Y 1=C is const, 0=C is reg |
| 3291 | * |
| 3292 | * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the |
| 3293 | * 8-bit opcode space for a single logical opcode. The base opcode |
| 3294 | * number should be divisible by 4. If the opcode is called 'FOO' |
| 3295 | * the following opcode constants would be defined: |
| 3296 | * |
| 3297 | * DUK_OP_FOO 100 // base opcode number |
| 3298 | * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg |
| 3299 | * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg |
| 3300 | * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const |
| 3301 | * DUK_OP_FOO_CC 103 // FOO, B=const, C=const |
| 3302 | * |
| 3303 | * If only B or C is a reg/const, the unused opcode combinations can be |
| 3304 | * used for other opcodes (which take no reg/const argument). However, |
| 3305 | * such opcode values are initially reserved, at least while opcode space |
| 3306 | * is available. For example, if 'BAR' uses B for a register field and |
| 3307 | * C is a reg/const: |
| 3308 | * |
| 3309 | * DUK_OP_BAR 116 // base opcode number |
| 3310 | * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg |
| 3311 | * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed |
| 3312 | * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const |
| 3313 | * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed |
| 3314 | * |
| 3315 | * Macro naming is a bit misleading, e.g. "ABC" in macro name but the |
| 3316 | * field layout is concretely "CBA" in the register. |
| 3317 | */ |
| 3318 | |
| 3319 | typedef duk_uint32_t duk_instr_t; |
| 3320 | |
| 3321 | #define DUK_BC_SHIFT_OP 0 |
| 3322 | #define DUK_BC_SHIFT_A 8 |
| 3323 | #define DUK_BC_SHIFT_B 16 |
| 3324 | #define DUK_BC_SHIFT_C 24 |
| 3325 | #define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B |
| 3326 | #define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A |
| 3327 | |
| 3328 | #define DUK_BC_UNSHIFTED_MASK_OP 0xffUL |
| 3329 | #define DUK_BC_UNSHIFTED_MASK_A 0xffUL |
| 3330 | #define DUK_BC_UNSHIFTED_MASK_B 0xffUL |
| 3331 | #define DUK_BC_UNSHIFTED_MASK_C 0xffUL |
| 3332 | #define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL |
| 3333 | #define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL |
| 3334 | |
| 3335 | #define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP) |
| 3336 | #define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A) |
| 3337 | #define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B) |
| 3338 | #define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C) |
| 3339 | #define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC) |
| 3340 | #define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC) |
| 3341 | |
| 3342 | #define DUK_DEC_OP(x) ((x) & 0xffUL) |
| 3343 | #define DUK_DEC_A(x) (((x) >> 8) & 0xffUL) |
| 3344 | #define DUK_DEC_B(x) (((x) >> 16) & 0xffUL) |
| 3345 | #define DUK_DEC_C(x) (((x) >> 24) & 0xffUL) |
| 3346 | #define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL) |
| 3347 | #define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL) |
| 3348 | |
| 3349 | #define DUK_ENC_OP(op) ((duk_instr_t) (op)) |
| 3350 | #define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \ |
| 3351 | (((duk_instr_t) (abc)) << 8) | \ |
| 3352 | ((duk_instr_t) (op)) \ |
| 3353 | )) |
| 3354 | #define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \ |
| 3355 | (((duk_instr_t) (bc)) << 16) | \ |
| 3356 | (((duk_instr_t) (a)) << 8) | \ |
| 3357 | ((duk_instr_t) (op)) \ |
| 3358 | )) |
| 3359 | #define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \ |
| 3360 | (((duk_instr_t) (c)) << 24) | \ |
| 3361 | (((duk_instr_t) (b)) << 16) | \ |
| 3362 | (((duk_instr_t) (a)) << 8) | \ |
| 3363 | ((duk_instr_t) (op)) \ |
| 3364 | )) |
| 3365 | #define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0) |
| 3366 | #define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0) |
| 3367 | #define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc)) |
| 3368 | |
| 3369 | /* Get opcode base value with B/C reg/const flags cleared. */ |
| 3370 | #define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc) |
| 3371 | |
| 3372 | /* Constants should be signed so that signed arithmetic involving them |
| 3373 | * won't cause values to be coerced accidentally to unsigned. |
| 3374 | */ |
| 3375 | #define DUK_BC_OP_MIN 0 |
| 3376 | #define DUK_BC_OP_MAX 0xffL |
| 3377 | #define DUK_BC_A_MIN 0 |
| 3378 | #define DUK_BC_A_MAX 0xffL |
| 3379 | #define DUK_BC_B_MIN 0 |
| 3380 | #define DUK_BC_B_MAX 0xffL |
| 3381 | #define DUK_BC_C_MIN 0 |
| 3382 | #define DUK_BC_C_MAX 0xffL |
| 3383 | #define DUK_BC_BC_MIN 0 |
| 3384 | #define DUK_BC_BC_MAX 0xffffL |
| 3385 | #define DUK_BC_ABC_MIN 0 |
| 3386 | #define DUK_BC_ABC_MAX 0xffffffL |
| 3387 | |
| 3388 | /* Masks for B/C reg/const indicator in opcode field. */ |
| 3389 | #define DUK_BC_REGCONST_B (0x01UL) |
| 3390 | #define DUK_BC_REGCONST_C (0x02UL) |
| 3391 | |
| 3392 | /* Misc. masks for opcode field. */ |
| 3393 | #define DUK_BC_INCDECP_FLAG_DEC (0x04UL) |
| 3394 | #define DUK_BC_INCDECP_FLAG_POST (0x08UL) |
| 3395 | |
| 3396 | /* Opcodes. */ |
| 3397 | #define DUK_OP_LDREG 0 |
| 3398 | #define DUK_OP_STREG 1 |
| 3399 | #define DUK_OP_JUMP 2 |
| 3400 | #define DUK_OP_LDCONST 3 |
| 3401 | #define DUK_OP_LDINT 4 |
| 3402 | #define DUK_OP_LDINTX 5 |
| 3403 | #define DUK_OP_LDTHIS 6 |
| 3404 | #define DUK_OP_LDUNDEF 7 |
| 3405 | #define DUK_OP_LDNULL 8 |
| 3406 | #define DUK_OP_LDTRUE 9 |
| 3407 | #define DUK_OP_LDFALSE 10 |
| 3408 | #define DUK_OP_GETVAR 11 |
| 3409 | #define DUK_OP_BNOT 12 |
| 3410 | #define DUK_OP_LNOT 13 |
| 3411 | #define DUK_OP_UNM 14 |
| 3412 | #define DUK_OP_UNP 15 |
| 3413 | #define DUK_OP_EQ 16 |
| 3414 | #define DUK_OP_EQ_RR 16 |
| 3415 | #define DUK_OP_EQ_CR 17 |
| 3416 | #define DUK_OP_EQ_RC 18 |
| 3417 | #define DUK_OP_EQ_CC 19 |
| 3418 | #define DUK_OP_NEQ 20 |
| 3419 | #define DUK_OP_NEQ_RR 20 |
| 3420 | #define DUK_OP_NEQ_CR 21 |
| 3421 | #define DUK_OP_NEQ_RC 22 |
| 3422 | #define DUK_OP_NEQ_CC 23 |
| 3423 | #define DUK_OP_SEQ 24 |
| 3424 | #define DUK_OP_SEQ_RR 24 |
| 3425 | #define DUK_OP_SEQ_CR 25 |
| 3426 | #define DUK_OP_SEQ_RC 26 |
| 3427 | #define DUK_OP_SEQ_CC 27 |
| 3428 | #define DUK_OP_SNEQ 28 |
| 3429 | #define DUK_OP_SNEQ_RR 28 |
| 3430 | #define DUK_OP_SNEQ_CR 29 |
| 3431 | #define DUK_OP_SNEQ_RC 30 |
| 3432 | #define DUK_OP_SNEQ_CC 31 |
| 3433 | #define DUK_OP_GT 32 |
| 3434 | #define DUK_OP_GT_RR 32 |
| 3435 | #define DUK_OP_GT_CR 33 |
| 3436 | #define DUK_OP_GT_RC 34 |
| 3437 | #define DUK_OP_GT_CC 35 |
| 3438 | #define DUK_OP_GE 36 |
| 3439 | #define DUK_OP_GE_RR 36 |
| 3440 | #define DUK_OP_GE_CR 37 |
| 3441 | #define DUK_OP_GE_RC 38 |
| 3442 | #define DUK_OP_GE_CC 39 |
| 3443 | #define DUK_OP_LT 40 |
| 3444 | #define DUK_OP_LT_RR 40 |
| 3445 | #define DUK_OP_LT_CR 41 |
| 3446 | #define DUK_OP_LT_RC 42 |
| 3447 | #define DUK_OP_LT_CC 43 |
| 3448 | #define DUK_OP_LE 44 |
| 3449 | #define DUK_OP_LE_RR 44 |
| 3450 | #define DUK_OP_LE_CR 45 |
| 3451 | #define DUK_OP_LE_RC 46 |
| 3452 | #define DUK_OP_LE_CC 47 |
| 3453 | #define DUK_OP_IFTRUE 48 |
| 3454 | #define DUK_OP_IFTRUE_R 48 |
| 3455 | #define DUK_OP_IFTRUE_C 49 |
| 3456 | #define DUK_OP_IFFALSE 50 |
| 3457 | #define DUK_OP_IFFALSE_R 50 |
| 3458 | #define DUK_OP_IFFALSE_C 51 |
| 3459 | #define DUK_OP_ADD 52 |
| 3460 | #define DUK_OP_ADD_RR 52 |
| 3461 | #define DUK_OP_ADD_CR 53 |
| 3462 | #define DUK_OP_ADD_RC 54 |
| 3463 | #define DUK_OP_ADD_CC 55 |
| 3464 | #define DUK_OP_SUB 56 |
| 3465 | #define DUK_OP_SUB_RR 56 |
| 3466 | #define DUK_OP_SUB_CR 57 |
| 3467 | #define DUK_OP_SUB_RC 58 |
| 3468 | #define DUK_OP_SUB_CC 59 |
| 3469 | #define DUK_OP_MUL 60 |
| 3470 | #define DUK_OP_MUL_RR 60 |
| 3471 | #define DUK_OP_MUL_CR 61 |
| 3472 | #define DUK_OP_MUL_RC 62 |
| 3473 | #define DUK_OP_MUL_CC 63 |
| 3474 | #define DUK_OP_DIV 64 |
| 3475 | #define DUK_OP_DIV_RR 64 |
| 3476 | #define DUK_OP_DIV_CR 65 |
| 3477 | #define DUK_OP_DIV_RC 66 |
| 3478 | #define DUK_OP_DIV_CC 67 |
| 3479 | #define DUK_OP_MOD 68 |
| 3480 | #define DUK_OP_MOD_RR 68 |
| 3481 | #define DUK_OP_MOD_CR 69 |
| 3482 | #define DUK_OP_MOD_RC 70 |
| 3483 | #define DUK_OP_MOD_CC 71 |
| 3484 | #define DUK_OP_EXP 72 |
| 3485 | #define DUK_OP_EXP_RR 72 |
| 3486 | #define DUK_OP_EXP_CR 73 |
| 3487 | #define DUK_OP_EXP_RC 74 |
| 3488 | #define DUK_OP_EXP_CC 75 |
| 3489 | #define DUK_OP_BAND 76 |
| 3490 | #define DUK_OP_BAND_RR 76 |
| 3491 | #define DUK_OP_BAND_CR 77 |
| 3492 | #define DUK_OP_BAND_RC 78 |
| 3493 | #define DUK_OP_BAND_CC 79 |
| 3494 | #define DUK_OP_BOR 80 |
| 3495 | #define DUK_OP_BOR_RR 80 |
| 3496 | #define DUK_OP_BOR_CR 81 |
| 3497 | #define DUK_OP_BOR_RC 82 |
| 3498 | #define DUK_OP_BOR_CC 83 |
| 3499 | #define DUK_OP_BXOR 84 |
| 3500 | #define DUK_OP_BXOR_RR 84 |
| 3501 | #define DUK_OP_BXOR_CR 85 |
| 3502 | #define DUK_OP_BXOR_RC 86 |
| 3503 | #define DUK_OP_BXOR_CC 87 |
| 3504 | #define DUK_OP_BASL 88 |
| 3505 | #define DUK_OP_BASL_RR 88 |
| 3506 | #define DUK_OP_BASL_CR 89 |
| 3507 | #define DUK_OP_BASL_RC 90 |
| 3508 | #define DUK_OP_BASL_CC 91 |
| 3509 | #define DUK_OP_BLSR 92 |
| 3510 | #define DUK_OP_BLSR_RR 92 |
| 3511 | #define DUK_OP_BLSR_CR 93 |
| 3512 | #define DUK_OP_BLSR_RC 94 |
| 3513 | #define DUK_OP_BLSR_CC 95 |
| 3514 | #define DUK_OP_BASR 96 |
| 3515 | #define DUK_OP_BASR_RR 96 |
| 3516 | #define DUK_OP_BASR_CR 97 |
| 3517 | #define DUK_OP_BASR_RC 98 |
| 3518 | #define DUK_OP_BASR_CC 99 |
| 3519 | #define DUK_OP_INSTOF 100 |
| 3520 | #define DUK_OP_INSTOF_RR 100 |
| 3521 | #define DUK_OP_INSTOF_CR 101 |
| 3522 | #define DUK_OP_INSTOF_RC 102 |
| 3523 | #define DUK_OP_INSTOF_CC 103 |
| 3524 | #define DUK_OP_IN 104 |
| 3525 | #define DUK_OP_IN_RR 104 |
| 3526 | #define DUK_OP_IN_CR 105 |
| 3527 | #define DUK_OP_IN_RC 106 |
| 3528 | #define DUK_OP_IN_CC 107 |
| 3529 | #define DUK_OP_GETPROP 108 |
| 3530 | #define DUK_OP_GETPROP_RR 108 |
| 3531 | #define DUK_OP_GETPROP_CR 109 |
| 3532 | #define DUK_OP_GETPROP_RC 110 |
| 3533 | #define DUK_OP_GETPROP_CC 111 |
| 3534 | #define DUK_OP_PUTPROP 112 |
| 3535 | #define DUK_OP_PUTPROP_RR 112 |
| 3536 | #define DUK_OP_PUTPROP_CR 113 |
| 3537 | #define DUK_OP_PUTPROP_RC 114 |
| 3538 | #define DUK_OP_PUTPROP_CC 115 |
| 3539 | #define DUK_OP_DELPROP 116 |
| 3540 | #define DUK_OP_DELPROP_RR 116 |
| 3541 | #define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */ |
| 3542 | #define DUK_OP_DELPROP_RC 118 |
| 3543 | #define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */ |
| 3544 | #define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */ |
| 3545 | #define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */ |
| 3546 | #define DUK_OP_POSTINCR 122 |
| 3547 | #define DUK_OP_POSTDECR 123 |
| 3548 | #define DUK_OP_PREINCV 124 |
| 3549 | #define DUK_OP_PREDECV 125 |
| 3550 | #define DUK_OP_POSTINCV 126 |
| 3551 | #define DUK_OP_POSTDECV 127 |
| 3552 | #define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */ |
| 3553 | #define DUK_OP_PREINCP_RR 128 |
| 3554 | #define DUK_OP_PREINCP_CR 129 |
| 3555 | #define DUK_OP_PREINCP_RC 130 |
| 3556 | #define DUK_OP_PREINCP_CC 131 |
| 3557 | #define DUK_OP_PREDECP 132 |
| 3558 | #define DUK_OP_PREDECP_RR 132 |
| 3559 | #define DUK_OP_PREDECP_CR 133 |
| 3560 | #define DUK_OP_PREDECP_RC 134 |
| 3561 | #define DUK_OP_PREDECP_CC 135 |
| 3562 | #define DUK_OP_POSTINCP 136 |
| 3563 | #define DUK_OP_POSTINCP_RR 136 |
| 3564 | #define DUK_OP_POSTINCP_CR 137 |
| 3565 | #define DUK_OP_POSTINCP_RC 138 |
| 3566 | #define DUK_OP_POSTINCP_CC 139 |
| 3567 | #define DUK_OP_POSTDECP 140 |
| 3568 | #define DUK_OP_POSTDECP_RR 140 |
| 3569 | #define DUK_OP_POSTDECP_CR 141 |
| 3570 | #define DUK_OP_POSTDECP_RC 142 |
| 3571 | #define DUK_OP_POSTDECP_CC 143 |
| 3572 | #define DUK_OP_DECLVAR 144 |
| 3573 | #define DUK_OP_DECLVAR_RR 144 |
| 3574 | #define DUK_OP_DECLVAR_CR 145 |
| 3575 | #define DUK_OP_DECLVAR_RC 146 |
| 3576 | #define DUK_OP_DECLVAR_CC 147 |
| 3577 | #define DUK_OP_REGEXP 148 |
| 3578 | #define DUK_OP_REGEXP_RR 148 |
| 3579 | #define DUK_OP_REGEXP_CR 149 |
| 3580 | #define DUK_OP_REGEXP_RC 150 |
| 3581 | #define DUK_OP_REGEXP_CC 151 |
| 3582 | #define DUK_OP_CLOSURE 152 |
| 3583 | #define DUK_OP_TYPEOF 153 |
| 3584 | #define DUK_OP_TYPEOFID 154 |
| 3585 | #define DUK_OP_PUTVAR 155 |
| 3586 | #define DUK_OP_DELVAR 156 |
| 3587 | #define DUK_OP_RETREG 157 |
| 3588 | #define DUK_OP_RETUNDEF 158 |
| 3589 | #define DUK_OP_RETCONST 159 |
| 3590 | #define DUK_OP_RETCONSTN 160 /* return const without incref (e.g. number) */ |
| 3591 | #define DUK_OP_LABEL 161 |
| 3592 | #define DUK_OP_ENDLABEL 162 |
| 3593 | #define DUK_OP_BREAK 163 |
| 3594 | #define DUK_OP_CONTINUE 164 |
| 3595 | #define DUK_OP_TRYCATCH 165 |
| 3596 | #define DUK_OP_ENDTRY 166 |
| 3597 | #define DUK_OP_ENDCATCH 167 |
| 3598 | #define DUK_OP_ENDFIN 168 |
| 3599 | #define DUK_OP_THROW 169 |
| 3600 | #define DUK_OP_INVLHS 170 |
| 3601 | #define DUK_OP_CSREG 171 |
| 3602 | #define DUK_OP_CSVAR 172 |
| 3603 | #define DUK_OP_CSVAR_RR 172 |
| 3604 | #define DUK_OP_CSVAR_CR 173 |
| 3605 | #define DUK_OP_CSVAR_RC 174 |
| 3606 | #define DUK_OP_CSVAR_CC 175 |
| 3607 | #define DUK_OP_CALL0 176 /* DUK_OP_CALL0 & 0x0F must be zero. */ |
| 3608 | #define DUK_OP_CALL1 177 |
| 3609 | #define DUK_OP_CALL2 178 |
| 3610 | #define DUK_OP_CALL3 179 |
| 3611 | #define DUK_OP_CALL4 180 |
| 3612 | #define DUK_OP_CALL5 181 |
| 3613 | #define DUK_OP_CALL6 182 |
| 3614 | #define DUK_OP_CALL7 183 |
| 3615 | #define DUK_OP_CALL8 184 |
| 3616 | #define DUK_OP_CALL9 185 |
| 3617 | #define DUK_OP_CALL10 186 |
| 3618 | #define DUK_OP_CALL11 187 |
| 3619 | #define DUK_OP_CALL12 188 |
| 3620 | #define DUK_OP_CALL13 189 |
| 3621 | #define DUK_OP_CALL14 190 |
| 3622 | #define DUK_OP_CALL15 191 |
| 3623 | #define DUK_OP_NEWOBJ 192 |
| 3624 | #define DUK_OP_NEWARR 193 |
| 3625 | #define DUK_OP_MPUTOBJ 194 |
| 3626 | #define DUK_OP_MPUTOBJI 195 |
| 3627 | #define DUK_OP_INITSET 196 |
| 3628 | #define DUK_OP_INITGET 197 |
| 3629 | #define DUK_OP_MPUTARR 198 |
| 3630 | #define DUK_OP_MPUTARRI 199 |
| 3631 | #define DUK_OP_SETALEN 200 |
| 3632 | #define DUK_OP_INITENUM 201 |
| 3633 | #define DUK_OP_NEXTENUM 202 |
| 3634 | #define DUK_OP_NEWTARGET 203 |
| 3635 | #define DUK_OP_DEBUGGER 204 |
| 3636 | #define DUK_OP_NOP 205 |
| 3637 | #define DUK_OP_INVALID 206 |
| 3638 | #define DUK_OP_UNUSED207 207 |
| 3639 | #define DUK_OP_GETPROPC 208 |
| 3640 | #define DUK_OP_GETPROPC_RR 208 |
| 3641 | #define DUK_OP_GETPROPC_CR 209 |
| 3642 | #define DUK_OP_GETPROPC_RC 210 |
| 3643 | #define DUK_OP_GETPROPC_CC 211 |
| 3644 | #define DUK_OP_UNUSED212 212 |
| 3645 | #define DUK_OP_UNUSED213 213 |
| 3646 | #define DUK_OP_UNUSED214 214 |
| 3647 | #define DUK_OP_UNUSED215 215 |
| 3648 | #define DUK_OP_UNUSED216 216 |
| 3649 | #define DUK_OP_UNUSED217 217 |
| 3650 | #define DUK_OP_UNUSED218 218 |
| 3651 | #define DUK_OP_UNUSED219 219 |
| 3652 | #define DUK_OP_UNUSED220 220 |
| 3653 | #define DUK_OP_UNUSED221 221 |
| 3654 | #define DUK_OP_UNUSED222 222 |
| 3655 | #define DUK_OP_UNUSED223 223 |
| 3656 | #define DUK_OP_UNUSED224 224 |
| 3657 | #define DUK_OP_UNUSED225 225 |
| 3658 | #define DUK_OP_UNUSED226 226 |
| 3659 | #define DUK_OP_UNUSED227 227 |
| 3660 | #define DUK_OP_UNUSED228 228 |
| 3661 | #define DUK_OP_UNUSED229 229 |
| 3662 | #define DUK_OP_UNUSED230 230 |
| 3663 | #define DUK_OP_UNUSED231 231 |
| 3664 | #define DUK_OP_UNUSED232 232 |
| 3665 | #define DUK_OP_UNUSED233 233 |
| 3666 | #define DUK_OP_UNUSED234 234 |
| 3667 | #define DUK_OP_UNUSED235 235 |
| 3668 | #define DUK_OP_UNUSED236 236 |
| 3669 | #define DUK_OP_UNUSED237 237 |
| 3670 | #define DUK_OP_UNUSED238 238 |
| 3671 | #define DUK_OP_UNUSED239 239 |
| 3672 | #define DUK_OP_UNUSED240 240 |
| 3673 | #define DUK_OP_UNUSED241 241 |
| 3674 | #define DUK_OP_UNUSED242 242 |
| 3675 | #define DUK_OP_UNUSED243 243 |
| 3676 | #define DUK_OP_UNUSED244 244 |
| 3677 | #define DUK_OP_UNUSED245 245 |
| 3678 | #define DUK_OP_UNUSED246 246 |
| 3679 | #define DUK_OP_UNUSED247 247 |
| 3680 | #define DUK_OP_UNUSED248 248 |
| 3681 | #define DUK_OP_UNUSED249 249 |
| 3682 | #define DUK_OP_UNUSED250 250 |
| 3683 | #define DUK_OP_UNUSED251 251 |
| 3684 | #define DUK_OP_UNUSED252 252 |
| 3685 | #define DUK_OP_UNUSED253 253 |
| 3686 | #define DUK_OP_UNUSED254 254 |
| 3687 | #define DUK_OP_UNUSED255 255 |
| 3688 | #define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */ |
| 3689 | |
| 3690 | /* XXX: Allocate flags from opcode field? Would take 16 opcode slots |
| 3691 | * but avoids shuffling in more cases. Maybe not worth it. |
| 3692 | */ |
| 3693 | /* DUK_OP_TRYCATCH flags in A. */ |
| 3694 | #define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1U << 0) |
| 3695 | #define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1U << 1) |
| 3696 | #define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1U << 2) |
| 3697 | #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1U << 3) |
| 3698 | |
| 3699 | /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags |
| 3700 | * (DUK_PROPDESC_FLAG_XXX). |
| 3701 | */ |
| 3702 | #define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1U << 4) /* function declaration */ |
| 3703 | |
| 3704 | /* DUK_OP_CALLn flags, part of opcode field. Three lowest bits must match |
| 3705 | * DUK_CALL_FLAG_xxx directly. |
| 3706 | */ |
| 3707 | #define DUK_BC_CALL_FLAG_TAILCALL (1U << 0) |
| 3708 | #define DUK_BC_CALL_FLAG_CONSTRUCT (1U << 1) |
| 3709 | #define DUK_BC_CALL_FLAG_CALLED_AS_EVAL (1U << 2) |
| 3710 | #define DUK_BC_CALL_FLAG_INDIRECT (1U << 3) |
| 3711 | |
| 3712 | /* Misc constants and helper macros. */ |
| 3713 | #define DUK_BC_LDINT_BIAS (1L << 15) |
| 3714 | #define DUK_BC_LDINTX_SHIFT 16 |
| 3715 | #define DUK_BC_JUMP_BIAS (1L << 23) |
| 3716 | |
| 3717 | #endif /* DUK_JS_BYTECODE_H_INCLUDED */ |
| 3718 | /* #include duk_lexer.h */ |
| 3719 | #line 1 "duk_lexer.h" |
| 3720 | /* |
| 3721 | * Lexer defines. |
| 3722 | */ |
| 3723 | |
| 3724 | #if !defined(DUK_LEXER_H_INCLUDED) |
| 3725 | #define DUK_LEXER_H_INCLUDED |
| 3726 | |
| 3727 | typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct); |
| 3728 | |
| 3729 | /* |
| 3730 | * A token is interpreted as any possible production of InputElementDiv |
| 3731 | * and InputElementRegExp, see E5 Section 7 in its entirety. Note that |
| 3732 | * the E5 "Token" production does not cover all actual tokens of the |
| 3733 | * language (which is explicitly stated in the specification, Section 7.5). |
| 3734 | * Null and boolean literals are defined as part of both ReservedWord |
| 3735 | * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here, |
| 3736 | * null and boolean values have literal tokens, and are not reserved |
| 3737 | * words. |
| 3738 | * |
| 3739 | * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER. |
| 3740 | * The number tokens always have a non-negative value. The unary minus |
| 3741 | * operator in "-1.0" is optimized during compilation to yield a single |
| 3742 | * negative constant. |
| 3743 | * |
| 3744 | * Token numbering is free except that reserved words are required to be |
| 3745 | * in a continuous range and in a particular order. See genstrings.py. |
| 3746 | */ |
| 3747 | |
| 3748 | #define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx)) |
| 3749 | |
| 3750 | #define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt)) |
| 3751 | |
| 3752 | #define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt)) |
| 3753 | |
| 3754 | /* Currently 6 characters of lookup are actually needed (duk_lexer.c). */ |
| 3755 | #define DUK_LEXER_WINDOW_SIZE 6 |
| 3756 | #if defined(DUK_USE_LEXER_SLIDING_WINDOW) |
| 3757 | #define DUK_LEXER_BUFFER_SIZE 64 |
| 3758 | #endif |
| 3759 | |
| 3760 | #define DUK_TOK_MINVAL 0 |
| 3761 | |
| 3762 | /* returned after EOF (infinite amount) */ |
| 3763 | #define DUK_TOK_EOF 0 |
| 3764 | |
| 3765 | /* identifier names (E5 Section 7.6) */ |
| 3766 | #define DUK_TOK_IDENTIFIER 1 |
| 3767 | |
| 3768 | /* reserved words: keywords */ |
| 3769 | #define DUK_TOK_START_RESERVED 2 |
| 3770 | #define DUK_TOK_BREAK 2 |
| 3771 | #define DUK_TOK_CASE 3 |
| 3772 | #define DUK_TOK_CATCH 4 |
| 3773 | #define DUK_TOK_CONTINUE 5 |
| 3774 | #define DUK_TOK_DEBUGGER 6 |
| 3775 | #define DUK_TOK_DEFAULT 7 |
| 3776 | #define DUK_TOK_DELETE 8 |
| 3777 | #define DUK_TOK_DO 9 |
| 3778 | #define DUK_TOK_ELSE 10 |
| 3779 | #define DUK_TOK_FINALLY 11 |
| 3780 | #define DUK_TOK_FOR 12 |
| 3781 | #define DUK_TOK_FUNCTION 13 |
| 3782 | #define DUK_TOK_IF 14 |
| 3783 | #define DUK_TOK_IN 15 |
| 3784 | #define DUK_TOK_INSTANCEOF 16 |
| 3785 | #define DUK_TOK_NEW 17 |
| 3786 | #define DUK_TOK_RETURN 18 |
| 3787 | #define DUK_TOK_SWITCH 19 |
| 3788 | #define DUK_TOK_THIS 20 |
| 3789 | #define DUK_TOK_THROW 21 |
| 3790 | #define DUK_TOK_TRY 22 |
| 3791 | #define DUK_TOK_TYPEOF 23 |
| 3792 | #define DUK_TOK_VAR 24 |
| 3793 | #define DUK_TOK_CONST 25 |
| 3794 | #define DUK_TOK_VOID 26 |
| 3795 | #define DUK_TOK_WHILE 27 |
| 3796 | #define DUK_TOK_WITH 28 |
| 3797 | |
| 3798 | /* reserved words: future reserved words */ |
| 3799 | #define DUK_TOK_CLASS 29 |
| 3800 | #define DUK_TOK_ENUM 30 |
| 3801 | #define DUK_TOK_EXPORT 31 |
| 3802 | #define DUK_TOK_EXTENDS 32 |
| 3803 | #define DUK_TOK_IMPORT 33 |
| 3804 | #define DUK_TOK_SUPER 34 |
| 3805 | |
| 3806 | /* "null", "true", and "false" are always reserved words. |
| 3807 | * Note that "get" and "set" are not! |
| 3808 | */ |
| 3809 | #define DUK_TOK_NULL 35 |
| 3810 | #define DUK_TOK_TRUE 36 |
| 3811 | #define DUK_TOK_FALSE 37 |
| 3812 | |
| 3813 | /* reserved words: additional future reserved words in strict mode */ |
| 3814 | #define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */ |
| 3815 | #define DUK_TOK_IMPLEMENTS 38 |
| 3816 | #define DUK_TOK_INTERFACE 39 |
| 3817 | #define DUK_TOK_LET 40 |
| 3818 | #define DUK_TOK_PACKAGE 41 |
| 3819 | #define DUK_TOK_PRIVATE 42 |
| 3820 | #define DUK_TOK_PROTECTED 43 |
| 3821 | #define DUK_TOK_PUBLIC 44 |
| 3822 | #define DUK_TOK_STATIC 45 |
| 3823 | #define DUK_TOK_YIELD 46 |
| 3824 | |
| 3825 | #define DUK_TOK_END_RESERVED 47 /* exclusive */ |
| 3826 | |
| 3827 | /* "get" and "set" are tokens but NOT ReservedWords. They are currently |
| 3828 | * parsed and identifiers and these defines are actually now unused. |
| 3829 | */ |
| 3830 | #define DUK_TOK_GET 47 |
| 3831 | #define DUK_TOK_SET 48 |
| 3832 | |
| 3833 | /* punctuators (unlike the spec, also includes "/" and "/=") */ |
| 3834 | #define DUK_TOK_LCURLY 49 |
| 3835 | #define DUK_TOK_RCURLY 50 |
| 3836 | #define DUK_TOK_LBRACKET 51 |
| 3837 | #define DUK_TOK_RBRACKET 52 |
| 3838 | #define DUK_TOK_LPAREN 53 |
| 3839 | #define DUK_TOK_RPAREN 54 |
| 3840 | #define DUK_TOK_PERIOD 55 |
| 3841 | #define DUK_TOK_SEMICOLON 56 |
| 3842 | #define DUK_TOK_COMMA 57 |
| 3843 | #define DUK_TOK_LT 58 |
| 3844 | #define DUK_TOK_GT 59 |
| 3845 | #define DUK_TOK_LE 60 |
| 3846 | #define DUK_TOK_GE 61 |
| 3847 | #define DUK_TOK_EQ 62 |
| 3848 | #define DUK_TOK_NEQ 63 |
| 3849 | #define DUK_TOK_SEQ 64 |
| 3850 | #define DUK_TOK_SNEQ 65 |
| 3851 | #define DUK_TOK_ADD 66 |
| 3852 | #define DUK_TOK_SUB 67 |
| 3853 | #define DUK_TOK_MUL 68 |
| 3854 | #define DUK_TOK_DIV 69 |
| 3855 | #define DUK_TOK_MOD 70 |
| 3856 | #define DUK_TOK_EXP 71 |
| 3857 | #define DUK_TOK_INCREMENT 72 |
| 3858 | #define DUK_TOK_DECREMENT 73 |
| 3859 | #define DUK_TOK_ALSHIFT 74 /* named "arithmetic" because result is signed */ |
| 3860 | #define DUK_TOK_ARSHIFT 75 |
| 3861 | #define DUK_TOK_RSHIFT 76 |
| 3862 | #define DUK_TOK_BAND 77 |
| 3863 | #define DUK_TOK_BOR 78 |
| 3864 | #define DUK_TOK_BXOR 79 |
| 3865 | #define DUK_TOK_LNOT 80 |
| 3866 | #define DUK_TOK_BNOT 81 |
| 3867 | #define DUK_TOK_LAND 82 |
| 3868 | #define DUK_TOK_LOR 83 |
| 3869 | #define DUK_TOK_QUESTION 84 |
| 3870 | #define DUK_TOK_COLON 85 |
| 3871 | #define DUK_TOK_EQUALSIGN 86 |
| 3872 | #define DUK_TOK_ADD_EQ 87 |
| 3873 | #define DUK_TOK_SUB_EQ 88 |
| 3874 | #define DUK_TOK_MUL_EQ 89 |
| 3875 | #define DUK_TOK_DIV_EQ 90 |
| 3876 | #define DUK_TOK_MOD_EQ 91 |
| 3877 | #define DUK_TOK_EXP_EQ 92 |
| 3878 | #define DUK_TOK_ALSHIFT_EQ 93 |
| 3879 | #define DUK_TOK_ARSHIFT_EQ 94 |
| 3880 | #define DUK_TOK_RSHIFT_EQ 95 |
| 3881 | #define DUK_TOK_BAND_EQ 96 |
| 3882 | #define DUK_TOK_BOR_EQ 97 |
| 3883 | #define DUK_TOK_BXOR_EQ 98 |
| 3884 | |
| 3885 | /* literals (E5 Section 7.8), except null, true, false, which are treated |
| 3886 | * like reserved words (above). |
| 3887 | */ |
| 3888 | #define DUK_TOK_NUMBER 99 |
| 3889 | #define DUK_TOK_STRING 100 |
| 3890 | #define DUK_TOK_REGEXP 101 |
| 3891 | |
| 3892 | #define DUK_TOK_MAXVAL 101 /* inclusive */ |
| 3893 | |
| 3894 | #define DUK_TOK_INVALID DUK_SMALL_UINT_MAX |
| 3895 | |
| 3896 | /* Convert heap string index to a token (reserved words) */ |
| 3897 | #define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED) |
| 3898 | |
| 3899 | /* Sanity check */ |
| 3900 | #if (DUK_TOK_MAXVAL > 255) |
| 3901 | #error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits |
| 3902 | #endif |
| 3903 | |
| 3904 | /* Sanity checks for string and token defines */ |
| 3905 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK) |
| 3906 | #error mismatch in token defines |
| 3907 | #endif |
| 3908 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE) |
| 3909 | #error mismatch in token defines |
| 3910 | #endif |
| 3911 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH) |
| 3912 | #error mismatch in token defines |
| 3913 | #endif |
| 3914 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE) |
| 3915 | #error mismatch in token defines |
| 3916 | #endif |
| 3917 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER) |
| 3918 | #error mismatch in token defines |
| 3919 | #endif |
| 3920 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT) |
| 3921 | #error mismatch in token defines |
| 3922 | #endif |
| 3923 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE) |
| 3924 | #error mismatch in token defines |
| 3925 | #endif |
| 3926 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO) |
| 3927 | #error mismatch in token defines |
| 3928 | #endif |
| 3929 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE) |
| 3930 | #error mismatch in token defines |
| 3931 | #endif |
| 3932 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY) |
| 3933 | #error mismatch in token defines |
| 3934 | #endif |
| 3935 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR) |
| 3936 | #error mismatch in token defines |
| 3937 | #endif |
| 3938 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION) |
| 3939 | #error mismatch in token defines |
| 3940 | #endif |
| 3941 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF) |
| 3942 | #error mismatch in token defines |
| 3943 | #endif |
| 3944 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN) |
| 3945 | #error mismatch in token defines |
| 3946 | #endif |
| 3947 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF) |
| 3948 | #error mismatch in token defines |
| 3949 | #endif |
| 3950 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW) |
| 3951 | #error mismatch in token defines |
| 3952 | #endif |
| 3953 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN) |
| 3954 | #error mismatch in token defines |
| 3955 | #endif |
| 3956 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH) |
| 3957 | #error mismatch in token defines |
| 3958 | #endif |
| 3959 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS) |
| 3960 | #error mismatch in token defines |
| 3961 | #endif |
| 3962 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW) |
| 3963 | #error mismatch in token defines |
| 3964 | #endif |
| 3965 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY) |
| 3966 | #error mismatch in token defines |
| 3967 | #endif |
| 3968 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF) |
| 3969 | #error mismatch in token defines |
| 3970 | #endif |
| 3971 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR) |
| 3972 | #error mismatch in token defines |
| 3973 | #endif |
| 3974 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID) |
| 3975 | #error mismatch in token defines |
| 3976 | #endif |
| 3977 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE) |
| 3978 | #error mismatch in token defines |
| 3979 | #endif |
| 3980 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH) |
| 3981 | #error mismatch in token defines |
| 3982 | #endif |
| 3983 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS) |
| 3984 | #error mismatch in token defines |
| 3985 | #endif |
| 3986 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST) |
| 3987 | #error mismatch in token defines |
| 3988 | #endif |
| 3989 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM) |
| 3990 | #error mismatch in token defines |
| 3991 | #endif |
| 3992 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT) |
| 3993 | #error mismatch in token defines |
| 3994 | #endif |
| 3995 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS) |
| 3996 | #error mismatch in token defines |
| 3997 | #endif |
| 3998 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT) |
| 3999 | #error mismatch in token defines |
| 4000 | #endif |
| 4001 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER) |
| 4002 | #error mismatch in token defines |
| 4003 | #endif |
| 4004 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL) |
| 4005 | #error mismatch in token defines |
| 4006 | #endif |
| 4007 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE) |
| 4008 | #error mismatch in token defines |
| 4009 | #endif |
| 4010 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE) |
| 4011 | #error mismatch in token defines |
| 4012 | #endif |
| 4013 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS) |
| 4014 | #error mismatch in token defines |
| 4015 | #endif |
| 4016 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE) |
| 4017 | #error mismatch in token defines |
| 4018 | #endif |
| 4019 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET) |
| 4020 | #error mismatch in token defines |
| 4021 | #endif |
| 4022 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE) |
| 4023 | #error mismatch in token defines |
| 4024 | #endif |
| 4025 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE) |
| 4026 | #error mismatch in token defines |
| 4027 | #endif |
| 4028 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED) |
| 4029 | #error mismatch in token defines |
| 4030 | #endif |
| 4031 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC) |
| 4032 | #error mismatch in token defines |
| 4033 | #endif |
| 4034 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC) |
| 4035 | #error mismatch in token defines |
| 4036 | #endif |
| 4037 | #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD) |
| 4038 | #error mismatch in token defines |
| 4039 | #endif |
| 4040 | |
| 4041 | /* Regexp tokens */ |
| 4042 | #define DUK_RETOK_EOF 0 |
| 4043 | #define DUK_RETOK_DISJUNCTION 1 |
| 4044 | #define DUK_RETOK_QUANTIFIER 2 |
| 4045 | #define DUK_RETOK_ASSERT_START 3 |
| 4046 | #define DUK_RETOK_ASSERT_END 4 |
| 4047 | #define DUK_RETOK_ASSERT_WORD_BOUNDARY 5 |
| 4048 | #define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6 |
| 4049 | #define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7 |
| 4050 | #define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8 |
| 4051 | #define DUK_RETOK_ATOM_PERIOD 9 |
| 4052 | #define DUK_RETOK_ATOM_CHAR 10 |
| 4053 | #define DUK_RETOK_ATOM_DIGIT 11 /* assumptions in regexp compiler */ |
| 4054 | #define DUK_RETOK_ATOM_NOT_DIGIT 12 /* -""- */ |
| 4055 | #define DUK_RETOK_ATOM_WHITE 13 /* -""- */ |
| 4056 | #define DUK_RETOK_ATOM_NOT_WHITE 14 /* -""- */ |
| 4057 | #define DUK_RETOK_ATOM_WORD_CHAR 15 /* -""- */ |
| 4058 | #define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 /* -""- */ |
| 4059 | #define DUK_RETOK_ATOM_BACKREFERENCE 17 |
| 4060 | #define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18 |
| 4061 | #define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19 |
| 4062 | #define DUK_RETOK_ATOM_START_CHARCLASS 20 |
| 4063 | #define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21 |
| 4064 | #define DUK_RETOK_ATOM_END_GROUP 22 |
| 4065 | |
| 4066 | /* Constants for duk_lexer_ctx.buf. */ |
| 4067 | #define DUK_LEXER_TEMP_BUF_LIMIT 256 |
| 4068 | |
| 4069 | /* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack. |
| 4070 | * Some fields (like num, str1, str2) are only valid for specific token types and may have |
| 4071 | * stale values otherwise. |
| 4072 | */ |
| 4073 | struct duk_token { |
| 4074 | duk_small_uint_t t; /* token type (with reserved word identification) */ |
| 4075 | duk_small_uint_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */ |
| 4076 | duk_double_t num; /* numeric value of token */ |
| 4077 | duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */ |
| 4078 | duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */ |
| 4079 | duk_size_t start_offset; /* start byte offset of token in lexer input */ |
| 4080 | duk_int_t start_line; /* start line of token (first char) */ |
| 4081 | duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */ |
| 4082 | duk_bool_t lineterm; /* token was preceded by a lineterm */ |
| 4083 | duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */ |
| 4084 | }; |
| 4085 | |
| 4086 | #define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL) |
| 4087 | |
| 4088 | /* A regexp token value. */ |
| 4089 | struct duk_re_token { |
| 4090 | duk_small_uint_t t; /* token type */ |
| 4091 | duk_small_uint_t greedy; |
| 4092 | duk_uint32_t num; /* numeric value (character, count) */ |
| 4093 | duk_uint32_t qmin; |
| 4094 | duk_uint32_t qmax; |
| 4095 | }; |
| 4096 | |
| 4097 | /* A structure for 'snapshotting' a point for rewinding */ |
| 4098 | struct duk_lexer_point { |
| 4099 | duk_size_t offset; |
| 4100 | duk_int_t line; |
| 4101 | }; |
| 4102 | |
| 4103 | /* Lexer codepoint with additional info like offset/line number */ |
| 4104 | struct duk_lexer_codepoint { |
| 4105 | duk_codepoint_t codepoint; |
| 4106 | duk_size_t offset; |
| 4107 | duk_int_t line; |
| 4108 | }; |
| 4109 | |
| 4110 | /* Lexer context. Same context is used for ECMAScript and Regexp parsing. */ |
| 4111 | struct duk_lexer_ctx { |
| 4112 | #if defined(DUK_USE_LEXER_SLIDING_WINDOW) |
| 4113 | duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */ |
| 4114 | duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE]; |
| 4115 | #else |
| 4116 | duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */ |
| 4117 | #endif |
| 4118 | |
| 4119 | duk_hthread *thr; /* thread; minimizes argument passing */ |
| 4120 | |
| 4121 | const duk_uint8_t *input; /* input string (may be a user pointer) */ |
| 4122 | duk_size_t input_length; /* input byte length */ |
| 4123 | duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */ |
| 4124 | duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */ |
| 4125 | |
| 4126 | duk_idx_t slot1_idx; /* valstack slot for 1st token value */ |
| 4127 | duk_idx_t slot2_idx; /* valstack slot for 2nd token value */ |
| 4128 | duk_idx_t buf_idx; /* valstack slot for temp buffer */ |
| 4129 | duk_hbuffer_dynamic *buf; /* temp accumulation buffer */ |
| 4130 | duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */ |
| 4131 | |
| 4132 | duk_int_t token_count; /* number of tokens parsed */ |
| 4133 | duk_int_t token_limit; /* maximum token count before error (sanity backstop) */ |
| 4134 | |
| 4135 | duk_small_uint_t flags; /* lexer flags, use compiler flag defines for now */ |
| 4136 | }; |
| 4137 | |
| 4138 | /* |
| 4139 | * Prototypes |
| 4140 | */ |
| 4141 | |
| 4142 | DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx); |
| 4143 | |
| 4144 | DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt); |
| 4145 | DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt); |
| 4146 | |
| 4147 | DUK_INTERNAL_DECL |
| 4148 | void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, |
| 4149 | duk_token *out_token, |
| 4150 | duk_bool_t strict_mode, |
| 4151 | duk_bool_t regexp_mode); |
| 4152 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 4153 | DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token); |
| 4154 | DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata); |
| 4155 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 4156 | |
| 4157 | #endif /* DUK_LEXER_H_INCLUDED */ |
| 4158 | /* #include duk_js_compiler.h */ |
| 4159 | #line 1 "duk_js_compiler.h" |
| 4160 | /* |
| 4161 | * ECMAScript compiler. |
| 4162 | */ |
| 4163 | |
| 4164 | #if !defined(DUK_JS_COMPILER_H_INCLUDED) |
| 4165 | #define DUK_JS_COMPILER_H_INCLUDED |
| 4166 | |
| 4167 | /* ECMAScript compiler limits */ |
| 4168 | #define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */ |
| 4169 | |
| 4170 | /* maximum loopcount for peephole optimization */ |
| 4171 | #define DUK_COMPILER_PEEPHOLE_MAXITER 3 |
| 4172 | |
| 4173 | /* maximum bytecode length in instructions */ |
| 4174 | #define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */ |
| 4175 | |
| 4176 | /* |
| 4177 | * Compiler intermediate values |
| 4178 | * |
| 4179 | * Intermediate values describe either plain values (e.g. strings or |
| 4180 | * numbers) or binary operations which have not yet been coerced into |
| 4181 | * either a left-hand-side or right-hand-side role (e.g. object property). |
| 4182 | */ |
| 4183 | |
| 4184 | #define DUK_IVAL_NONE 0 /* no value */ |
| 4185 | #define DUK_IVAL_PLAIN 1 /* register, constant, or value */ |
| 4186 | #define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */ |
| 4187 | #define DUK_IVAL_PROP 3 /* property access */ |
| 4188 | #define DUK_IVAL_VAR 4 /* variable access */ |
| 4189 | |
| 4190 | #define DUK_ISPEC_NONE 0 /* no value */ |
| 4191 | #define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */ |
| 4192 | #define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */ |
| 4193 | |
| 4194 | /* Bit mask which indicates that a regconst is a constant instead of a register. |
| 4195 | * Chosen so that when a regconst is cast to duk_int32_t, all consts are |
| 4196 | * negative values. |
| 4197 | */ |
| 4198 | #define DUK_REGCONST_CONST_MARKER DUK_INT32_MIN /* = -0x80000000 */ |
| 4199 | |
| 4200 | /* Type to represent a reg/const reference during compilation, with <0 |
| 4201 | * indicating a constant. Some call sites also use -1 to indicate 'none'. |
| 4202 | */ |
| 4203 | typedef duk_int32_t duk_regconst_t; |
| 4204 | |
| 4205 | typedef struct { |
| 4206 | duk_small_uint_t t; /* DUK_ISPEC_XXX */ |
| 4207 | duk_regconst_t regconst; |
| 4208 | duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */ |
| 4209 | } duk_ispec; |
| 4210 | |
| 4211 | typedef struct { |
| 4212 | /* |
| 4213 | * PLAIN: x1 |
| 4214 | * ARITH: x1 <op> x2 |
| 4215 | * PROP: x1.x2 |
| 4216 | * VAR: x1 (name) |
| 4217 | */ |
| 4218 | |
| 4219 | /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */ |
| 4220 | duk_small_uint_t t; /* DUK_IVAL_XXX */ |
| 4221 | duk_small_uint_t op; /* bytecode opcode for binary ops */ |
| 4222 | duk_ispec x1; |
| 4223 | duk_ispec x2; |
| 4224 | } duk_ivalue; |
| 4225 | |
| 4226 | /* |
| 4227 | * Bytecode instruction representation during compilation |
| 4228 | * |
| 4229 | * Contains the actual instruction and (optionally) debug info. |
| 4230 | */ |
| 4231 | |
| 4232 | struct duk_compiler_instr { |
| 4233 | duk_instr_t ins; |
| 4234 | #if defined(DUK_USE_PC2LINE) |
| 4235 | duk_uint32_t line; |
| 4236 | #endif |
| 4237 | }; |
| 4238 | |
| 4239 | /* |
| 4240 | * Compiler state |
| 4241 | */ |
| 4242 | |
| 4243 | #define DUK_LABEL_FLAG_ALLOW_BREAK (1U << 0) |
| 4244 | #define DUK_LABEL_FLAG_ALLOW_CONTINUE (1U << 1) |
| 4245 | |
| 4246 | #define DUK_DECL_TYPE_VAR 0 |
| 4247 | #define DUK_DECL_TYPE_FUNC 1 |
| 4248 | |
| 4249 | /* XXX: optimize to 16 bytes */ |
| 4250 | typedef struct { |
| 4251 | duk_small_uint_t flags; |
| 4252 | duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */ |
| 4253 | duk_hstring *h_label; /* borrowed label name */ |
| 4254 | duk_int_t catch_depth; /* catch depth at point of definition */ |
| 4255 | duk_int_t pc_label; /* pc of label statement: |
| 4256 | * pc+1: break jump site |
| 4257 | * pc+2: continue jump site |
| 4258 | */ |
| 4259 | |
| 4260 | /* Fast jumps (which avoid longjmp) jump directly to the jump sites |
| 4261 | * which are always known even while the iteration/switch statement |
| 4262 | * is still being parsed. A final peephole pass "straightens out" |
| 4263 | * the jumps. |
| 4264 | */ |
| 4265 | } duk_labelinfo; |
| 4266 | |
| 4267 | /* Compiling state of one function, eventually converted to duk_hcompfunc */ |
| 4268 | struct duk_compiler_func { |
| 4269 | /* These pointers are at the start of the struct so that they pack |
| 4270 | * nicely. Mixing pointers and integer values is bad on some |
| 4271 | * platforms (e.g. if int is 32 bits and pointers are 64 bits). |
| 4272 | */ |
| 4273 | |
| 4274 | duk_bufwriter_ctx bw_code; /* bufwriter for code */ |
| 4275 | |
| 4276 | duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */ |
| 4277 | /* h_code: held in bw_code */ |
| 4278 | duk_hobject *h_consts; /* array */ |
| 4279 | duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2] |
| 4280 | * offset/line points to closing brace to allow skipping on pass 2 |
| 4281 | */ |
| 4282 | duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ] |
| 4283 | * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars) |
| 4284 | * record function and variable declarations in pass 1 |
| 4285 | */ |
| 4286 | duk_hobject *h_labelnames; /* array of active label names */ |
| 4287 | duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */ |
| 4288 | duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */ |
| 4289 | duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */ |
| 4290 | |
| 4291 | /* Value stack indices for tracking objects. */ |
| 4292 | /* code_idx: not needed */ |
| 4293 | duk_idx_t consts_idx; |
| 4294 | duk_idx_t funcs_idx; |
| 4295 | duk_idx_t decls_idx; |
| 4296 | duk_idx_t labelnames_idx; |
| 4297 | duk_idx_t labelinfos_idx; |
| 4298 | duk_idx_t argnames_idx; |
| 4299 | duk_idx_t varmap_idx; |
| 4300 | |
| 4301 | /* Temp reg handling. */ |
| 4302 | duk_regconst_t temp_first; /* first register that is a temporary (below: variables) */ |
| 4303 | duk_regconst_t temp_next; /* next temporary register to allocate */ |
| 4304 | duk_regconst_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */ |
| 4305 | |
| 4306 | /* Shuffle registers if large number of regs/consts. */ |
| 4307 | duk_regconst_t shuffle1; |
| 4308 | duk_regconst_t shuffle2; |
| 4309 | duk_regconst_t shuffle3; |
| 4310 | |
| 4311 | /* Stats for current expression being parsed. */ |
| 4312 | duk_int_t nud_count; |
| 4313 | duk_int_t led_count; |
| 4314 | duk_int_t paren_level; /* parenthesis count, 0 = top level */ |
| 4315 | duk_bool_t expr_lhs; /* expression is left-hand-side compatible */ |
| 4316 | duk_bool_t allow_in; /* current paren level allows 'in' token */ |
| 4317 | |
| 4318 | /* Misc. */ |
| 4319 | duk_int_t stmt_next; /* statement id allocation (running counter) */ |
| 4320 | duk_int_t label_next; /* label id allocation (running counter) */ |
| 4321 | duk_int_t catch_depth; /* catch stack depth */ |
| 4322 | duk_int_t with_depth; /* with stack depth (affects identifier lookups) */ |
| 4323 | duk_int_t fnum_next; /* inner function numbering */ |
| 4324 | duk_int_t num_formals; /* number of formal arguments */ |
| 4325 | duk_regconst_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */ |
| 4326 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 4327 | duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */ |
| 4328 | duk_int_t max_line; |
| 4329 | #endif |
| 4330 | |
| 4331 | /* Status booleans. */ |
| 4332 | duk_uint8_t is_function; /* is an actual function (not global/eval code) */ |
| 4333 | duk_uint8_t is_eval; /* is eval code */ |
| 4334 | duk_uint8_t is_global; /* is global code */ |
| 4335 | duk_uint8_t is_namebinding; /* needs a name binding */ |
| 4336 | duk_uint8_t is_constructable; /* result is constructable */ |
| 4337 | duk_uint8_t is_setget; /* is a setter/getter */ |
| 4338 | duk_uint8_t is_strict; /* function is strict */ |
| 4339 | duk_uint8_t is_notail; /* function must not be tail called */ |
| 4340 | duk_uint8_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */ |
| 4341 | duk_uint8_t in_scanning; /* parsing in "scanning" phase (first pass) */ |
| 4342 | duk_uint8_t may_direct_eval; /* function may call direct eval */ |
| 4343 | duk_uint8_t id_access_arguments; /* function refers to 'arguments' identifier */ |
| 4344 | duk_uint8_t id_access_slow; /* function makes one or more slow path accesses that won't match own static variables */ |
| 4345 | duk_uint8_t id_access_slow_own; /* function makes one or more slow path accesses that may match own static variables */ |
| 4346 | duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */ |
| 4347 | duk_uint8_t needs_shuffle; /* function needs shuffle registers */ |
| 4348 | duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */ |
| 4349 | duk_uint8_t allow_regexp_in_adv; /* allow RegExp literal on next advance() call */ |
| 4350 | }; |
| 4351 | |
| 4352 | struct duk_compiler_ctx { |
| 4353 | duk_hthread *thr; |
| 4354 | |
| 4355 | /* filename being compiled (ends up in functions' '_filename' property) */ |
| 4356 | duk_hstring *h_filename; /* borrowed reference */ |
| 4357 | |
| 4358 | /* lexing (tokenization) state (contains two valstack slot indices) */ |
| 4359 | duk_lexer_ctx lex; |
| 4360 | |
| 4361 | /* current and previous token for parsing */ |
| 4362 | duk_token prev_token; |
| 4363 | duk_token curr_token; |
| 4364 | duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */ |
| 4365 | duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */ |
| 4366 | duk_idx_t tok21_idx; /* prev_token slot1 */ |
| 4367 | duk_idx_t tok22_idx; /* prev_token slot2 */ |
| 4368 | |
| 4369 | /* recursion limit */ |
| 4370 | duk_int_t recursion_depth; |
| 4371 | duk_int_t recursion_limit; |
| 4372 | |
| 4373 | /* code emission temporary */ |
| 4374 | duk_int_t emit_jumpslot_pc; |
| 4375 | |
| 4376 | /* current function being compiled (embedded instead of pointer for more compact access) */ |
| 4377 | duk_compiler_func curr_func; |
| 4378 | }; |
| 4379 | |
| 4380 | /* |
| 4381 | * Prototypes |
| 4382 | */ |
| 4383 | |
| 4384 | DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags); |
| 4385 | |
| 4386 | #endif /* DUK_JS_COMPILER_H_INCLUDED */ |
| 4387 | /* #include duk_regexp.h */ |
| 4388 | #line 1 "duk_regexp.h" |
| 4389 | /* |
| 4390 | * Regular expression structs, constants, and bytecode defines. |
| 4391 | */ |
| 4392 | |
| 4393 | #if !defined(DUK_REGEXP_H_INCLUDED) |
| 4394 | #define DUK_REGEXP_H_INCLUDED |
| 4395 | |
| 4396 | /* maximum bytecode copies for {n,m} quantifiers */ |
| 4397 | #define DUK_RE_MAX_ATOM_COPIES 1000 |
| 4398 | |
| 4399 | /* regexp compilation limits */ |
| 4400 | #define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */ |
| 4401 | |
| 4402 | /* regexp execution limits */ |
| 4403 | #define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */ |
| 4404 | |
| 4405 | /* regexp opcodes */ |
| 4406 | #define DUK_REOP_MATCH 1 |
| 4407 | #define DUK_REOP_CHAR 2 |
| 4408 | #define DUK_REOP_PERIOD 3 |
| 4409 | #define DUK_REOP_RANGES 4 |
| 4410 | #define DUK_REOP_INVRANGES 5 |
| 4411 | #define DUK_REOP_JUMP 6 |
| 4412 | #define DUK_REOP_SPLIT1 7 |
| 4413 | #define DUK_REOP_SPLIT2 8 |
| 4414 | #define DUK_REOP_SQMINIMAL 9 |
| 4415 | #define DUK_REOP_SQGREEDY 10 |
| 4416 | #define DUK_REOP_SAVE 11 |
| 4417 | #define DUK_REOP_WIPERANGE 12 |
| 4418 | #define DUK_REOP_LOOKPOS 13 |
| 4419 | #define DUK_REOP_LOOKNEG 14 |
| 4420 | #define DUK_REOP_BACKREFERENCE 15 |
| 4421 | #define DUK_REOP_ASSERT_START 16 |
| 4422 | #define DUK_REOP_ASSERT_END 17 |
| 4423 | #define DUK_REOP_ASSERT_WORD_BOUNDARY 18 |
| 4424 | #define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19 |
| 4425 | |
| 4426 | /* flags */ |
| 4427 | #define DUK_RE_FLAG_GLOBAL (1U << 0) |
| 4428 | #define DUK_RE_FLAG_IGNORE_CASE (1U << 1) |
| 4429 | #define DUK_RE_FLAG_MULTILINE (1U << 2) |
| 4430 | |
| 4431 | struct duk_re_matcher_ctx { |
| 4432 | duk_hthread *thr; |
| 4433 | |
| 4434 | duk_uint32_t re_flags; |
| 4435 | const duk_uint8_t *input; |
| 4436 | const duk_uint8_t *input_end; |
| 4437 | const duk_uint8_t *bytecode; |
| 4438 | const duk_uint8_t *bytecode_end; |
| 4439 | const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */ |
| 4440 | duk_uint32_t nsaved; |
| 4441 | duk_uint32_t recursion_depth; |
| 4442 | duk_uint32_t recursion_limit; |
| 4443 | duk_uint32_t steps_count; |
| 4444 | duk_uint32_t steps_limit; |
| 4445 | }; |
| 4446 | |
| 4447 | struct duk_re_compiler_ctx { |
| 4448 | duk_hthread *thr; |
| 4449 | |
| 4450 | duk_uint32_t re_flags; |
| 4451 | duk_lexer_ctx lex; |
| 4452 | duk_re_token curr_token; |
| 4453 | duk_bufwriter_ctx bw; |
| 4454 | duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */ |
| 4455 | duk_uint32_t highest_backref; |
| 4456 | duk_uint32_t recursion_depth; |
| 4457 | duk_uint32_t recursion_limit; |
| 4458 | duk_uint32_t nranges; /* internal temporary value, used for char classes */ |
| 4459 | }; |
| 4460 | |
| 4461 | /* |
| 4462 | * Prototypes |
| 4463 | */ |
| 4464 | |
| 4465 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 4466 | DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr); |
| 4467 | DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr); |
| 4468 | DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr); |
| 4469 | DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */ |
| 4470 | #endif |
| 4471 | |
| 4472 | #endif /* DUK_REGEXP_H_INCLUDED */ |
| 4473 | /* #include duk_heaphdr.h */ |
| 4474 | #line 1 "duk_heaphdr.h" |
| 4475 | /* |
| 4476 | * Heap header definition and assorted macros, including ref counting. |
| 4477 | * Access all fields through the accessor macros. |
| 4478 | */ |
| 4479 | |
| 4480 | #if !defined(DUK_HEAPHDR_H_INCLUDED) |
| 4481 | #define DUK_HEAPHDR_H_INCLUDED |
| 4482 | |
| 4483 | /* |
| 4484 | * Common heap header |
| 4485 | * |
| 4486 | * All heap objects share the same flags and refcount fields. Objects other |
| 4487 | * than strings also need to have a single or double linked list pointers |
| 4488 | * for insertion into the "heap allocated" list. Strings have single linked |
| 4489 | * list pointers for string table chaining. |
| 4490 | * |
| 4491 | * Technically, 'h_refcount' must be wide enough to guarantee that it cannot |
| 4492 | * wrap; otherwise objects might be freed incorrectly after wrapping. The |
| 4493 | * default refcount field is 32 bits even on 64-bit systems: while that's in |
| 4494 | * theory incorrect, the Duktape heap needs to be larger than 64GB for the |
| 4495 | * count to actually wrap (assuming 16-byte duk_tvals). This is very unlikely |
| 4496 | * to ever be an issue, but if it is, disabling DUK_USE_REFCOUNT32 causes |
| 4497 | * Duktape to use size_t for refcounts which should always be safe. |
| 4498 | * |
| 4499 | * Heap header size on 32-bit platforms: 8 bytes without reference counting, |
| 4500 | * 16 bytes with reference counting. |
| 4501 | * |
| 4502 | * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not |
| 4503 | * defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined() |
| 4504 | * around them. |
| 4505 | */ |
| 4506 | |
| 4507 | /* XXX: macro for shared header fields (avoids some padding issues) */ |
| 4508 | |
| 4509 | struct duk_heaphdr { |
| 4510 | duk_uint32_t h_flags; |
| 4511 | |
| 4512 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 4513 | #if defined(DUK_USE_ASSERTIONS) |
| 4514 | /* When assertions enabled, used by mark-and-sweep for refcount |
| 4515 | * validation. Largest reasonable type; also detects overflows. |
| 4516 | */ |
| 4517 | duk_size_t h_assert_refcount; |
| 4518 | #endif |
| 4519 | #if defined(DUK_USE_REFCOUNT16) |
| 4520 | duk_uint16_t h_refcount; |
| 4521 | #elif defined(DUK_USE_REFCOUNT32) |
| 4522 | duk_uint32_t h_refcount; |
| 4523 | #else |
| 4524 | duk_size_t h_refcount; |
| 4525 | #endif |
| 4526 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 4527 | |
| 4528 | #if defined(DUK_USE_HEAPPTR16) |
| 4529 | duk_uint16_t h_next16; |
| 4530 | #else |
| 4531 | duk_heaphdr *h_next; |
| 4532 | #endif |
| 4533 | |
| 4534 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 4535 | /* refcounting requires direct heap frees, which in turn requires a dual linked heap */ |
| 4536 | #if defined(DUK_USE_HEAPPTR16) |
| 4537 | duk_uint16_t h_prev16; |
| 4538 | #else |
| 4539 | duk_heaphdr *h_prev; |
| 4540 | #endif |
| 4541 | #endif |
| 4542 | |
| 4543 | /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the |
| 4544 | * struct won't align nicely to 4 bytes. This 16-bit extra field |
| 4545 | * is added to make the alignment clean; the field can be used by |
| 4546 | * heap objects when 16-bit packing is used. This field is now |
| 4547 | * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be |
| 4548 | * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP; |
| 4549 | * this only matter to low memory environments anyway. |
| 4550 | */ |
| 4551 | #if defined(DUK_USE_HEAPPTR16) |
| 4552 | duk_uint16_t h_extra16; |
| 4553 | #endif |
| 4554 | }; |
| 4555 | |
| 4556 | struct duk_heaphdr_string { |
| 4557 | /* 16 bits would be enough for shared heaphdr flags and duk_hstring |
| 4558 | * flags. The initial parts of duk_heaphdr_string and duk_heaphdr |
| 4559 | * must match so changing the flags field size here would be quite |
| 4560 | * awkward. However, to minimize struct size, we can pack at least |
| 4561 | * 16 bits of duk_hstring data into the flags field. |
| 4562 | */ |
| 4563 | duk_uint32_t h_flags; |
| 4564 | |
| 4565 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 4566 | #if defined(DUK_USE_ASSERTIONS) |
| 4567 | /* When assertions enabled, used by mark-and-sweep for refcount |
| 4568 | * validation. Largest reasonable type; also detects overflows. |
| 4569 | */ |
| 4570 | duk_size_t h_assert_refcount; |
| 4571 | #endif |
| 4572 | #if defined(DUK_USE_REFCOUNT16) |
| 4573 | duk_uint16_t h_refcount; |
| 4574 | duk_uint16_t h_strextra16; /* round out to 8 bytes */ |
| 4575 | #elif defined(DUK_USE_REFCOUNT32) |
| 4576 | duk_uint32_t h_refcount; |
| 4577 | #else |
| 4578 | duk_size_t h_refcount; |
| 4579 | #endif |
| 4580 | #else |
| 4581 | duk_uint16_t h_strextra16; |
| 4582 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 4583 | |
| 4584 | duk_hstring *h_next; |
| 4585 | /* No 'h_prev' pointer for strings. */ |
| 4586 | }; |
| 4587 | |
| 4588 | #define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL |
| 4589 | #define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK) |
| 4590 | |
| 4591 | /* 2 bits for heap type */ |
| 4592 | #define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */ |
| 4593 | #define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */ |
| 4594 | |
| 4595 | #define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n)) |
| 4596 | #define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n)) |
| 4597 | #define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n))) |
| 4598 | #define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n))) |
| 4599 | |
| 4600 | #define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */ |
| 4601 | #define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */ |
| 4602 | #define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */ |
| 4603 | #define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */ |
| 4604 | #define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */ |
| 4605 | |
| 4606 | #define DUK_HTYPE_MIN 0 |
| 4607 | #define DUK_HTYPE_STRING 0 |
| 4608 | #define DUK_HTYPE_OBJECT 1 |
| 4609 | #define DUK_HTYPE_BUFFER 2 |
| 4610 | #define DUK_HTYPE_MAX 2 |
| 4611 | |
| 4612 | #if defined(DUK_USE_HEAPPTR16) |
| 4613 | #define DUK_HEAPHDR_GET_NEXT(heap,h) \ |
| 4614 | ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16)) |
| 4615 | #define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \ |
| 4616 | (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \ |
| 4617 | } while (0) |
| 4618 | #else |
| 4619 | #define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next) |
| 4620 | #define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \ |
| 4621 | (h)->h_next = (val); \ |
| 4622 | } while (0) |
| 4623 | #endif |
| 4624 | |
| 4625 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 4626 | #if defined(DUK_USE_HEAPPTR16) |
| 4627 | #define DUK_HEAPHDR_GET_PREV(heap,h) \ |
| 4628 | ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16)) |
| 4629 | #define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \ |
| 4630 | (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \ |
| 4631 | } while (0) |
| 4632 | #else |
| 4633 | #define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev) |
| 4634 | #define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \ |
| 4635 | (h)->h_prev = (val); \ |
| 4636 | } while (0) |
| 4637 | #endif |
| 4638 | #endif |
| 4639 | |
| 4640 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 4641 | #define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount) |
| 4642 | #define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \ |
| 4643 | (h)->h_refcount = (val); \ |
| 4644 | DUK_ASSERT((h)->h_refcount == (val)); /* No truncation. */ \ |
| 4645 | } while (0) |
| 4646 | #define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */ |
| 4647 | #define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */ |
| 4648 | #else |
| 4649 | /* refcount macros not defined without refcounting, caller must #if defined() now */ |
| 4650 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 4651 | |
| 4652 | /* |
| 4653 | * Note: type is treated as a field separate from flags, so some masking is |
| 4654 | * involved in the macros below. |
| 4655 | */ |
| 4656 | |
| 4657 | #define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags) |
| 4658 | #define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \ |
| 4659 | (h)->h_flags = (val); } \ |
| 4660 | } |
| 4661 | #define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK) |
| 4662 | #define DUK_HEAPHDR_SET_FLAGS(h,val) do { \ |
| 4663 | (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \ |
| 4664 | } while (0) |
| 4665 | #define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK) |
| 4666 | #define DUK_HEAPHDR_SET_TYPE(h,val) do { \ |
| 4667 | (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \ |
| 4668 | } while (0) |
| 4669 | |
| 4670 | /* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero |
| 4671 | * and the comparison is unsigned, it's always true and generates warnings. |
| 4672 | */ |
| 4673 | #define DUK_HEAPHDR_HTYPE_VALID(h) ( \ |
| 4674 | DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \ |
| 4675 | ) |
| 4676 | |
| 4677 | #define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \ |
| 4678 | (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \ |
| 4679 | ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \ |
| 4680 | } while (0) |
| 4681 | |
| 4682 | #define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \ |
| 4683 | DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \ |
| 4684 | (h)->h_flags |= (bits); \ |
| 4685 | } while (0) |
| 4686 | |
| 4687 | #define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \ |
| 4688 | DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \ |
| 4689 | (h)->h_flags &= ~((bits)); \ |
| 4690 | } while (0) |
| 4691 | |
| 4692 | #define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0) |
| 4693 | |
| 4694 | #define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) |
| 4695 | #define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) |
| 4696 | #define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE) |
| 4697 | |
| 4698 | #define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) |
| 4699 | #define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) |
| 4700 | #define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT) |
| 4701 | |
| 4702 | #define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) |
| 4703 | #define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) |
| 4704 | #define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE) |
| 4705 | |
| 4706 | #define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) |
| 4707 | #define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) |
| 4708 | #define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED) |
| 4709 | |
| 4710 | #define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) |
| 4711 | #define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) |
| 4712 | #define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY) |
| 4713 | |
| 4714 | /* get or set a range of flags; m=first bit number, n=number of bits */ |
| 4715 | #define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL)) |
| 4716 | |
| 4717 | #define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \ |
| 4718 | (h)->h_flags = \ |
| 4719 | ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \ |
| 4720 | | ((v) << (m)); \ |
| 4721 | } while (0) |
| 4722 | |
| 4723 | /* init pointer fields to null */ |
| 4724 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 4725 | #define DUK_HEAPHDR_INIT_NULLS(h) do { \ |
| 4726 | DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \ |
| 4727 | DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \ |
| 4728 | } while (0) |
| 4729 | #else |
| 4730 | #define DUK_HEAPHDR_INIT_NULLS(h) do { \ |
| 4731 | DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \ |
| 4732 | } while (0) |
| 4733 | #endif |
| 4734 | |
| 4735 | #define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \ |
| 4736 | (h)->h_next = NULL; \ |
| 4737 | } while (0) |
| 4738 | |
| 4739 | /* |
| 4740 | * Type tests |
| 4741 | */ |
| 4742 | |
| 4743 | /* Take advantage of the fact that for DUK_HTYPE_xxx numbers the lowest bit |
| 4744 | * is only set for DUK_HTYPE_OBJECT (= 1). |
| 4745 | */ |
| 4746 | #if 0 |
| 4747 | #define DUK_HEAPHDR_IS_OBJECT(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT) |
| 4748 | #endif |
| 4749 | #define DUK_HEAPHDR_IS_OBJECT(h) ((h)->h_flags & 0x01UL) |
| 4750 | #define DUK_HEAPHDR_IS_STRING(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING) |
| 4751 | #define DUK_HEAPHDR_IS_BUFFER(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER) |
| 4752 | |
| 4753 | /* |
| 4754 | * Assert helpers |
| 4755 | */ |
| 4756 | |
| 4757 | /* Check that prev/next links are consistent: if e.g. h->prev is != NULL, |
| 4758 | * h->prev->next should point back to h. |
| 4759 | */ |
| 4760 | #if defined(DUK_USE_ASSERTIONS) |
| 4761 | DUK_INTERNAL_DECL void duk_heaphdr_assert_valid_subclassed(duk_heaphdr *h); |
| 4762 | DUK_INTERNAL_DECL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h); |
| 4763 | DUK_INTERNAL_DECL void duk_heaphdr_assert_valid(duk_heaphdr *h); |
| 4764 | #define DUK_HEAPHDR_ASSERT_LINKS(heap,h) do { duk_heaphdr_assert_links((heap), (h)); } while (0) |
| 4765 | #define DUK_HEAPHDR_ASSERT_VALID(h) do { duk_heaphdr_assert_valid((h)); } while (0) |
| 4766 | #else |
| 4767 | #define DUK_HEAPHDR_ASSERT_LINKS(heap,h) do {} while (0) |
| 4768 | #define DUK_HEAPHDR_ASSERT_VALID(h) do {} while (0) |
| 4769 | #endif |
| 4770 | |
| 4771 | #endif /* DUK_HEAPHDR_H_INCLUDED */ |
| 4772 | /* #include duk_refcount.h */ |
| 4773 | #line 1 "duk_refcount.h" |
| 4774 | /* |
| 4775 | * Reference counting helper macros. The macros take a thread argument |
| 4776 | * and must thus always be executed in a specific thread context. The |
| 4777 | * thread argument is not really needed anymore: DECREF can operate with |
| 4778 | * a heap pointer only, and INCREF needs neither. |
| 4779 | */ |
| 4780 | |
| 4781 | #if !defined(DUK_REFCOUNT_H_INCLUDED) |
| 4782 | #define DUK_REFCOUNT_H_INCLUDED |
| 4783 | |
| 4784 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 4785 | |
| 4786 | #if defined(DUK_USE_ROM_OBJECTS) |
| 4787 | /* With ROM objects "needs refcount update" is true when the value is |
| 4788 | * heap allocated and is not a ROM object. |
| 4789 | */ |
| 4790 | /* XXX: double evaluation for 'tv' argument. */ |
| 4791 | #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \ |
| 4792 | (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv)))) |
| 4793 | #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h))) |
| 4794 | #else /* DUK_USE_ROM_OBJECTS */ |
| 4795 | /* Without ROM objects "needs refcount update" == is heap allocated. */ |
| 4796 | #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv)) |
| 4797 | #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1 |
| 4798 | #endif /* DUK_USE_ROM_OBJECTS */ |
| 4799 | |
| 4800 | /* Fast variants, inline refcount operations except for refzero handling. |
| 4801 | * Can be used explicitly when speed is always more important than size. |
| 4802 | * For a good compiler and a single file build, these are basically the |
| 4803 | * same as a forced inline. |
| 4804 | */ |
| 4805 | #define DUK_TVAL_INCREF_FAST(thr,tv) do { \ |
| 4806 | duk_tval *duk__tv = (tv); \ |
| 4807 | DUK_ASSERT(duk__tv != NULL); \ |
| 4808 | if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ |
| 4809 | duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ |
| 4810 | DUK_ASSERT(duk__h != NULL); \ |
| 4811 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ |
| 4812 | DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ |
| 4813 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ |
| 4814 | } \ |
| 4815 | } while (0) |
| 4816 | #define DUK_TVAL_DECREF_FAST(thr,tv) do { \ |
| 4817 | duk_tval *duk__tv = (tv); \ |
| 4818 | DUK_ASSERT(duk__tv != NULL); \ |
| 4819 | if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ |
| 4820 | duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ |
| 4821 | DUK_ASSERT(duk__h != NULL); \ |
| 4822 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ |
| 4823 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ |
| 4824 | if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ |
| 4825 | duk_heaphdr_refzero((thr), duk__h); \ |
| 4826 | } \ |
| 4827 | } \ |
| 4828 | } while (0) |
| 4829 | #define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \ |
| 4830 | duk_tval *duk__tv = (tv); \ |
| 4831 | DUK_ASSERT(duk__tv != NULL); \ |
| 4832 | if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \ |
| 4833 | duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \ |
| 4834 | DUK_ASSERT(duk__h != NULL); \ |
| 4835 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ |
| 4836 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ |
| 4837 | if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ |
| 4838 | duk_heaphdr_refzero_norz((thr), duk__h); \ |
| 4839 | } \ |
| 4840 | } \ |
| 4841 | } while (0) |
| 4842 | #define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \ |
| 4843 | duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ |
| 4844 | DUK_ASSERT(duk__h != NULL); \ |
| 4845 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ |
| 4846 | if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ |
| 4847 | DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \ |
| 4848 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0); /* No wrapping. */ \ |
| 4849 | } \ |
| 4850 | } while (0) |
| 4851 | #define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \ |
| 4852 | duk_heaphdr *duk__h = (duk_heaphdr *) (h); \ |
| 4853 | DUK_ASSERT(duk__h != NULL); \ |
| 4854 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \ |
| 4855 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \ |
| 4856 | if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \ |
| 4857 | if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \ |
| 4858 | (rzcall)((thr), (rzcast) duk__h); \ |
| 4859 | } \ |
| 4860 | } \ |
| 4861 | } while (0) |
| 4862 | #define DUK_HEAPHDR_DECREF_FAST(thr,h) \ |
| 4863 | DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) |
| 4864 | #define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \ |
| 4865 | DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) |
| 4866 | |
| 4867 | /* Slow variants, call to a helper to reduce code size. |
| 4868 | * Can be used explicitly when size is always more important than speed. |
| 4869 | */ |
| 4870 | #define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0) |
| 4871 | #define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0) |
| 4872 | #define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0) |
| 4873 | #define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) |
| 4874 | #define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) |
| 4875 | #define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) |
| 4876 | #define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) |
| 4877 | #define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) |
| 4878 | #define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) |
| 4879 | #define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) |
| 4880 | #define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) |
| 4881 | #define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) |
| 4882 | #define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0) |
| 4883 | #define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0) |
| 4884 | #define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0) |
| 4885 | |
| 4886 | /* Default variants. Selection depends on speed/size preference. |
| 4887 | * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary |
| 4888 | * is about +1kB for _FAST variants. |
| 4889 | */ |
| 4890 | #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| 4891 | /* XXX: It would be nice to specialize for specific duk_hobject subtypes |
| 4892 | * but current refzero queue handling prevents that. |
| 4893 | */ |
| 4894 | #define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv)) |
| 4895 | #define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv)) |
| 4896 | #define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv)) |
| 4897 | #define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h)) |
| 4898 | #define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *) |
| 4899 | #define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *) |
| 4900 | #define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) |
| 4901 | #define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) |
| 4902 | #define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */ |
| 4903 | #define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) |
| 4904 | #define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) |
| 4905 | #define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) |
| 4906 | #define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) |
| 4907 | #define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) |
| 4908 | #define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */ |
| 4909 | #define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4910 | #define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) |
| 4911 | #define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) |
| 4912 | #define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4913 | #define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) |
| 4914 | #define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) |
| 4915 | #define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4916 | #define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) |
| 4917 | #define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) |
| 4918 | #define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4919 | #define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *) |
| 4920 | #define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *) |
| 4921 | #else |
| 4922 | #define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv)) |
| 4923 | #define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv)) |
| 4924 | #define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv)) |
| 4925 | #define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h)) |
| 4926 | #define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h)) |
| 4927 | #define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h)) |
| 4928 | #define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) |
| 4929 | #define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h)) |
| 4930 | #define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h)) |
| 4931 | #define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) |
| 4932 | #define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h)) |
| 4933 | #define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h)) |
| 4934 | #define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h)) |
| 4935 | #define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h)) |
| 4936 | #define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h)) |
| 4937 | #define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4938 | #define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4939 | #define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4940 | #define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4941 | #define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4942 | #define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4943 | #define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4944 | #define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4945 | #define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4946 | #define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj) |
| 4947 | #define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4948 | #define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj) |
| 4949 | #endif |
| 4950 | |
| 4951 | /* Convenience for some situations; the above macros don't allow NULLs |
| 4952 | * for performance reasons. Macros cover only actually needed cases. |
| 4953 | */ |
| 4954 | #define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \ |
| 4955 | if ((h) != NULL) { \ |
| 4956 | DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \ |
| 4957 | } \ |
| 4958 | } while (0) |
| 4959 | #define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \ |
| 4960 | if ((h) != NULL) { \ |
| 4961 | DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \ |
| 4962 | } \ |
| 4963 | } while (0) |
| 4964 | #define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \ |
| 4965 | if ((h) != NULL) { \ |
| 4966 | DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \ |
| 4967 | } \ |
| 4968 | } while (0) |
| 4969 | #define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \ |
| 4970 | if ((h) != NULL) { \ |
| 4971 | DUK_HOBJECT_INCREF((thr), (h)); \ |
| 4972 | } \ |
| 4973 | } while (0) |
| 4974 | #define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \ |
| 4975 | if ((h) != NULL) { \ |
| 4976 | DUK_HOBJECT_DECREF((thr), (h)); \ |
| 4977 | } \ |
| 4978 | } while (0) |
| 4979 | #define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \ |
| 4980 | if ((h) != NULL) { \ |
| 4981 | DUK_HOBJECT_DECREF_NORZ((thr), (h)); \ |
| 4982 | } \ |
| 4983 | } while (0) |
| 4984 | #define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \ |
| 4985 | if ((h) != NULL) { \ |
| 4986 | DUK_HBUFFER_INCREF((thr), (h)); \ |
| 4987 | } \ |
| 4988 | } while (0) |
| 4989 | #define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \ |
| 4990 | if ((h) != NULL) { \ |
| 4991 | DUK_HBUFFER_DECREF((thr), (h)); \ |
| 4992 | } \ |
| 4993 | } while (0) |
| 4994 | #define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \ |
| 4995 | if ((h) != NULL) { \ |
| 4996 | DUK_HBUFFER_DECREF_NORZ((thr), (h)); \ |
| 4997 | } \ |
| 4998 | } while (0) |
| 4999 | #define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \ |
| 5000 | if ((h) != NULL) { \ |
| 5001 | DUK_HTHREAD_INCREF((thr), (h)); \ |
| 5002 | } \ |
| 5003 | } while (0) |
| 5004 | #define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \ |
| 5005 | if ((h) != NULL) { \ |
| 5006 | DUK_HTHREAD_DECREF((thr), (h)); \ |
| 5007 | } \ |
| 5008 | } while (0) |
| 5009 | #define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \ |
| 5010 | if ((h) != NULL) { \ |
| 5011 | DUK_HTHREAD_DECREF_NORZ((thr), (h)); \ |
| 5012 | } \ |
| 5013 | } while (0) |
| 5014 | |
| 5015 | /* Called after one or more DECREF NORZ calls to handle pending side effects. |
| 5016 | * At present DECREF NORZ does freeing inline but doesn't execute finalizers, |
| 5017 | * so these macros check for pending finalizers and execute them. The FAST |
| 5018 | * variant is performance critical. |
| 5019 | */ |
| 5020 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 5021 | #define DUK_REFZERO_CHECK_FAST(thr) do { \ |
| 5022 | duk_refzero_check_fast((thr)); \ |
| 5023 | } while (0) |
| 5024 | #define DUK_REFZERO_CHECK_SLOW(thr) do { \ |
| 5025 | duk_refzero_check_slow((thr)); \ |
| 5026 | } while (0) |
| 5027 | #else /* DUK_USE_FINALIZER_SUPPORT */ |
| 5028 | #define DUK_REFZERO_CHECK_FAST(thr) do { } while (0) |
| 5029 | #define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0) |
| 5030 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 5031 | |
| 5032 | /* |
| 5033 | * Macros to set a duk_tval and update refcount of the target (decref the |
| 5034 | * old value and incref the new value if necessary). This is both performance |
| 5035 | * and footprint critical; any changes made should be measured for size/speed. |
| 5036 | */ |
| 5037 | |
| 5038 | #define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5039 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5040 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5041 | DUK_TVAL_SET_UNDEFINED(tv__dst); \ |
| 5042 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5043 | } while (0) |
| 5044 | |
| 5045 | #define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \ |
| 5046 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5047 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5048 | DUK_TVAL_SET_UNDEFINED(tv__dst); \ |
| 5049 | DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \ |
| 5050 | } while (0) |
| 5051 | |
| 5052 | #define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5053 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5054 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5055 | DUK_TVAL_SET_UNUSED(tv__dst); \ |
| 5056 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5057 | } while (0) |
| 5058 | |
| 5059 | #define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5060 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5061 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5062 | DUK_TVAL_SET_NULL(tv__dst); \ |
| 5063 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5064 | } while (0) |
| 5065 | |
| 5066 | #define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5067 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5068 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5069 | DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ |
| 5070 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5071 | } while (0) |
| 5072 | |
| 5073 | #define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5074 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5075 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5076 | DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ |
| 5077 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5078 | } while (0) |
| 5079 | #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5080 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5081 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5082 | DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ |
| 5083 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5084 | } while (0) |
| 5085 | #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5086 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5087 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5088 | DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ |
| 5089 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5090 | } while (0) |
| 5091 | #define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5092 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5093 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5094 | DUK_TVAL_SET_NAN(tv__dst); \ |
| 5095 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5096 | } while (0) |
| 5097 | #if defined(DUK_USE_FASTINT) |
| 5098 | #define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5099 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5100 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5101 | DUK_TVAL_SET_I48(tv__dst, (newval)); \ |
| 5102 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5103 | } while (0) |
| 5104 | #define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5105 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5106 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5107 | DUK_TVAL_SET_I32(tv__dst, (newval)); \ |
| 5108 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5109 | } while (0) |
| 5110 | #define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5111 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5112 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5113 | DUK_TVAL_SET_U32(tv__dst, (newval)); \ |
| 5114 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5115 | } while (0) |
| 5116 | #else |
| 5117 | #define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ |
| 5118 | DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) |
| 5119 | #endif /* DUK_USE_FASTINT */ |
| 5120 | |
| 5121 | #define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ |
| 5122 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5123 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5124 | DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ |
| 5125 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5126 | } while (0) |
| 5127 | |
| 5128 | #define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5129 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5130 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5131 | DUK_TVAL_SET_STRING(tv__dst, (newval)); \ |
| 5132 | DUK_HSTRING_INCREF((thr), (newval)); \ |
| 5133 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5134 | } while (0) |
| 5135 | |
| 5136 | #define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5137 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5138 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5139 | DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ |
| 5140 | DUK_HOBJECT_INCREF((thr), (newval)); \ |
| 5141 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5142 | } while (0) |
| 5143 | |
| 5144 | #define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5145 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5146 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5147 | DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ |
| 5148 | DUK_HBUFFER_INCREF((thr), (newval)); \ |
| 5149 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5150 | } while (0) |
| 5151 | |
| 5152 | #define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5153 | duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \ |
| 5154 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5155 | DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ |
| 5156 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5157 | } while (0) |
| 5158 | |
| 5159 | /* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups, |
| 5160 | * etc, so it's very important for performance. Measure when changing. |
| 5161 | * |
| 5162 | * NOTE: the source and destination duk_tval pointers may be the same, and |
| 5163 | * the macros MUST deal with that correctly. |
| 5164 | */ |
| 5165 | |
| 5166 | /* Original idiom used, minimal code size. */ |
| 5167 | #define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ |
| 5168 | duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \ |
| 5169 | tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ |
| 5170 | DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \ |
| 5171 | DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ |
| 5172 | DUK_TVAL_INCREF((thr), tv__src); \ |
| 5173 | DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \ |
| 5174 | } while (0) |
| 5175 | |
| 5176 | /* Faster alternative: avoid making a temporary copy of tvptr_dst and use |
| 5177 | * fast incref/decref macros. |
| 5178 | */ |
| 5179 | #define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \ |
| 5180 | duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \ |
| 5181 | tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ |
| 5182 | DUK_TVAL_INCREF_FAST((thr), tv__src); \ |
| 5183 | if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \ |
| 5184 | h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \ |
| 5185 | DUK_ASSERT(h__obj != NULL); \ |
| 5186 | DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ |
| 5187 | DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \ |
| 5188 | } else { \ |
| 5189 | DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ |
| 5190 | } \ |
| 5191 | } while (0) |
| 5192 | |
| 5193 | /* XXX: no optimized variants yet */ |
| 5194 | #define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 |
| 5195 | #define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0 |
| 5196 | #define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 |
| 5197 | #define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 |
| 5198 | #define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 |
| 5199 | #define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 |
| 5200 | #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 |
| 5201 | #define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 |
| 5202 | #define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 |
| 5203 | #if defined(DUK_USE_FASTINT) |
| 5204 | #define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 |
| 5205 | #define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 |
| 5206 | #define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 |
| 5207 | #else |
| 5208 | #define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */ |
| 5209 | #define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF |
| 5210 | #define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF |
| 5211 | #endif /* DUK_USE_FASTINT */ |
| 5212 | #define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ |
| 5213 | #define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 |
| 5214 | #define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 |
| 5215 | #define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 |
| 5216 | #define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 |
| 5217 | #define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 |
| 5218 | |
| 5219 | #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| 5220 | /* Optimized for speed. */ |
| 5221 | #define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1 |
| 5222 | #define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1 |
| 5223 | #define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 |
| 5224 | #else |
| 5225 | /* Optimized for size. */ |
| 5226 | #define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 |
| 5227 | #define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 |
| 5228 | #define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 |
| 5229 | #endif |
| 5230 | |
| 5231 | #else /* DUK_USE_REFERENCE_COUNTING */ |
| 5232 | |
| 5233 | #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0 |
| 5234 | #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0 |
| 5235 | |
| 5236 | #define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */ |
| 5237 | #define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */ |
| 5238 | #define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */ |
| 5239 | #define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */ |
| 5240 | #define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */ |
| 5241 | #define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */ |
| 5242 | #define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */ |
| 5243 | #define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */ |
| 5244 | #define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */ |
| 5245 | #define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5246 | #define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5247 | #define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ |
| 5248 | #define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5249 | #define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5250 | #define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ |
| 5251 | #define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */ |
| 5252 | #define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */ |
| 5253 | #define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5254 | #define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5255 | #define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5256 | #define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ |
| 5257 | #define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5258 | #define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5259 | #define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ |
| 5260 | #define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */ |
| 5261 | #define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */ |
| 5262 | #define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5263 | #define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5264 | #define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5265 | #define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ |
| 5266 | #define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5267 | #define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5268 | #define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ |
| 5269 | #define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */ |
| 5270 | #define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */ |
| 5271 | #define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5272 | #define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5273 | #define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */ |
| 5274 | #define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */ |
| 5275 | #define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5276 | #define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */ |
| 5277 | #define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */ |
| 5278 | #define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */ |
| 5279 | #define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */ |
| 5280 | #define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5281 | |
| 5282 | #define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */ |
| 5283 | #define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */ |
| 5284 | #define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5285 | #define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */ |
| 5286 | #define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */ |
| 5287 | #define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5288 | #define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */ |
| 5289 | #define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */ |
| 5290 | #define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5291 | #define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */ |
| 5292 | #define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */ |
| 5293 | #define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */ |
| 5294 | #define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ |
| 5295 | #define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ |
| 5296 | #define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ |
| 5297 | #define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ |
| 5298 | #define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */ |
| 5299 | #define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */ |
| 5300 | |
| 5301 | #define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */ |
| 5302 | #define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */ |
| 5303 | |
| 5304 | #define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5305 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5306 | DUK_TVAL_SET_UNDEFINED(tv__dst); \ |
| 5307 | DUK_UNREF((thr)); \ |
| 5308 | } while (0) |
| 5309 | |
| 5310 | #define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5311 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5312 | DUK_TVAL_SET_UNUSED(tv__dst); \ |
| 5313 | DUK_UNREF((thr)); \ |
| 5314 | } while (0) |
| 5315 | |
| 5316 | #define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5317 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5318 | DUK_TVAL_SET_NULL(tv__dst); \ |
| 5319 | DUK_UNREF((thr)); \ |
| 5320 | } while (0) |
| 5321 | |
| 5322 | #define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5323 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5324 | DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \ |
| 5325 | DUK_UNREF((thr)); \ |
| 5326 | } while (0) |
| 5327 | |
| 5328 | #define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5329 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5330 | DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \ |
| 5331 | DUK_UNREF((thr)); \ |
| 5332 | } while (0) |
| 5333 | #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5334 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5335 | DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \ |
| 5336 | DUK_UNREF((thr)); \ |
| 5337 | } while (0) |
| 5338 | #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5339 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5340 | DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \ |
| 5341 | DUK_UNREF((thr)); \ |
| 5342 | } while (0) |
| 5343 | #define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \ |
| 5344 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5345 | DUK_TVAL_SET_NAN(tv__dst); \ |
| 5346 | DUK_UNREF((thr)); \ |
| 5347 | } while (0) |
| 5348 | #if defined(DUK_USE_FASTINT) |
| 5349 | #define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5350 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5351 | DUK_TVAL_SET_I48(tv__dst, (newval)); \ |
| 5352 | DUK_UNREF((thr)); \ |
| 5353 | } while (0) |
| 5354 | #define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5355 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5356 | DUK_TVAL_SET_I32(tv__dst, (newval)); \ |
| 5357 | DUK_UNREF((thr)); \ |
| 5358 | } while (0) |
| 5359 | #define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5360 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5361 | DUK_TVAL_SET_U32(tv__dst, (newval)); \ |
| 5362 | DUK_UNREF((thr)); \ |
| 5363 | } while (0) |
| 5364 | #else |
| 5365 | #define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \ |
| 5366 | DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval)) |
| 5367 | #endif /* DUK_USE_FASTINT */ |
| 5368 | |
| 5369 | #define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \ |
| 5370 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5371 | DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \ |
| 5372 | DUK_UNREF((thr)); \ |
| 5373 | } while (0) |
| 5374 | |
| 5375 | #define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5376 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5377 | DUK_TVAL_SET_STRING(tv__dst, (newval)); \ |
| 5378 | DUK_UNREF((thr)); \ |
| 5379 | } while (0) |
| 5380 | |
| 5381 | #define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5382 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5383 | DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \ |
| 5384 | DUK_UNREF((thr)); \ |
| 5385 | } while (0) |
| 5386 | |
| 5387 | #define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5388 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5389 | DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \ |
| 5390 | DUK_UNREF((thr)); \ |
| 5391 | } while (0) |
| 5392 | |
| 5393 | #define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \ |
| 5394 | duk_tval *tv__dst; tv__dst = (tvptr_dst); \ |
| 5395 | DUK_TVAL_SET_POINTER(tv__dst, (newval)); \ |
| 5396 | DUK_UNREF((thr)); \ |
| 5397 | } while (0) |
| 5398 | |
| 5399 | #define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \ |
| 5400 | duk_tval *tv__dst, *tv__src; \ |
| 5401 | tv__dst = (tvptr_dst); tv__src = (tvptr_src); \ |
| 5402 | DUK_TVAL_SET_TVAL(tv__dst, tv__src); \ |
| 5403 | DUK_UNREF((thr)); \ |
| 5404 | } while (0) |
| 5405 | |
| 5406 | #define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 |
| 5407 | #define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0 |
| 5408 | #define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0 |
| 5409 | #define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0 |
| 5410 | #define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0 |
| 5411 | #define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0 |
| 5412 | #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0 |
| 5413 | #define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0 |
| 5414 | #define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0 |
| 5415 | #if defined(DUK_USE_FASTINT) |
| 5416 | #define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0 |
| 5417 | #define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0 |
| 5418 | #define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0 |
| 5419 | #else |
| 5420 | #define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */ |
| 5421 | #define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF |
| 5422 | #define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF |
| 5423 | #endif /* DUK_USE_FASTINT */ |
| 5424 | #define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */ |
| 5425 | #define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0 |
| 5426 | #define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0 |
| 5427 | #define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0 |
| 5428 | #define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0 |
| 5429 | #define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0 |
| 5430 | |
| 5431 | #define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0 |
| 5432 | #define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0 |
| 5433 | #define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0 |
| 5434 | |
| 5435 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 5436 | |
| 5437 | /* |
| 5438 | * Some convenience macros that don't have optimized implementations now. |
| 5439 | */ |
| 5440 | |
| 5441 | #define DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr,tv_dst,tv_src) do { \ |
| 5442 | duk_hthread *duk__thr = (thr); \ |
| 5443 | duk_tval *duk__dst = (tv_dst); \ |
| 5444 | duk_tval *duk__src = (tv_src); \ |
| 5445 | DUK_UNREF(duk__thr); \ |
| 5446 | DUK_TVAL_DECREF_NORZ(thr, duk__dst); \ |
| 5447 | DUK_TVAL_SET_TVAL(duk__dst, duk__src); \ |
| 5448 | DUK_TVAL_INCREF(thr, duk__dst); \ |
| 5449 | } while (0) |
| 5450 | |
| 5451 | #define DUK_TVAL_SET_U32_UPDREF_NORZ(thr,tv_dst,val) do { \ |
| 5452 | duk_hthread *duk__thr = (thr); \ |
| 5453 | duk_tval *duk__dst = (tv_dst); \ |
| 5454 | duk_uint32_t duk__val = (duk_uint32_t) (val); \ |
| 5455 | DUK_UNREF(duk__thr); \ |
| 5456 | DUK_TVAL_DECREF_NORZ(thr, duk__dst); \ |
| 5457 | DUK_TVAL_SET_U32(duk__dst, duk__val); \ |
| 5458 | } while (0) |
| 5459 | |
| 5460 | /* |
| 5461 | * Prototypes |
| 5462 | */ |
| 5463 | |
| 5464 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 5465 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 5466 | DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr); |
| 5467 | DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr); |
| 5468 | #endif |
| 5469 | DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr); |
| 5470 | DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h); |
| 5471 | #if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */ |
| 5472 | DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h); |
| 5473 | DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h); |
| 5474 | DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h); |
| 5475 | DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h); |
| 5476 | DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h); |
| 5477 | DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h); |
| 5478 | #endif |
| 5479 | DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h); |
| 5480 | DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h); |
| 5481 | #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| 5482 | DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */ |
| 5483 | DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */ |
| 5484 | DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h); |
| 5485 | DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h); |
| 5486 | #else |
| 5487 | DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv); |
| 5488 | DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv); |
| 5489 | DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv); |
| 5490 | DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h); |
| 5491 | DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h); |
| 5492 | DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h); |
| 5493 | #endif |
| 5494 | #else /* DUK_USE_REFERENCE_COUNTING */ |
| 5495 | /* no refcounting */ |
| 5496 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 5497 | |
| 5498 | #endif /* DUK_REFCOUNT_H_INCLUDED */ |
| 5499 | /* #include duk_api_internal.h */ |
| 5500 | #line 1 "duk_api_internal.h" |
| 5501 | /* |
| 5502 | * Internal API calls which have (stack and other) semantics similar |
| 5503 | * to the public API. |
| 5504 | */ |
| 5505 | |
| 5506 | #if !defined(DUK_API_INTERNAL_H_INCLUDED) |
| 5507 | #define DUK_API_INTERNAL_H_INCLUDED |
| 5508 | |
| 5509 | /* Inline macro helpers. */ |
| 5510 | #if defined(DUK_USE_PREFER_SIZE) |
| 5511 | #define DUK_INLINE_PERF |
| 5512 | #define DUK_ALWAYS_INLINE_PERF |
| 5513 | #define DUK_NOINLINE_PERF |
| 5514 | #else |
| 5515 | #define DUK_INLINE_PERF DUK_INLINE |
| 5516 | #define DUK_ALWAYS_INLINE_PERF DUK_ALWAYS_INLINE |
| 5517 | #define DUK_NOINLINE_PERF DUK_NOINLINE |
| 5518 | #endif |
| 5519 | |
| 5520 | /* Inline macro helpers, for bytecode executor. */ |
| 5521 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 5522 | #define DUK_EXEC_INLINE_PERF |
| 5523 | #define DUK_EXEC_ALWAYS_INLINE_PERF |
| 5524 | #define DUK_EXEC_NOINLINE_PERF |
| 5525 | #else |
| 5526 | #define DUK_EXEC_INLINE_PERF DUK_INLINE |
| 5527 | #define DUK_EXEC_ALWAYS_INLINE_PERF DUK_ALWAYS_INLINE |
| 5528 | #define DUK_EXEC_NOINLINE_PERF DUK_NOINLINE |
| 5529 | #endif |
| 5530 | |
| 5531 | /* duk_push_sprintf constants */ |
| 5532 | #define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L |
| 5533 | #define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L) |
| 5534 | |
| 5535 | /* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not |
| 5536 | * blamed as source of error for error fileName / lineNumber. |
| 5537 | */ |
| 5538 | #define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24) |
| 5539 | |
| 5540 | /* Current convention is to use duk_size_t for value stack sizes and global indices, |
| 5541 | * and duk_idx_t for local frame indices. |
| 5542 | */ |
| 5543 | DUK_INTERNAL_DECL void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes); |
| 5544 | DUK_INTERNAL_DECL duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes); |
| 5545 | DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug); |
| 5546 | |
| 5547 | DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count); |
| 5548 | |
| 5549 | DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count); |
| 5550 | |
| 5551 | DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx); |
| 5552 | DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start); |
| 5553 | |
| 5554 | DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr); |
| 5555 | DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr); |
| 5556 | DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr); |
| 5557 | /* duk_dup_m1() would be same as duk_dup_top() */ |
| 5558 | DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr); |
| 5559 | DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr); |
| 5560 | DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr); |
| 5561 | |
| 5562 | DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx); |
| 5563 | DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr); |
| 5564 | DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count); |
| 5565 | DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count); |
| 5566 | |
| 5567 | DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv); |
| 5568 | DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv); |
| 5569 | |
| 5570 | #if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) |
| 5571 | DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx); |
| 5572 | #endif |
| 5573 | DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx); |
| 5574 | |
| 5575 | DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx); |
| 5576 | DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx); |
| 5577 | DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx); |
| 5578 | DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv); |
| 5579 | |
| 5580 | /* Push the current 'this' binding; throw TypeError if binding is not object |
| 5581 | * coercible (CheckObjectCoercible). |
| 5582 | */ |
| 5583 | DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr); |
| 5584 | |
| 5585 | /* duk_push_this() + CheckObjectCoercible() + duk_to_object() */ |
| 5586 | DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr); |
| 5587 | |
| 5588 | /* duk_push_this() + CheckObjectCoercible() + duk_to_string() */ |
| 5589 | DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr); |
| 5590 | |
| 5591 | DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i); |
| 5592 | |
| 5593 | /* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must |
| 5594 | * make sure there's an active callstack entry. Note that the returned pointer |
| 5595 | * is unstable with regards to side effects. |
| 5596 | */ |
| 5597 | DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr); |
| 5598 | |
| 5599 | /* XXX: add fastint support? */ |
| 5600 | #define duk_push_u64(thr,val) \ |
| 5601 | duk_push_number((thr), (duk_double_t) (val)) |
| 5602 | #define duk_push_i64(thr,val) \ |
| 5603 | duk_push_number((thr), (duk_double_t) (val)) |
| 5604 | |
| 5605 | /* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */ |
| 5606 | #define duk_push_u32(thr,val) \ |
| 5607 | duk_push_uint((thr), (duk_uint_t) (val)) |
| 5608 | #define duk_push_i32(thr,val) \ |
| 5609 | duk_push_int((thr), (duk_int_t) (val)) |
| 5610 | |
| 5611 | /* sometimes stack and array indices need to go on the stack */ |
| 5612 | #define duk_push_idx(thr,val) \ |
| 5613 | duk_push_int((thr), (duk_int_t) (val)) |
| 5614 | #define duk_push_uarridx(thr,val) \ |
| 5615 | duk_push_uint((thr), (duk_uint_t) (val)) |
| 5616 | #define duk_push_size_t(thr,val) \ |
| 5617 | duk_push_uint((thr), (duk_uint_t) (val)) /* XXX: assumed to fit for now */ |
| 5618 | |
| 5619 | DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx); |
| 5620 | |
| 5621 | DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv); |
| 5622 | |
| 5623 | DUK_INTERNAL_DECL duk_bool_t duk_is_bare_object(duk_hthread *thr, duk_idx_t idx); |
| 5624 | |
| 5625 | DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx); |
| 5626 | DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx); |
| 5627 | DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx); |
| 5628 | DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx); |
| 5629 | DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx); |
| 5630 | DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx); |
| 5631 | DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx); |
| 5632 | DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx); |
| 5633 | |
| 5634 | DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len, duk_bool_t throw_flag, duk_bool_t *out_isbuffer); |
| 5635 | |
| 5636 | DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum); |
| 5637 | |
| 5638 | DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask); |
| 5639 | DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask); |
| 5640 | DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask); |
| 5641 | #define duk_require_hobject_promote_lfunc(thr,idx) \ |
| 5642 | duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC) |
| 5643 | #define duk_get_hobject_promote_lfunc(thr,idx) \ |
| 5644 | duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC) |
| 5645 | |
| 5646 | #if 0 /*unused*/ |
| 5647 | DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx); |
| 5648 | #endif |
| 5649 | |
| 5650 | DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx); |
| 5651 | DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx); |
| 5652 | DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx); |
| 5653 | DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx); |
| 5654 | DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx); |
| 5655 | |
| 5656 | DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv); |
| 5657 | |
| 5658 | DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx); |
| 5659 | DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr); |
| 5660 | DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx); |
| 5661 | |
| 5662 | DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx); |
| 5663 | |
| 5664 | DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr); |
| 5665 | DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr); |
| 5666 | |
| 5667 | DUK_INTERNAL_DECL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr); |
| 5668 | |
| 5669 | #if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ |
| 5670 | DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx); |
| 5671 | #endif |
| 5672 | DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects); |
| 5673 | |
| 5674 | DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */ |
| 5675 | DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval); |
| 5676 | DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval); |
| 5677 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 5678 | DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx); |
| 5679 | #endif |
| 5680 | DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx); |
| 5681 | |
| 5682 | DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx); |
| 5683 | DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx); |
| 5684 | DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len); |
| 5685 | DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx); |
| 5686 | DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx); |
| 5687 | DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx); |
| 5688 | DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx); |
| 5689 | DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx); |
| 5690 | DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx); |
| 5691 | |
| 5692 | DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum); |
| 5693 | |
| 5694 | DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h); |
| 5695 | DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx); |
| 5696 | DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr); |
| 5697 | DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h); |
| 5698 | DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h); |
| 5699 | #define duk_push_hthread(thr,h) \ |
| 5700 | duk_push_hobject((thr), (duk_hobject *) (h)) |
| 5701 | #define duk_push_hnatfunc(thr,h) \ |
| 5702 | duk_push_hobject((thr), (duk_hobject *) (h)) |
| 5703 | DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx); |
| 5704 | DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); |
| 5705 | DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto); |
| 5706 | DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr); |
| 5707 | DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr); |
| 5708 | DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs); |
| 5709 | DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs); |
| 5710 | |
| 5711 | /* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with |
| 5712 | * duk_push_hobject() etc which don't create a new value. |
| 5713 | */ |
| 5714 | DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr); |
| 5715 | DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size); |
| 5716 | DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size); |
| 5717 | |
| 5718 | DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz); |
| 5719 | DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags); |
| 5720 | DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv); |
| 5721 | DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv); |
| 5722 | #if 0 /* not used yet */ |
| 5723 | DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h); |
| 5724 | #endif |
| 5725 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 5726 | DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx); |
| 5727 | #endif |
| 5728 | |
| 5729 | DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len); |
| 5730 | DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len); |
| 5731 | |
| 5732 | DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx); |
| 5733 | DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv); |
| 5734 | DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv); |
| 5735 | |
| 5736 | /* The duk_xxx_prop_stridx_short() variants expect their arguments to be short |
| 5737 | * enough to be packed into a single 32-bit integer argument. Argument limits |
| 5738 | * vary per call; typically 16 bits are assigned to the signed value stack index |
| 5739 | * and the stridx. In practice these work well for footprint with constant |
| 5740 | * arguments and such call sites are also easiest to verify to be correct. |
| 5741 | */ |
| 5742 | |
| 5743 | DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */ |
| 5744 | DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); |
| 5745 | #define duk_get_prop_stridx_short(thr,obj_idx,stridx) \ |
| 5746 | (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \ |
| 5747 | DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ |
| 5748 | duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) |
| 5749 | DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */ |
| 5750 | |
| 5751 | DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop(duk_hthread *thr, duk_idx_t obj_idx); |
| 5752 | DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); |
| 5753 | DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); |
| 5754 | #define duk_xget_owndataprop_stridx_short(thr,obj_idx,stridx) \ |
| 5755 | (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \ |
| 5756 | DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ |
| 5757 | duk_xget_owndataprop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) |
| 5758 | |
| 5759 | DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */ |
| 5760 | DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); |
| 5761 | #define duk_put_prop_stridx_short(thr,obj_idx,stridx) \ |
| 5762 | (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \ |
| 5763 | DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ |
| 5764 | duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) |
| 5765 | |
| 5766 | DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ |
| 5767 | #if 0 /* Too few call sites to be useful. */ |
| 5768 | DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); |
| 5769 | #define duk_del_prop_stridx_short(thr,obj_idx,stridx) \ |
| 5770 | (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \ |
| 5771 | DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \ |
| 5772 | duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) |
| 5773 | #endif |
| 5774 | #define duk_del_prop_stridx_short(thr,obj_idx,stridx) \ |
| 5775 | duk_del_prop_stridx((thr), (obj_idx), (stridx)) |
| 5776 | |
| 5777 | DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ |
| 5778 | #if 0 /* Too few call sites to be useful. */ |
| 5779 | DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); |
| 5780 | #define duk_has_prop_stridx_short(thr,obj_idx,stridx) \ |
| 5781 | (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \ |
| 5782 | DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \ |
| 5783 | duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx)))) |
| 5784 | #endif |
| 5785 | #define duk_has_prop_stridx_short(thr,obj_idx,stridx) \ |
| 5786 | duk_has_prop_stridx((thr), (obj_idx), (stridx)) |
| 5787 | |
| 5788 | DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */ |
| 5789 | |
| 5790 | DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */ |
| 5791 | |
| 5792 | /* XXX: Because stridx and desc_flags have a limited range, this call could |
| 5793 | * always pack stridx and desc_flags into a single argument. |
| 5794 | */ |
| 5795 | DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */ |
| 5796 | DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args); |
| 5797 | #define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \ |
| 5798 | (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \ |
| 5799 | DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \ |
| 5800 | DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \ |
| 5801 | duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags))) |
| 5802 | |
| 5803 | #define duk_xdef_prop_wec(thr,obj_idx) \ |
| 5804 | duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC) |
| 5805 | #define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \ |
| 5806 | duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC) |
| 5807 | #define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \ |
| 5808 | duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC) |
| 5809 | #define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \ |
| 5810 | duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC) |
| 5811 | |
| 5812 | #if 0 /*unused*/ |
| 5813 | DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */ |
| 5814 | #endif |
| 5815 | |
| 5816 | DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */ |
| 5817 | |
| 5818 | DUK_INTERNAL_DECL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx); |
| 5819 | |
| 5820 | DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count); |
| 5821 | DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx); |
| 5822 | #if 0 |
| 5823 | DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr); |
| 5824 | #endif |
| 5825 | |
| 5826 | DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h); |
| 5827 | |
| 5828 | DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr); |
| 5829 | |
| 5830 | DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top); |
| 5831 | DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr); |
| 5832 | |
| 5833 | DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count); |
| 5834 | DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr); |
| 5835 | DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr); |
| 5836 | DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr); |
| 5837 | DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count); |
| 5838 | DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr); |
| 5839 | DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr); |
| 5840 | DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr); |
| 5841 | DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr); |
| 5842 | |
| 5843 | DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr); |
| 5844 | |
| 5845 | DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze); |
| 5846 | |
| 5847 | DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx); |
| 5848 | DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count); |
| 5849 | |
| 5850 | DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr); |
| 5851 | |
| 5852 | DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags); |
| 5853 | |
| 5854 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 5855 | DUK_INTERNAL_DECL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint); |
| 5856 | #endif |
| 5857 | |
| 5858 | DUK_INTERNAL_DECL void duk_clear_prototype(duk_hthread *thr, duk_idx_t idx); |
| 5859 | |
| 5860 | /* Raw internal valstack access macros: access is unsafe so call site |
| 5861 | * must have a guarantee that the index is valid. When that is the case, |
| 5862 | * using these macro results in faster and smaller code than duk_get_tval(). |
| 5863 | * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts. |
| 5864 | */ |
| 5865 | #define DUK_ASSERT_VALID_NEGIDX(thr,idx) \ |
| 5866 | (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx)))) |
| 5867 | #define DUK_ASSERT_VALID_POSIDX(thr,idx) \ |
| 5868 | (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx)))) |
| 5869 | #define DUK_GET_TVAL_NEGIDX(thr,idx) \ |
| 5870 | (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx)) |
| 5871 | #define DUK_GET_TVAL_POSIDX(thr,idx) \ |
| 5872 | (DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx)) |
| 5873 | #define DUK_GET_HOBJECT_NEGIDX(thr,idx) \ |
| 5874 | (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx))) |
| 5875 | #define DUK_GET_HOBJECT_POSIDX(thr,idx) \ |
| 5876 | (DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx))) |
| 5877 | |
| 5878 | #define DUK_GET_THIS_TVAL_PTR(thr) \ |
| 5879 | (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \ |
| 5880 | (thr)->valstack_bottom - 1) |
| 5881 | |
| 5882 | DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr); |
| 5883 | DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr); |
| 5884 | DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr); |
| 5885 | |
| 5886 | #endif /* DUK_API_INTERNAL_H_INCLUDED */ |
| 5887 | /* #include duk_hstring.h */ |
| 5888 | #line 1 "duk_hstring.h" |
| 5889 | /* |
| 5890 | * Heap string representation. |
| 5891 | * |
| 5892 | * Strings are byte sequences ordinarily stored in extended UTF-8 format, |
| 5893 | * allowing values larger than the official UTF-8 range (used internally) |
| 5894 | * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format). |
| 5895 | * Strings may also be invalid UTF-8 altogether which is the case e.g. with |
| 5896 | * strings used as internal property names and raw buffers converted to |
| 5897 | * strings. In such cases the 'clen' field contains an inaccurate value. |
| 5898 | * |
| 5899 | * ECMAScript requires support for 32-bit long strings. However, since each |
| 5900 | * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only |
| 5901 | * support about 1.4G codepoint long strings in extreme cases. This is not |
| 5902 | * really a practical issue. |
| 5903 | */ |
| 5904 | |
| 5905 | #if !defined(DUK_HSTRING_H_INCLUDED) |
| 5906 | #define DUK_HSTRING_H_INCLUDED |
| 5907 | |
| 5908 | /* Impose a maximum string length for now. Restricted artificially to |
| 5909 | * ensure adding a heap header length won't overflow size_t. The limit |
| 5910 | * should be synchronized with DUK_HBUFFER_MAX_BYTELEN. |
| 5911 | * |
| 5912 | * E5.1 makes provisions to support strings longer than 4G characters. |
| 5913 | * This limit should be eliminated on 64-bit platforms (and increased |
| 5914 | * closer to maximum support on 32-bit platforms). |
| 5915 | */ |
| 5916 | |
| 5917 | #if defined(DUK_USE_STRLEN16) |
| 5918 | #define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL) |
| 5919 | #else |
| 5920 | #define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL) |
| 5921 | #endif |
| 5922 | |
| 5923 | /* XXX: could add flags for "is valid CESU-8" (ECMAScript compatible strings), |
| 5924 | * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not, |
| 5925 | * regexp bytecode is), and "contains non-BMP characters". These are not |
| 5926 | * needed right now. |
| 5927 | */ |
| 5928 | |
| 5929 | /* With lowmem builds the high 16 bits of duk_heaphdr are used for other |
| 5930 | * purposes, so this leaves 7 duk_heaphdr flags and 9 duk_hstring flags. |
| 5931 | */ |
| 5932 | #define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */ |
| 5933 | #define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */ |
| 5934 | #define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */ |
| 5935 | #define DUK_HSTRING_FLAG_HIDDEN DUK_HEAPHDR_USER_FLAG(3) /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */ |
| 5936 | #define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (non-strict) */ |
| 5937 | #define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */ |
| 5938 | #define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */ |
| 5939 | #define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */ |
| 5940 | #define DUK_HSTRING_FLAG_PINNED_LITERAL DUK_HEAPHDR_USER_FLAG(8) /* string is a literal, and pinned */ |
| 5941 | |
| 5942 | #define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) |
| 5943 | #define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) |
| 5944 | #define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) |
| 5945 | #define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) |
| 5946 | #define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) |
| 5947 | #define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) |
| 5948 | #define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) |
| 5949 | #define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) |
| 5950 | #define DUK_HSTRING_HAS_PINNED_LITERAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL) |
| 5951 | |
| 5952 | #define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) |
| 5953 | #define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) |
| 5954 | #define DUK_HSTRING_SET_SYMBOL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) |
| 5955 | #define DUK_HSTRING_SET_HIDDEN(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) |
| 5956 | #define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) |
| 5957 | #define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) |
| 5958 | #define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) |
| 5959 | #define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) |
| 5960 | #define DUK_HSTRING_SET_PINNED_LITERAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL) |
| 5961 | |
| 5962 | #define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII) |
| 5963 | #define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX) |
| 5964 | #define DUK_HSTRING_CLEAR_SYMBOL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL) |
| 5965 | #define DUK_HSTRING_CLEAR_HIDDEN(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN) |
| 5966 | #define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD) |
| 5967 | #define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD) |
| 5968 | #define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS) |
| 5969 | #define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA) |
| 5970 | #define DUK_HSTRING_CLEAR_PINNED_LITERAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL) |
| 5971 | |
| 5972 | #if 0 /* Slightly smaller code without explicit flag, but explicit flag |
| 5973 | * is very useful when 'clen' is dropped. |
| 5974 | */ |
| 5975 | #define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x))) |
| 5976 | #endif |
| 5977 | #define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x)) /* lazily set! */ |
| 5978 | #define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0) |
| 5979 | |
| 5980 | #if defined(DUK_USE_STRHASH16) |
| 5981 | #define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16) |
| 5982 | #define DUK_HSTRING_SET_HASH(x,v) do { \ |
| 5983 | (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \ |
| 5984 | } while (0) |
| 5985 | #else |
| 5986 | #define DUK_HSTRING_GET_HASH(x) ((x)->hash) |
| 5987 | #define DUK_HSTRING_SET_HASH(x,v) do { \ |
| 5988 | (x)->hash = (v); \ |
| 5989 | } while (0) |
| 5990 | #endif |
| 5991 | |
| 5992 | #if defined(DUK_USE_STRLEN16) |
| 5993 | #define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16) |
| 5994 | #define DUK_HSTRING_SET_BYTELEN(x,v) do { \ |
| 5995 | (x)->hdr.h_strextra16 = (v); \ |
| 5996 | } while (0) |
| 5997 | #if defined(DUK_USE_HSTRING_CLEN) |
| 5998 | #define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) |
| 5999 | #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ |
| 6000 | (x)->clen16 = (v); \ |
| 6001 | } while (0) |
| 6002 | #else |
| 6003 | #define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) |
| 6004 | #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ |
| 6005 | DUK_ASSERT(0); /* should never be called */ \ |
| 6006 | } while (0) |
| 6007 | #endif |
| 6008 | #else |
| 6009 | #define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen) |
| 6010 | #define DUK_HSTRING_SET_BYTELEN(x,v) do { \ |
| 6011 | (x)->blen = (v); \ |
| 6012 | } while (0) |
| 6013 | #define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x)) |
| 6014 | #define DUK_HSTRING_SET_CHARLEN(x,v) do { \ |
| 6015 | (x)->clen = (v); \ |
| 6016 | } while (0) |
| 6017 | #endif |
| 6018 | |
| 6019 | #if defined(DUK_USE_HSTRING_EXTDATA) |
| 6020 | #define DUK_HSTRING_GET_EXTDATA(x) \ |
| 6021 | ((x)->extdata) |
| 6022 | #define DUK_HSTRING_GET_DATA(x) \ |
| 6023 | (DUK_HSTRING_HAS_EXTDATA((x)) ? \ |
| 6024 | DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1))) |
| 6025 | #else |
| 6026 | #define DUK_HSTRING_GET_DATA(x) \ |
| 6027 | ((const duk_uint8_t *) ((x) + 1)) |
| 6028 | #endif |
| 6029 | |
| 6030 | #define DUK_HSTRING_GET_DATA_END(x) \ |
| 6031 | (DUK_HSTRING_GET_DATA((x)) + (x)->blen) |
| 6032 | |
| 6033 | /* Marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest |
| 6034 | * valid). |
| 6035 | */ |
| 6036 | #define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL) |
| 6037 | |
| 6038 | #if defined(DUK_USE_HSTRING_ARRIDX) |
| 6039 | #define DUK_HSTRING_GET_ARRIDX_FAST(h) ((h)->arridx) |
| 6040 | #define DUK_HSTRING_GET_ARRIDX_SLOW(h) ((h)->arridx) |
| 6041 | #else |
| 6042 | /* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX); |
| 6043 | * avoids helper call if string has no array index value. |
| 6044 | */ |
| 6045 | #define DUK_HSTRING_GET_ARRIDX_FAST(h) \ |
| 6046 | (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX) |
| 6047 | |
| 6048 | /* Slower but more compact variant. */ |
| 6049 | #define DUK_HSTRING_GET_ARRIDX_SLOW(h) \ |
| 6050 | (duk_js_to_arrayindex_hstring_fast((h))) |
| 6051 | #endif |
| 6052 | |
| 6053 | /* XXX: these actually fit into duk_hstring */ |
| 6054 | #define DUK_SYMBOL_TYPE_HIDDEN 0 |
| 6055 | #define DUK_SYMBOL_TYPE_GLOBAL 1 |
| 6056 | #define DUK_SYMBOL_TYPE_LOCAL 2 |
| 6057 | #define DUK_SYMBOL_TYPE_WELLKNOWN 3 |
| 6058 | |
| 6059 | /* Assertion for duk_hstring validity. */ |
| 6060 | #if defined(DUK_USE_ASSERTIONS) |
| 6061 | DUK_INTERNAL_DECL void duk_hstring_assert_valid(duk_hstring *h); |
| 6062 | #define DUK_HSTRING_ASSERT_VALID(h) do { duk_hstring_assert_valid((h)); } while (0) |
| 6063 | #else |
| 6064 | #define DUK_HSTRING_ASSERT_VALID(h) do {} while (0) |
| 6065 | #endif |
| 6066 | |
| 6067 | /* |
| 6068 | * Misc |
| 6069 | */ |
| 6070 | |
| 6071 | struct duk_hstring { |
| 6072 | /* Smaller heaphdr than for other objects, because strings are held |
| 6073 | * in string intern table which requires no link pointers. Much of |
| 6074 | * the 32-bit flags field is unused by flags, so we can stuff a 16-bit |
| 6075 | * field in there. |
| 6076 | */ |
| 6077 | duk_heaphdr_string hdr; |
| 6078 | |
| 6079 | /* String hash. */ |
| 6080 | #if defined(DUK_USE_STRHASH16) |
| 6081 | /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */ |
| 6082 | #else |
| 6083 | duk_uint32_t hash; |
| 6084 | #endif |
| 6085 | |
| 6086 | /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */ |
| 6087 | #if defined(DUK_USE_HSTRING_ARRIDX) |
| 6088 | duk_uarridx_t arridx; |
| 6089 | #endif |
| 6090 | |
| 6091 | /* Length in bytes (not counting NUL term). */ |
| 6092 | #if defined(DUK_USE_STRLEN16) |
| 6093 | /* placed in duk_heaphdr_string */ |
| 6094 | #else |
| 6095 | duk_uint32_t blen; |
| 6096 | #endif |
| 6097 | |
| 6098 | /* Length in codepoints (must be E5 compatible). */ |
| 6099 | #if defined(DUK_USE_STRLEN16) |
| 6100 | #if defined(DUK_USE_HSTRING_CLEN) |
| 6101 | duk_uint16_t clen16; |
| 6102 | #else |
| 6103 | /* computed live */ |
| 6104 | #endif |
| 6105 | #else |
| 6106 | duk_uint32_t clen; |
| 6107 | #endif |
| 6108 | |
| 6109 | /* |
| 6110 | * String data of 'blen+1' bytes follows (+1 for NUL termination |
| 6111 | * convenience for C API). No alignment needs to be guaranteed |
| 6112 | * for strings, but fields above should guarantee alignment-by-4 |
| 6113 | * (but not alignment-by-8). |
| 6114 | */ |
| 6115 | }; |
| 6116 | |
| 6117 | /* The external string struct is defined even when the feature is inactive. */ |
| 6118 | struct duk_hstring_external { |
| 6119 | duk_hstring str; |
| 6120 | |
| 6121 | /* |
| 6122 | * For an external string, the NUL-terminated string data is stored |
| 6123 | * externally. The user must guarantee that data behind this pointer |
| 6124 | * doesn't change while it's used. |
| 6125 | */ |
| 6126 | |
| 6127 | const duk_uint8_t *extdata; |
| 6128 | }; |
| 6129 | |
| 6130 | /* |
| 6131 | * Prototypes |
| 6132 | */ |
| 6133 | |
| 6134 | DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware); |
| 6135 | DUK_INTERNAL_DECL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr); |
| 6136 | DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h); |
| 6137 | #if !defined(DUK_USE_HSTRING_LAZY_CLEN) |
| 6138 | DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h); |
| 6139 | #endif |
| 6140 | |
| 6141 | #endif /* DUK_HSTRING_H_INCLUDED */ |
| 6142 | /* #include duk_hobject.h */ |
| 6143 | #line 1 "duk_hobject.h" |
| 6144 | /* |
| 6145 | * Heap object representation. |
| 6146 | * |
| 6147 | * Heap objects are used for ECMAScript objects, arrays, and functions, |
| 6148 | * but also for internal control like declarative and object environment |
| 6149 | * records. Compiled functions, native functions, and threads are also |
| 6150 | * objects but with an extended C struct. |
| 6151 | * |
| 6152 | * Objects provide the required ECMAScript semantics and exotic behaviors |
| 6153 | * especially for property access. |
| 6154 | * |
| 6155 | * Properties are stored in three conceptual parts: |
| 6156 | * |
| 6157 | * 1. A linear 'entry part' contains ordered key-value-attributes triples |
| 6158 | * and is the main method of string properties. |
| 6159 | * |
| 6160 | * 2. An optional linear 'array part' is used for array objects to store a |
| 6161 | * (dense) range of [0,N[ array indexed entries with default attributes |
| 6162 | * (writable, enumerable, configurable). If the array part would become |
| 6163 | * sparse or non-default attributes are required, the array part is |
| 6164 | * abandoned and moved to the 'entry part'. |
| 6165 | * |
| 6166 | * 3. An optional 'hash part' is used to optimize lookups of the entry |
| 6167 | * part; it is used only for objects with sufficiently many properties |
| 6168 | * and can be abandoned without loss of information. |
| 6169 | * |
| 6170 | * These three conceptual parts are stored in a single memory allocated area. |
| 6171 | * This minimizes memory allocation overhead but also means that all three |
| 6172 | * parts are resized together, and makes property access a bit complicated. |
| 6173 | */ |
| 6174 | |
| 6175 | #if !defined(DUK_HOBJECT_H_INCLUDED) |
| 6176 | #define DUK_HOBJECT_H_INCLUDED |
| 6177 | |
| 6178 | /* Object flags. Make sure this stays in sync with debugger object |
| 6179 | * inspection code. |
| 6180 | */ |
| 6181 | |
| 6182 | /* XXX: some flags are object subtype specific (e.g. common to all function |
| 6183 | * subtypes, duk_harray, etc) and could be reused for different subtypes. |
| 6184 | */ |
| 6185 | #define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */ |
| 6186 | #define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */ |
| 6187 | #define DUK_HOBJECT_FLAG_CALLABLE DUK_HEAPHDR_USER_FLAG(2) /* object is callable */ |
| 6188 | #define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(3) /* object established using Function.prototype.bind() */ |
| 6189 | #define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */ |
| 6190 | #define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */ |
| 6191 | #define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */ |
| 6192 | #define DUK_HOBJECT_FLAG_FASTREFS DUK_HEAPHDR_USER_FLAG(7) /* object has no fields needing DECREF/marking beyond base duk_hobject header */ |
| 6193 | #define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */ |
| 6194 | #define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */ |
| 6195 | #define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */ |
| 6196 | #define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */ |
| 6197 | #define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */ |
| 6198 | #define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */ |
| 6199 | #define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable (own) finalizer property */ |
| 6200 | #define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */ |
| 6201 | #define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */ |
| 6202 | #define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */ |
| 6203 | #define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */ |
| 6204 | #define DUK_HOBJECT_FLAG_SPECIAL_CALL DUK_HEAPHDR_USER_FLAG(19) /* special casing in call behavior, for .call(), .apply(), etc. */ |
| 6205 | |
| 6206 | #define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20) |
| 6207 | #define DUK_HOBJECT_FLAG_CLASS_BITS 5 |
| 6208 | |
| 6209 | #define DUK_HOBJECT_GET_CLASS_NUMBER(h) \ |
| 6210 | DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS) |
| 6211 | #define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \ |
| 6212 | DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v)) |
| 6213 | |
| 6214 | #define DUK_HOBJECT_GET_CLASS_MASK(h) \ |
| 6215 | (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)) |
| 6216 | |
| 6217 | /* Macro for creating flag initializer from a class number. |
| 6218 | * Unsigned type cast is needed to avoid warnings about coercing |
| 6219 | * a signed integer to an unsigned one; the largest class values |
| 6220 | * have the highest bit (bit 31) set which causes this. |
| 6221 | */ |
| 6222 | #define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE) |
| 6223 | |
| 6224 | /* E5 Section 8.6.2 + custom classes */ |
| 6225 | #define DUK_HOBJECT_CLASS_NONE 0 |
| 6226 | #define DUK_HOBJECT_CLASS_OBJECT 1 |
| 6227 | #define DUK_HOBJECT_CLASS_ARRAY 2 |
| 6228 | #define DUK_HOBJECT_CLASS_FUNCTION 3 |
| 6229 | #define DUK_HOBJECT_CLASS_ARGUMENTS 4 |
| 6230 | #define DUK_HOBJECT_CLASS_BOOLEAN 5 |
| 6231 | #define DUK_HOBJECT_CLASS_DATE 6 |
| 6232 | #define DUK_HOBJECT_CLASS_ERROR 7 |
| 6233 | #define DUK_HOBJECT_CLASS_JSON 8 |
| 6234 | #define DUK_HOBJECT_CLASS_MATH 9 |
| 6235 | #define DUK_HOBJECT_CLASS_NUMBER 10 |
| 6236 | #define DUK_HOBJECT_CLASS_REGEXP 11 |
| 6237 | #define DUK_HOBJECT_CLASS_STRING 12 |
| 6238 | #define DUK_HOBJECT_CLASS_GLOBAL 13 |
| 6239 | #define DUK_HOBJECT_CLASS_SYMBOL 14 |
| 6240 | #define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */ |
| 6241 | #define DUK_HOBJECT_CLASS_DECENV 16 /* custom */ |
| 6242 | #define DUK_HOBJECT_CLASS_POINTER 17 /* custom */ |
| 6243 | #define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */ |
| 6244 | #define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19 |
| 6245 | #define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */ |
| 6246 | #define DUK_HOBJECT_CLASS_DATAVIEW 20 |
| 6247 | #define DUK_HOBJECT_CLASS_INT8ARRAY 21 |
| 6248 | #define DUK_HOBJECT_CLASS_UINT8ARRAY 22 |
| 6249 | #define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23 |
| 6250 | #define DUK_HOBJECT_CLASS_INT16ARRAY 24 |
| 6251 | #define DUK_HOBJECT_CLASS_UINT16ARRAY 25 |
| 6252 | #define DUK_HOBJECT_CLASS_INT32ARRAY 26 |
| 6253 | #define DUK_HOBJECT_CLASS_UINT32ARRAY 27 |
| 6254 | #define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28 |
| 6255 | #define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29 |
| 6256 | #define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29 |
| 6257 | #define DUK_HOBJECT_CLASS_MAX 29 |
| 6258 | |
| 6259 | /* Class masks. */ |
| 6260 | #define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL) |
| 6261 | #define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE) |
| 6262 | #define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS) |
| 6263 | #define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY) |
| 6264 | #define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN) |
| 6265 | #define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE) |
| 6266 | #define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR) |
| 6267 | #define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION) |
| 6268 | #define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON) |
| 6269 | #define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH) |
| 6270 | #define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER) |
| 6271 | #define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT) |
| 6272 | #define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP) |
| 6273 | #define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING) |
| 6274 | #define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL) |
| 6275 | #define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL) |
| 6276 | #define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV) |
| 6277 | #define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV) |
| 6278 | #define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER) |
| 6279 | #define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER) |
| 6280 | #define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW) |
| 6281 | #define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY) |
| 6282 | #define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY) |
| 6283 | #define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY) |
| 6284 | #define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY) |
| 6285 | #define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY) |
| 6286 | #define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY) |
| 6287 | #define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY) |
| 6288 | #define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY) |
| 6289 | #define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY) |
| 6290 | |
| 6291 | #define DUK_HOBJECT_CMASK_ALL_BUFOBJS \ |
| 6292 | (DUK_HOBJECT_CMASK_ARRAYBUFFER | \ |
| 6293 | DUK_HOBJECT_CMASK_DATAVIEW | \ |
| 6294 | DUK_HOBJECT_CMASK_INT8ARRAY | \ |
| 6295 | DUK_HOBJECT_CMASK_UINT8ARRAY | \ |
| 6296 | DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \ |
| 6297 | DUK_HOBJECT_CMASK_INT16ARRAY | \ |
| 6298 | DUK_HOBJECT_CMASK_UINT16ARRAY | \ |
| 6299 | DUK_HOBJECT_CMASK_INT32ARRAY | \ |
| 6300 | DUK_HOBJECT_CMASK_UINT32ARRAY | \ |
| 6301 | DUK_HOBJECT_CMASK_FLOAT32ARRAY | \ |
| 6302 | DUK_HOBJECT_CMASK_FLOAT64ARRAY) |
| 6303 | |
| 6304 | #define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV) |
| 6305 | #define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV) |
| 6306 | #define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h))) |
| 6307 | #define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */ |
| 6308 | #define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) |
| 6309 | #define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) |
| 6310 | #define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) |
| 6311 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 6312 | #define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) |
| 6313 | #else |
| 6314 | #define DUK_HOBJECT_IS_BUFOBJ(h) 0 |
| 6315 | #endif |
| 6316 | #define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD) |
| 6317 | #if defined(DUK_USE_ES6_PROXY) |
| 6318 | #define DUK_HOBJECT_IS_PROXY(h) DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h)) |
| 6319 | #else |
| 6320 | #define DUK_HOBJECT_IS_PROXY(h) 0 |
| 6321 | #endif |
| 6322 | |
| 6323 | #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ |
| 6324 | DUK_HOBJECT_FLAG_COMPFUNC | \ |
| 6325 | DUK_HOBJECT_FLAG_NATFUNC) |
| 6326 | |
| 6327 | #define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \ |
| 6328 | DUK_HOBJECT_FLAG_BOUNDFUNC | \ |
| 6329 | DUK_HOBJECT_FLAG_COMPFUNC | \ |
| 6330 | DUK_HOBJECT_FLAG_NATFUNC) |
| 6331 | |
| 6332 | #define DUK_HOBJECT_IS_CALLABLE(h) DUK_HOBJECT_HAS_CALLABLE((h)) |
| 6333 | |
| 6334 | /* Object has any exotic behavior(s). */ |
| 6335 | #define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ |
| 6336 | DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \ |
| 6337 | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ |
| 6338 | DUK_HOBJECT_FLAG_BUFOBJ | \ |
| 6339 | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) |
| 6340 | #define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS) |
| 6341 | |
| 6342 | /* Object has any virtual properties (not counting Proxy behavior). */ |
| 6343 | #define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ |
| 6344 | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \ |
| 6345 | DUK_HOBJECT_FLAG_BUFOBJ) |
| 6346 | #define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS) |
| 6347 | |
| 6348 | #define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) |
| 6349 | #define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) |
| 6350 | #define DUK_HOBJECT_HAS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE) |
| 6351 | #define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) |
| 6352 | #define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) |
| 6353 | #define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) |
| 6354 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 6355 | #define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) |
| 6356 | #else |
| 6357 | #define DUK_HOBJECT_HAS_BUFOBJ(h) 0 |
| 6358 | #endif |
| 6359 | #define DUK_HOBJECT_HAS_FASTREFS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS) |
| 6360 | #define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) |
| 6361 | #define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) |
| 6362 | #define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) |
| 6363 | #define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) |
| 6364 | #define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) |
| 6365 | #define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) |
| 6366 | #define DUK_HOBJECT_HAS_HAVE_FINALIZER(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER) |
| 6367 | #define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) |
| 6368 | #define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) |
| 6369 | #define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) |
| 6370 | #if defined(DUK_USE_ES6_PROXY) |
| 6371 | #define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) |
| 6372 | #else |
| 6373 | #define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) 0 |
| 6374 | #endif |
| 6375 | #define DUK_HOBJECT_HAS_SPECIAL_CALL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL) |
| 6376 | |
| 6377 | #define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) |
| 6378 | #define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) |
| 6379 | #define DUK_HOBJECT_SET_CALLABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE) |
| 6380 | #define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) |
| 6381 | #define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) |
| 6382 | #define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) |
| 6383 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 6384 | #define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) |
| 6385 | #endif |
| 6386 | #define DUK_HOBJECT_SET_FASTREFS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS) |
| 6387 | #define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) |
| 6388 | #define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) |
| 6389 | #define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) |
| 6390 | #define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) |
| 6391 | #define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) |
| 6392 | #define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) |
| 6393 | #define DUK_HOBJECT_SET_HAVE_FINALIZER(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER) |
| 6394 | #define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) |
| 6395 | #define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) |
| 6396 | #define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) |
| 6397 | #if defined(DUK_USE_ES6_PROXY) |
| 6398 | #define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) |
| 6399 | #endif |
| 6400 | #define DUK_HOBJECT_SET_SPECIAL_CALL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL) |
| 6401 | |
| 6402 | #define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE) |
| 6403 | #define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE) |
| 6404 | #define DUK_HOBJECT_CLEAR_CALLABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE) |
| 6405 | #define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC) |
| 6406 | #define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC) |
| 6407 | #define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC) |
| 6408 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 6409 | #define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ) |
| 6410 | #endif |
| 6411 | #define DUK_HOBJECT_CLEAR_FASTREFS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS) |
| 6412 | #define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART) |
| 6413 | #define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT) |
| 6414 | #define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL) |
| 6415 | #define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV) |
| 6416 | #define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING) |
| 6417 | #define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS) |
| 6418 | #define DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER) |
| 6419 | #define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY) |
| 6420 | #define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ) |
| 6421 | #define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS) |
| 6422 | #if defined(DUK_USE_ES6_PROXY) |
| 6423 | #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ) |
| 6424 | #endif |
| 6425 | #define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL) |
| 6426 | |
| 6427 | /* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond |
| 6428 | * duk_hobject base header. This is used just for asserts so doesn't need to |
| 6429 | * be optimized. |
| 6430 | */ |
| 6431 | #define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \ |
| 6432 | (DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \ |
| 6433 | DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \ |
| 6434 | DUK_HOBJECT_IS_BOUNDFUNC((h))) |
| 6435 | #define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h))) |
| 6436 | |
| 6437 | /* Flags used for property attributes in duk_propdesc and packed flags. |
| 6438 | * Must fit into 8 bits. |
| 6439 | */ |
| 6440 | #define DUK_PROPDESC_FLAG_WRITABLE (1U << 0) /* E5 Section 8.6.1 */ |
| 6441 | #define DUK_PROPDESC_FLAG_ENUMERABLE (1U << 1) /* E5 Section 8.6.1 */ |
| 6442 | #define DUK_PROPDESC_FLAG_CONFIGURABLE (1U << 2) /* E5 Section 8.6.1 */ |
| 6443 | #define DUK_PROPDESC_FLAG_ACCESSOR (1U << 3) /* accessor */ |
| 6444 | #define DUK_PROPDESC_FLAG_VIRTUAL (1U << 4) /* property is virtual: used in duk_propdesc, never stored |
| 6445 | * (used by e.g. buffer virtual properties) |
| 6446 | */ |
| 6447 | #define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \ |
| 6448 | DUK_PROPDESC_FLAG_ENUMERABLE | \ |
| 6449 | DUK_PROPDESC_FLAG_CONFIGURABLE | \ |
| 6450 | DUK_PROPDESC_FLAG_ACCESSOR) |
| 6451 | |
| 6452 | /* Additional flags which are passed in the same flags argument as property |
| 6453 | * flags but are not stored in object properties. |
| 6454 | */ |
| 6455 | #define DUK_PROPDESC_FLAG_NO_OVERWRITE (1U << 4) /* internal define property: skip write silently if exists */ |
| 6456 | |
| 6457 | /* Convenience defines for property attributes. */ |
| 6458 | #define DUK_PROPDESC_FLAGS_NONE 0 |
| 6459 | #define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE) |
| 6460 | #define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE) |
| 6461 | #define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE) |
| 6462 | #define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE) |
| 6463 | #define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) |
| 6464 | #define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE) |
| 6465 | #define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \ |
| 6466 | DUK_PROPDESC_FLAG_ENUMERABLE | \ |
| 6467 | DUK_PROPDESC_FLAG_CONFIGURABLE) |
| 6468 | |
| 6469 | /* Flags for duk_hobject_get_own_propdesc() and variants. */ |
| 6470 | #define DUK_GETDESC_FLAG_PUSH_VALUE (1U << 0) /* push value to stack */ |
| 6471 | #define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1U << 1) /* don't throw for prototype loop */ |
| 6472 | |
| 6473 | /* |
| 6474 | * Macro for object validity check |
| 6475 | * |
| 6476 | * Assert for currently guaranteed relations between flags, for instance. |
| 6477 | */ |
| 6478 | |
| 6479 | #if defined(DUK_USE_ASSERTIONS) |
| 6480 | DUK_INTERNAL_DECL void duk_hobject_assert_valid(duk_hobject *h); |
| 6481 | #define DUK_HOBJECT_ASSERT_VALID(h) do { duk_hobject_assert_valid((h)); } while (0) |
| 6482 | #else |
| 6483 | #define DUK_HOBJECT_ASSERT_VALID(h) do {} while (0) |
| 6484 | #endif |
| 6485 | |
| 6486 | /* |
| 6487 | * Macros to access the 'props' allocation. |
| 6488 | */ |
| 6489 | |
| 6490 | #if defined(DUK_USE_HEAPPTR16) |
| 6491 | #define DUK_HOBJECT_GET_PROPS(heap,h) \ |
| 6492 | ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16)) |
| 6493 | #define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ |
| 6494 | ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ |
| 6495 | } while (0) |
| 6496 | #else |
| 6497 | #define DUK_HOBJECT_GET_PROPS(heap,h) \ |
| 6498 | ((h)->props) |
| 6499 | #define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \ |
| 6500 | (h)->props = (duk_uint8_t *) (x); \ |
| 6501 | } while (0) |
| 6502 | #endif |
| 6503 | |
| 6504 | #if defined(DUK_USE_HOBJECT_LAYOUT_1) |
| 6505 | /* LAYOUT 1 */ |
| 6506 | #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ |
| 6507 | ((duk_hstring **) (void *) ( \ |
| 6508 | DUK_HOBJECT_GET_PROPS((heap), (h)) \ |
| 6509 | )) |
| 6510 | #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ |
| 6511 | ((duk_propvalue *) (void *) ( \ |
| 6512 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6513 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \ |
| 6514 | )) |
| 6515 | #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ |
| 6516 | ((duk_uint8_t *) (void *) ( \ |
| 6517 | DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ |
| 6518 | )) |
| 6519 | #define DUK_HOBJECT_A_GET_BASE(heap,h) \ |
| 6520 | ((duk_tval *) (void *) ( \ |
| 6521 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6522 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \ |
| 6523 | )) |
| 6524 | #define DUK_HOBJECT_H_GET_BASE(heap,h) \ |
| 6525 | ((duk_uint32_t *) (void *) ( \ |
| 6526 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6527 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ |
| 6528 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ |
| 6529 | )) |
| 6530 | #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ |
| 6531 | ( \ |
| 6532 | (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ |
| 6533 | (n_arr) * sizeof(duk_tval) + \ |
| 6534 | (n_hash) * sizeof(duk_uint32_t) \ |
| 6535 | ) |
| 6536 | #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 { \ |
| 6537 | (set_e_k) = (duk_hstring **) (void *) (p_base); \ |
| 6538 | (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \ |
| 6539 | (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \ |
| 6540 | (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \ |
| 6541 | (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ |
| 6542 | } while (0) |
| 6543 | #elif defined(DUK_USE_HOBJECT_LAYOUT_2) |
| 6544 | /* LAYOUT 2 */ |
| 6545 | #if (DUK_USE_ALIGN_BY == 4) |
| 6546 | #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03) |
| 6547 | #elif (DUK_USE_ALIGN_BY == 8) |
| 6548 | #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07) |
| 6549 | #elif (DUK_USE_ALIGN_BY == 1) |
| 6550 | #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0 |
| 6551 | #else |
| 6552 | #error invalid DUK_USE_ALIGN_BY |
| 6553 | #endif |
| 6554 | #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ |
| 6555 | ((duk_hstring **) (void *) ( \ |
| 6556 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6557 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ |
| 6558 | )) |
| 6559 | #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ |
| 6560 | ((duk_propvalue *) (void *) ( \ |
| 6561 | DUK_HOBJECT_GET_PROPS((heap), (h)) \ |
| 6562 | )) |
| 6563 | #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ |
| 6564 | ((duk_uint8_t *) (void *) ( \ |
| 6565 | DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \ |
| 6566 | )) |
| 6567 | #define DUK_HOBJECT_A_GET_BASE(heap,h) \ |
| 6568 | ((duk_tval *) (void *) ( \ |
| 6569 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6570 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ |
| 6571 | DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \ |
| 6572 | )) |
| 6573 | #define DUK_HOBJECT_H_GET_BASE(heap,h) \ |
| 6574 | ((duk_uint32_t *) (void *) ( \ |
| 6575 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6576 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ |
| 6577 | DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \ |
| 6578 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ |
| 6579 | )) |
| 6580 | #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ |
| 6581 | ( \ |
| 6582 | (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \ |
| 6583 | DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \ |
| 6584 | (n_arr) * sizeof(duk_tval) + \ |
| 6585 | (n_hash) * sizeof(duk_uint32_t) \ |
| 6586 | ) |
| 6587 | #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 { \ |
| 6588 | (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ |
| 6589 | (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \ |
| 6590 | (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \ |
| 6591 | (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \ |
| 6592 | sizeof(duk_uint8_t) * (n_ent) + \ |
| 6593 | DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \ |
| 6594 | (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \ |
| 6595 | } while (0) |
| 6596 | #elif defined(DUK_USE_HOBJECT_LAYOUT_3) |
| 6597 | /* LAYOUT 3 */ |
| 6598 | #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \ |
| 6599 | ((duk_hstring **) (void *) ( \ |
| 6600 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6601 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \ |
| 6602 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ |
| 6603 | )) |
| 6604 | #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \ |
| 6605 | ((duk_propvalue *) (void *) ( \ |
| 6606 | DUK_HOBJECT_GET_PROPS((heap), (h)) \ |
| 6607 | )) |
| 6608 | #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \ |
| 6609 | ((duk_uint8_t *) (void *) ( \ |
| 6610 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6611 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ |
| 6612 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \ |
| 6613 | DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \ |
| 6614 | )) |
| 6615 | #define DUK_HOBJECT_A_GET_BASE(heap,h) \ |
| 6616 | ((duk_tval *) (void *) ( \ |
| 6617 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6618 | DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \ |
| 6619 | )) |
| 6620 | #define DUK_HOBJECT_H_GET_BASE(heap,h) \ |
| 6621 | ((duk_uint32_t *) (void *) ( \ |
| 6622 | DUK_HOBJECT_GET_PROPS((heap), (h)) + \ |
| 6623 | DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \ |
| 6624 | DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \ |
| 6625 | )) |
| 6626 | #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \ |
| 6627 | ( \ |
| 6628 | (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \ |
| 6629 | (n_arr) * sizeof(duk_tval) + \ |
| 6630 | (n_hash) * sizeof(duk_uint32_t) \ |
| 6631 | ) |
| 6632 | #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 { \ |
| 6633 | (set_e_pv) = (duk_propvalue *) (void *) (p_base); \ |
| 6634 | (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \ |
| 6635 | (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \ |
| 6636 | (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \ |
| 6637 | (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \ |
| 6638 | } while (0) |
| 6639 | #else |
| 6640 | #error invalid hobject layout defines |
| 6641 | #endif /* hobject property layout */ |
| 6642 | |
| 6643 | #define DUK_HOBJECT_P_ALLOC_SIZE(h) \ |
| 6644 | DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h))) |
| 6645 | |
| 6646 | #define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) |
| 6647 | #define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)]) |
| 6648 | #define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) |
| 6649 | #define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)]) |
| 6650 | #define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) |
| 6651 | #define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v) |
| 6652 | #define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) |
| 6653 | #define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get) |
| 6654 | #define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) |
| 6655 | #define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set) |
| 6656 | #define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) |
| 6657 | #define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)]) |
| 6658 | #define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) |
| 6659 | #define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)]) |
| 6660 | #define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) |
| 6661 | #define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)]) |
| 6662 | |
| 6663 | #define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \ |
| 6664 | DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \ |
| 6665 | } while (0) |
| 6666 | #define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \ |
| 6667 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \ |
| 6668 | } while (0) |
| 6669 | #define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \ |
| 6670 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \ |
| 6671 | } while (0) |
| 6672 | #define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \ |
| 6673 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \ |
| 6674 | } while (0) |
| 6675 | #define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \ |
| 6676 | DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \ |
| 6677 | } while (0) |
| 6678 | #define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \ |
| 6679 | DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \ |
| 6680 | } while (0) |
| 6681 | #define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \ |
| 6682 | DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \ |
| 6683 | } while (0) |
| 6684 | #define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \ |
| 6685 | DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */ |
| 6686 | #define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \ |
| 6687 | DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \ |
| 6688 | } while (0) |
| 6689 | |
| 6690 | #define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \ |
| 6691 | DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \ |
| 6692 | } while (0) |
| 6693 | |
| 6694 | #define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \ |
| 6695 | DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \ |
| 6696 | } while (0) |
| 6697 | |
| 6698 | #define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0) |
| 6699 | #define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) |
| 6700 | #define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) |
| 6701 | #define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0) |
| 6702 | |
| 6703 | #define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) |
| 6704 | #define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) |
| 6705 | #define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) |
| 6706 | #define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) |
| 6707 | |
| 6708 | #define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE) |
| 6709 | #define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE) |
| 6710 | #define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE) |
| 6711 | #define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR) |
| 6712 | |
| 6713 | #define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0) |
| 6714 | #define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0) |
| 6715 | #define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0) |
| 6716 | #define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0) |
| 6717 | |
| 6718 | #define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL |
| 6719 | #define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL |
| 6720 | |
| 6721 | /* |
| 6722 | * Macros for accessing size fields |
| 6723 | */ |
| 6724 | |
| 6725 | #if defined(DUK_USE_OBJSIZES16) |
| 6726 | #define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16) |
| 6727 | #define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0) |
| 6728 | #define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16) |
| 6729 | #define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0) |
| 6730 | #define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++) |
| 6731 | #define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16) |
| 6732 | #define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0) |
| 6733 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 6734 | #define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16) |
| 6735 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0) |
| 6736 | #else |
| 6737 | #define DUK_HOBJECT_GET_HSIZE(h) 0 |
| 6738 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) |
| 6739 | #endif |
| 6740 | #else |
| 6741 | #define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size) |
| 6742 | #define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0) |
| 6743 | #define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next) |
| 6744 | #define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0) |
| 6745 | #define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++) |
| 6746 | #define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size) |
| 6747 | #define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0) |
| 6748 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 6749 | #define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size) |
| 6750 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0) |
| 6751 | #else |
| 6752 | #define DUK_HOBJECT_GET_HSIZE(h) 0 |
| 6753 | #define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0) |
| 6754 | #endif |
| 6755 | #endif |
| 6756 | |
| 6757 | /* |
| 6758 | * Misc |
| 6759 | */ |
| 6760 | |
| 6761 | /* Maximum prototype traversal depth. Sanity limit which handles e.g. |
| 6762 | * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4). |
| 6763 | */ |
| 6764 | #define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L |
| 6765 | |
| 6766 | /* |
| 6767 | * ECMAScript [[Class]] |
| 6768 | */ |
| 6769 | |
| 6770 | /* range check not necessary because all 4-bit values are mapped */ |
| 6771 | #define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)] |
| 6772 | |
| 6773 | #define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \ |
| 6774 | DUK_HEAP_GET_STRING( \ |
| 6775 | (heap), \ |
| 6776 | DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \ |
| 6777 | ) |
| 6778 | |
| 6779 | /* |
| 6780 | * Macros for property handling |
| 6781 | */ |
| 6782 | |
| 6783 | #if defined(DUK_USE_HEAPPTR16) |
| 6784 | #define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ |
| 6785 | ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16)) |
| 6786 | #define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ |
| 6787 | (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \ |
| 6788 | } while (0) |
| 6789 | #else |
| 6790 | #define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \ |
| 6791 | ((h)->prototype) |
| 6792 | #define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \ |
| 6793 | (h)->prototype = (x); \ |
| 6794 | } while (0) |
| 6795 | #endif |
| 6796 | |
| 6797 | /* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */ |
| 6798 | #define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p)) |
| 6799 | |
| 6800 | /* Set initial prototype, assume NULL previous prototype, INCREF new value, |
| 6801 | * tolerate NULL. |
| 6802 | */ |
| 6803 | #define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \ |
| 6804 | duk_hthread *duk__thr = (thr); \ |
| 6805 | duk_hobject *duk__obj = (h); \ |
| 6806 | duk_hobject *duk__proto = (proto); \ |
| 6807 | DUK_UNREF(duk__thr); \ |
| 6808 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \ |
| 6809 | DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \ |
| 6810 | DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \ |
| 6811 | } while (0) |
| 6812 | |
| 6813 | /* |
| 6814 | * Finalizer check |
| 6815 | */ |
| 6816 | |
| 6817 | #if defined(DUK_USE_HEAPPTR16) |
| 6818 | #define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((heap), (h)) |
| 6819 | #else |
| 6820 | #define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((h)) |
| 6821 | #endif |
| 6822 | |
| 6823 | /* |
| 6824 | * Resizing and hash behavior |
| 6825 | */ |
| 6826 | |
| 6827 | /* Sanity limit on max number of properties (allocated, not necessarily used). |
| 6828 | * This is somewhat arbitrary, but if we're close to 2**32 properties some |
| 6829 | * algorithms will fail (e.g. hash size selection, next prime selection). |
| 6830 | * Also, we use negative array/entry table indices to indicate 'not found', |
| 6831 | * so anything above 0x80000000 will cause trouble now. |
| 6832 | */ |
| 6833 | #if defined(DUK_USE_OBJSIZES16) |
| 6834 | #define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL |
| 6835 | #else |
| 6836 | #define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */ |
| 6837 | #endif |
| 6838 | |
| 6839 | /* internal align target for props allocation, must be 2*n for some n */ |
| 6840 | #if (DUK_USE_ALIGN_BY == 4) |
| 6841 | #define DUK_HOBJECT_ALIGN_TARGET 4 |
| 6842 | #elif (DUK_USE_ALIGN_BY == 8) |
| 6843 | #define DUK_HOBJECT_ALIGN_TARGET 8 |
| 6844 | #elif (DUK_USE_ALIGN_BY == 1) |
| 6845 | #define DUK_HOBJECT_ALIGN_TARGET 1 |
| 6846 | #else |
| 6847 | #error invalid DUK_USE_ALIGN_BY |
| 6848 | #endif |
| 6849 | |
| 6850 | /* |
| 6851 | * PC-to-line constants |
| 6852 | */ |
| 6853 | |
| 6854 | #define DUK_PC2LINE_SKIP 64 |
| 6855 | |
| 6856 | /* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */ |
| 6857 | #define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8) |
| 6858 | |
| 6859 | /* |
| 6860 | * Struct defs |
| 6861 | */ |
| 6862 | |
| 6863 | struct duk_propaccessor { |
| 6864 | duk_hobject *get; |
| 6865 | duk_hobject *set; |
| 6866 | }; |
| 6867 | |
| 6868 | union duk_propvalue { |
| 6869 | /* The get/set pointers could be 16-bit pointer compressed but it |
| 6870 | * would make no difference on 32-bit platforms because duk_tval is |
| 6871 | * 8 bytes or more anyway. |
| 6872 | */ |
| 6873 | duk_tval v; |
| 6874 | duk_propaccessor a; |
| 6875 | }; |
| 6876 | |
| 6877 | struct duk_propdesc { |
| 6878 | /* read-only values 'lifted' for ease of use */ |
| 6879 | duk_small_uint_t flags; |
| 6880 | duk_hobject *get; |
| 6881 | duk_hobject *set; |
| 6882 | |
| 6883 | /* for updating (all are set to < 0 for virtual properties) */ |
| 6884 | duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */ |
| 6885 | duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */ |
| 6886 | duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */ |
| 6887 | }; |
| 6888 | |
| 6889 | struct duk_hobject { |
| 6890 | duk_heaphdr hdr; |
| 6891 | |
| 6892 | /* |
| 6893 | * 'props' contains {key,value,flags} entries, optional array entries, and |
| 6894 | * an optional hash lookup table for non-array entries in a single 'sliced' |
| 6895 | * allocation. There are several layout options, which differ slightly in |
| 6896 | * generated code size/speed and alignment/padding; duk_features.h selects |
| 6897 | * the layout used. |
| 6898 | * |
| 6899 | * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1): |
| 6900 | * |
| 6901 | * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) |
| 6902 | * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) |
| 6903 | * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) |
| 6904 | * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) |
| 6905 | * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), |
| 6906 | * 0xffffffffUL = unused, 0xfffffffeUL = deleted |
| 6907 | * |
| 6908 | * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2): |
| 6909 | * |
| 6910 | * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) |
| 6911 | * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) |
| 6912 | * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable) |
| 6913 | * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) |
| 6914 | * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), |
| 6915 | * 0xffffffffUL = unused, 0xfffffffeUL = deleted |
| 6916 | * |
| 6917 | * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3): |
| 6918 | * |
| 6919 | * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable) |
| 6920 | * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable) |
| 6921 | * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable) |
| 6922 | * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size), |
| 6923 | * 0xffffffffUL = unused, 0xfffffffeUL = deleted |
| 6924 | * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable) |
| 6925 | * |
| 6926 | * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms |
| 6927 | * requiring 4 or 8 byte alignment. This ensures proper alignment |
| 6928 | * for the entries, at the cost of memory footprint. However, it's |
| 6929 | * probably preferable to use another layout on such platforms instead. |
| 6930 | * |
| 6931 | * In layout 2, the key and value parts are swapped to avoid padding |
| 6932 | * the key array on platforms requiring alignment by 8. The flags part |
| 6933 | * is padded to get alignment for array entries. The 'e_next' count does |
| 6934 | * not need to be rounded as in layout 1. |
| 6935 | * |
| 6936 | * In layout 3, entry values and array values are always aligned properly, |
| 6937 | * and assuming pointers are at most 8 bytes, so are the entry keys. Hash |
| 6938 | * indices will be properly aligned (assuming pointers are at least 4 bytes). |
| 6939 | * Finally, flags don't need additional alignment. This layout provides |
| 6940 | * compact allocations without padding (even on platforms with alignment |
| 6941 | * requirements) at the cost of a bit slower lookups. |
| 6942 | * |
| 6943 | * Objects with few keys don't have a hash index; keys are looked up linearly, |
| 6944 | * which is cache efficient because the keys are consecutive. Larger objects |
| 6945 | * have a hash index part which contains integer indexes to the entries part. |
| 6946 | * |
| 6947 | * A single allocation reduces memory allocation overhead but requires more |
| 6948 | * work when any part needs to be resized. A sliced allocation for entries |
| 6949 | * makes linear key matching faster on most platforms (more locality) and |
| 6950 | * skimps on flags size (which would be followed by 3 bytes of padding in |
| 6951 | * most architectures if entries were placed in a struct). |
| 6952 | * |
| 6953 | * 'props' also contains internal properties distinguished with a non-BMP |
| 6954 | * prefix. Often used properties should be placed early in 'props' whenever |
| 6955 | * possible to make accessing them as fast a possible. |
| 6956 | */ |
| 6957 | |
| 6958 | #if defined(DUK_USE_HEAPPTR16) |
| 6959 | /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like |
| 6960 | * duk_hcompfunc) are not free to use h_extra16 for this reason. |
| 6961 | */ |
| 6962 | #else |
| 6963 | duk_uint8_t *props; |
| 6964 | #endif |
| 6965 | |
| 6966 | /* prototype: the only internal property lifted outside 'e' as it is so central */ |
| 6967 | #if defined(DUK_USE_HEAPPTR16) |
| 6968 | duk_uint16_t prototype16; |
| 6969 | #else |
| 6970 | duk_hobject *prototype; |
| 6971 | #endif |
| 6972 | |
| 6973 | #if defined(DUK_USE_OBJSIZES16) |
| 6974 | duk_uint16_t e_size16; |
| 6975 | duk_uint16_t e_next16; |
| 6976 | duk_uint16_t a_size16; |
| 6977 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 6978 | duk_uint16_t h_size16; |
| 6979 | #endif |
| 6980 | #else |
| 6981 | duk_uint32_t e_size; /* entry part size */ |
| 6982 | duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */ |
| 6983 | duk_uint32_t a_size; /* array part size (entirely gc reachable) */ |
| 6984 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 6985 | duk_uint32_t h_size; /* hash part size or 0 if unused */ |
| 6986 | #endif |
| 6987 | #endif |
| 6988 | }; |
| 6989 | |
| 6990 | /* |
| 6991 | * Exposed data |
| 6992 | */ |
| 6993 | |
| 6994 | #if !defined(DUK_SINGLE_FILE) |
| 6995 | DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32]; |
| 6996 | #endif /* !DUK_SINGLE_FILE */ |
| 6997 | |
| 6998 | /* |
| 6999 | * Prototypes |
| 7000 | */ |
| 7001 | |
| 7002 | /* alloc and init */ |
| 7003 | DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags); |
| 7004 | DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7005 | DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7006 | DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7007 | DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7008 | DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags); |
| 7009 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 7010 | DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7011 | #endif |
| 7012 | DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags); |
| 7013 | DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7014 | DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7015 | DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7016 | DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags); |
| 7017 | |
| 7018 | /* resize */ |
| 7019 | DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr, |
| 7020 | duk_hobject *obj, |
| 7021 | duk_uint32_t new_e_size, |
| 7022 | duk_uint32_t new_a_size, |
| 7023 | duk_uint32_t new_h_size, |
| 7024 | duk_bool_t abandon_array); |
| 7025 | DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr, |
| 7026 | duk_hobject *obj, |
| 7027 | duk_uint32_t new_e_size); |
| 7028 | #if 0 /*unused*/ |
| 7029 | DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr, |
| 7030 | duk_hobject *obj, |
| 7031 | duk_uint32_t new_a_size); |
| 7032 | #endif |
| 7033 | |
| 7034 | /* low-level property functions */ |
| 7035 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_find_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx); |
| 7036 | DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key); |
| 7037 | DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr_stridx(duk_heap *heap, duk_hobject *obj, duk_small_uint_t stridx); |
| 7038 | DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs); |
| 7039 | DUK_INTERNAL_DECL duk_tval *duk_hobject_find_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i); |
| 7040 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags); |
| 7041 | |
| 7042 | /* core property functions */ |
| 7043 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); |
| 7044 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag); |
| 7045 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag); |
| 7046 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key); |
| 7047 | |
| 7048 | /* internal property functions */ |
| 7049 | #define DUK_DELPROP_FLAG_THROW (1U << 0) |
| 7050 | #define DUK_DELPROP_FLAG_FORCE (1U << 1) |
| 7051 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); |
| 7052 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key); |
| 7053 | DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags); |
| 7054 | DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags); |
| 7055 | DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); |
| 7056 | #if defined(DUK_USE_HEAPPTR16) |
| 7057 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj); |
| 7058 | #else |
| 7059 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj); |
| 7060 | #endif |
| 7061 | |
| 7062 | /* helpers for defineProperty() and defineProperties() */ |
| 7063 | DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr, |
| 7064 | duk_idx_t idx_in, |
| 7065 | duk_uint_t *out_defprop_flags, |
| 7066 | duk_idx_t *out_idx_value, |
| 7067 | duk_hobject **out_getter, |
| 7068 | duk_hobject **out_setter); |
| 7069 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr, |
| 7070 | duk_uint_t defprop_flags, |
| 7071 | duk_hobject *obj, |
| 7072 | duk_hstring *key, |
| 7073 | duk_idx_t idx_value, |
| 7074 | duk_hobject *get, |
| 7075 | duk_hobject *set, |
| 7076 | duk_bool_t throw_flag); |
| 7077 | |
| 7078 | /* Object built-in methods */ |
| 7079 | DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx); |
| 7080 | DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze); |
| 7081 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen); |
| 7082 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags); |
| 7083 | |
| 7084 | /* internal properties */ |
| 7085 | DUK_INTERNAL_DECL duk_tval *duk_hobject_get_internal_value_tval_ptr(duk_heap *heap, duk_hobject *obj); |
| 7086 | DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj); |
| 7087 | DUK_INTERNAL_DECL duk_harray *duk_hobject_get_formals(duk_hthread *thr, duk_hobject *obj); |
| 7088 | DUK_INTERNAL_DECL duk_hobject *duk_hobject_get_varmap(duk_hthread *thr, duk_hobject *obj); |
| 7089 | |
| 7090 | /* hobject management functions */ |
| 7091 | DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj); |
| 7092 | |
| 7093 | /* ES2015 proxy */ |
| 7094 | #if defined(DUK_USE_ES6_PROXY) |
| 7095 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler); |
| 7096 | DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj); |
| 7097 | #endif |
| 7098 | |
| 7099 | /* enumeration */ |
| 7100 | DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags); |
| 7101 | DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags); |
| 7102 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value); |
| 7103 | |
| 7104 | /* macros */ |
| 7105 | DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p); |
| 7106 | |
| 7107 | /* pc2line */ |
| 7108 | #if defined(DUK_USE_PC2LINE) |
| 7109 | DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length); |
| 7110 | DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc); |
| 7111 | #endif |
| 7112 | |
| 7113 | /* misc */ |
| 7114 | DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop); |
| 7115 | |
| 7116 | #if !defined(DUK_USE_OBJECT_BUILTIN) |
| 7117 | /* These declarations are needed when related built-in is disabled and |
| 7118 | * genbuiltins.py won't automatically emit the declerations. |
| 7119 | */ |
| 7120 | DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr); |
| 7121 | DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr); |
| 7122 | #endif |
| 7123 | |
| 7124 | #endif /* DUK_HOBJECT_H_INCLUDED */ |
| 7125 | /* #include duk_hcompfunc.h */ |
| 7126 | #line 1 "duk_hcompfunc.h" |
| 7127 | /* |
| 7128 | * Heap compiled function (ECMAScript function) representation. |
| 7129 | * |
| 7130 | * There is a single data buffer containing the ECMAScript function's |
| 7131 | * bytecode, constants, and inner functions. |
| 7132 | */ |
| 7133 | |
| 7134 | #if !defined(DUK_HCOMPFUNC_H_INCLUDED) |
| 7135 | #define DUK_HCOMPFUNC_H_INCLUDED |
| 7136 | |
| 7137 | /* |
| 7138 | * Field accessor macros |
| 7139 | */ |
| 7140 | |
| 7141 | /* XXX: casts could be improved, especially for GET/SET DATA */ |
| 7142 | |
| 7143 | #if defined(DUK_USE_HEAPPTR16) |
| 7144 | #define DUK_HCOMPFUNC_GET_DATA(heap,h) \ |
| 7145 | ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16)) |
| 7146 | #define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ |
| 7147 | (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ |
| 7148 | } while (0) |
| 7149 | #define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \ |
| 7150 | ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16))) |
| 7151 | #define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ |
| 7152 | (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ |
| 7153 | } while (0) |
| 7154 | #define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \ |
| 7155 | ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16))) |
| 7156 | #define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ |
| 7157 | (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ |
| 7158 | } while (0) |
| 7159 | #define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \ |
| 7160 | ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16))) |
| 7161 | #define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ |
| 7162 | (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ |
| 7163 | } while (0) |
| 7164 | #define DUK_HCOMPFUNC_GET_VARENV(heap,h) \ |
| 7165 | ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16))) |
| 7166 | #define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ |
| 7167 | (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ |
| 7168 | } while (0) |
| 7169 | #else |
| 7170 | #define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data) |
| 7171 | #define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ |
| 7172 | (h)->data = (duk_hbuffer *) (v); \ |
| 7173 | } while (0) |
| 7174 | #define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs) |
| 7175 | #define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ |
| 7176 | (h)->funcs = (v); \ |
| 7177 | } while (0) |
| 7178 | #define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode) |
| 7179 | #define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ |
| 7180 | (h)->bytecode = (v); \ |
| 7181 | } while (0) |
| 7182 | #define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env) |
| 7183 | #define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ |
| 7184 | (h)->lex_env = (v); \ |
| 7185 | } while (0) |
| 7186 | #define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env) |
| 7187 | #define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ |
| 7188 | (h)->var_env = (v); \ |
| 7189 | } while (0) |
| 7190 | #endif |
| 7191 | |
| 7192 | /* |
| 7193 | * Accessor macros for function specific data areas |
| 7194 | */ |
| 7195 | |
| 7196 | /* Note: assumes 'data' is always a fixed buffer */ |
| 7197 | #define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \ |
| 7198 | DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) |
| 7199 | |
| 7200 | #define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \ |
| 7201 | ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h))) |
| 7202 | |
| 7203 | #define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \ |
| 7204 | DUK_HCOMPFUNC_GET_FUNCS((heap), (h)) |
| 7205 | |
| 7206 | #define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \ |
| 7207 | DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)) |
| 7208 | |
| 7209 | #define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \ |
| 7210 | ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h))) |
| 7211 | |
| 7212 | #define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \ |
| 7213 | ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))) |
| 7214 | |
| 7215 | /* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */ |
| 7216 | #define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \ |
| 7217 | ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \ |
| 7218 | DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h)))) |
| 7219 | |
| 7220 | #define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \ |
| 7221 | ( \ |
| 7222 | (duk_size_t) \ |
| 7223 | ( \ |
| 7224 | ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \ |
| 7225 | ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \ |
| 7226 | ) \ |
| 7227 | ) |
| 7228 | |
| 7229 | #define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \ |
| 7230 | ( \ |
| 7231 | (duk_size_t) \ |
| 7232 | ( \ |
| 7233 | ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \ |
| 7234 | ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \ |
| 7235 | ) \ |
| 7236 | ) |
| 7237 | |
| 7238 | #define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \ |
| 7239 | ( \ |
| 7240 | (duk_size_t) \ |
| 7241 | ( \ |
| 7242 | ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \ |
| 7243 | ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \ |
| 7244 | ) \ |
| 7245 | ) |
| 7246 | |
| 7247 | #define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \ |
| 7248 | ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval))) |
| 7249 | |
| 7250 | #define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \ |
| 7251 | ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *))) |
| 7252 | |
| 7253 | #define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \ |
| 7254 | ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t))) |
| 7255 | |
| 7256 | /* |
| 7257 | * Validity assert |
| 7258 | */ |
| 7259 | |
| 7260 | #if defined(DUK_USE_ASSERTIONS) |
| 7261 | DUK_INTERNAL_DECL void duk_hcompfunc_assert_valid(duk_hcompfunc *h); |
| 7262 | #define DUK_HCOMPFUNC_ASSERT_VALID(h) do { duk_hcompfunc_assert_valid((h)); } while (0) |
| 7263 | #else |
| 7264 | #define DUK_HCOMPFUNC_ASSERT_VALID(h) do {} while (0) |
| 7265 | #endif |
| 7266 | |
| 7267 | /* |
| 7268 | * Main struct |
| 7269 | */ |
| 7270 | |
| 7271 | struct duk_hcompfunc { |
| 7272 | /* shared object part */ |
| 7273 | duk_hobject obj; |
| 7274 | |
| 7275 | /* |
| 7276 | * Pointers to function data area for faster access. Function |
| 7277 | * data is a buffer shared between all closures of the same |
| 7278 | * "template" function. The data buffer is always fixed (non- |
| 7279 | * dynamic, hence stable), with a layout as follows: |
| 7280 | * |
| 7281 | * constants (duk_tval) |
| 7282 | * inner functions (duk_hobject *) |
| 7283 | * bytecode (duk_instr_t) |
| 7284 | * |
| 7285 | * Note: bytecode end address can be computed from 'data' buffer |
| 7286 | * size. It is not strictly necessary functionally, assuming |
| 7287 | * bytecode never jumps outside its allocated area. However, |
| 7288 | * it's a safety/robustness feature for avoiding the chance of |
| 7289 | * executing random data as bytecode due to a compiler error. |
| 7290 | * |
| 7291 | * Note: values in the data buffer must be incref'd (they will |
| 7292 | * be decref'd on release) for every compiledfunction referring |
| 7293 | * to the 'data' element. |
| 7294 | */ |
| 7295 | |
| 7296 | /* Data area, fixed allocation, stable data ptrs. */ |
| 7297 | #if defined(DUK_USE_HEAPPTR16) |
| 7298 | duk_uint16_t data16; |
| 7299 | #else |
| 7300 | duk_hbuffer *data; |
| 7301 | #endif |
| 7302 | |
| 7303 | /* No need for constants pointer (= same as data). |
| 7304 | * |
| 7305 | * When using 16-bit packing alignment to 4 is nice. 'funcs' will be |
| 7306 | * 4-byte aligned because 'constants' are duk_tvals. For now the |
| 7307 | * inner function pointers are not compressed, so that 'bytecode' will |
| 7308 | * also be 4-byte aligned. |
| 7309 | */ |
| 7310 | #if defined(DUK_USE_HEAPPTR16) |
| 7311 | duk_uint16_t funcs16; |
| 7312 | duk_uint16_t bytecode16; |
| 7313 | #else |
| 7314 | duk_hobject **funcs; |
| 7315 | duk_instr_t *bytecode; |
| 7316 | #endif |
| 7317 | |
| 7318 | /* Lexenv: lexical environment of closure, NULL for templates. |
| 7319 | * Varenv: variable environment of closure, NULL for templates. |
| 7320 | */ |
| 7321 | #if defined(DUK_USE_HEAPPTR16) |
| 7322 | duk_uint16_t lex_env16; |
| 7323 | duk_uint16_t var_env16; |
| 7324 | #else |
| 7325 | duk_hobject *lex_env; |
| 7326 | duk_hobject *var_env; |
| 7327 | #endif |
| 7328 | |
| 7329 | /* |
| 7330 | * 'nregs' registers are allocated on function entry, at most 'nargs' |
| 7331 | * are initialized to arguments, and the rest to undefined. Arguments |
| 7332 | * above 'nregs' are not mapped to registers. All registers in the |
| 7333 | * active stack range must be initialized because they are GC reachable. |
| 7334 | * 'nargs' is needed so that if the function is given more than 'nargs' |
| 7335 | * arguments, the additional arguments do not 'clobber' registers |
| 7336 | * beyond 'nregs' which must be consistently initialized to undefined. |
| 7337 | * |
| 7338 | * Usually there is no need to know which registers are mapped to |
| 7339 | * local variables. Registers may be allocated to variable in any |
| 7340 | * way (even including gaps). However, a register-variable mapping |
| 7341 | * must be the same for the duration of the function execution and |
| 7342 | * the register cannot be used for anything else. |
| 7343 | * |
| 7344 | * When looking up variables by name, the '_Varmap' map is used. |
| 7345 | * When an activation closes, registers mapped to arguments are |
| 7346 | * copied into the environment record based on the same map. The |
| 7347 | * reverse map (from register to variable) is not currently needed |
| 7348 | * at run time, except for debugging, so it is not maintained. |
| 7349 | */ |
| 7350 | |
| 7351 | duk_uint16_t nregs; /* regs to allocate */ |
| 7352 | duk_uint16_t nargs; /* number of arguments allocated to regs */ |
| 7353 | |
| 7354 | /* |
| 7355 | * Additional control information is placed into the object itself |
| 7356 | * as internal properties to avoid unnecessary fields for the |
| 7357 | * majority of functions. The compiler tries to omit internal |
| 7358 | * control fields when possible. |
| 7359 | * |
| 7360 | * Function templates: |
| 7361 | * |
| 7362 | * { |
| 7363 | * name: "func", // declaration, named function expressions |
| 7364 | * fileName: <debug info for creating nice errors> |
| 7365 | * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, |
| 7366 | * _Formals: [ "arg1", "arg2" ], |
| 7367 | * _Source: "function func(arg1, arg2) { ... }", |
| 7368 | * _Pc2line: <debug info for pc-to-line mapping>, |
| 7369 | * } |
| 7370 | * |
| 7371 | * Function instances: |
| 7372 | * |
| 7373 | * { |
| 7374 | * length: 2, |
| 7375 | * prototype: { constructor: <func> }, |
| 7376 | * caller: <thrower>, |
| 7377 | * arguments: <thrower>, |
| 7378 | * name: "func", // declaration, named function expressions |
| 7379 | * fileName: <debug info for creating nice errors> |
| 7380 | * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, |
| 7381 | * _Formals: [ "arg1", "arg2" ], |
| 7382 | * _Source: "function func(arg1, arg2) { ... }", |
| 7383 | * _Pc2line: <debug info for pc-to-line mapping>, |
| 7384 | * } |
| 7385 | * |
| 7386 | * More detailed description of these properties can be found |
| 7387 | * in the documentation. |
| 7388 | */ |
| 7389 | |
| 7390 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 7391 | /* Line number range for function. Needed during debugging to |
| 7392 | * determine active breakpoints. |
| 7393 | */ |
| 7394 | duk_uint32_t start_line; |
| 7395 | duk_uint32_t end_line; |
| 7396 | #endif |
| 7397 | }; |
| 7398 | |
| 7399 | #endif /* DUK_HCOMPFUNC_H_INCLUDED */ |
| 7400 | /* #include duk_hnatfunc.h */ |
| 7401 | #line 1 "duk_hnatfunc.h" |
| 7402 | /* |
| 7403 | * Heap native function representation. |
| 7404 | */ |
| 7405 | |
| 7406 | #if !defined(DUK_HNATFUNC_H_INCLUDED) |
| 7407 | #define DUK_HNATFUNC_H_INCLUDED |
| 7408 | |
| 7409 | #if defined(DUK_USE_ASSERTIONS) |
| 7410 | DUK_INTERNAL_DECL void duk_hnatfunc_assert_valid(duk_hnatfunc *h); |
| 7411 | #define DUK_HNATFUNC_ASSERT_VALID(h) do { duk_hnatfunc_assert_valid((h)); } while (0) |
| 7412 | #else |
| 7413 | #define DUK_HNATFUNC_ASSERT_VALID(h) do {} while (0) |
| 7414 | #endif |
| 7415 | |
| 7416 | #define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1) |
| 7417 | #define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff) |
| 7418 | |
| 7419 | struct duk_hnatfunc { |
| 7420 | /* shared object part */ |
| 7421 | duk_hobject obj; |
| 7422 | |
| 7423 | duk_c_function func; |
| 7424 | duk_int16_t nargs; |
| 7425 | duk_int16_t magic; |
| 7426 | |
| 7427 | /* The 'magic' field allows an opaque 16-bit field to be accessed by the |
| 7428 | * Duktape/C function. This allows, for instance, the same native function |
| 7429 | * to be used for a set of very similar functions, with the 'magic' field |
| 7430 | * providing the necessary non-argument flags / values to guide the behavior |
| 7431 | * of the native function. The value is signed on purpose: it is easier to |
| 7432 | * convert a signed value to unsigned (simply AND with 0xffff) than vice |
| 7433 | * versa. |
| 7434 | * |
| 7435 | * Note: cannot place nargs/magic into the heaphdr flags, because |
| 7436 | * duk_hobject takes almost all flags already. |
| 7437 | */ |
| 7438 | }; |
| 7439 | |
| 7440 | #endif /* DUK_HNATFUNC_H_INCLUDED */ |
| 7441 | /* #include duk_hboundfunc.h */ |
| 7442 | #line 1 "duk_hboundfunc.h" |
| 7443 | /* |
| 7444 | * Bound function representation. |
| 7445 | */ |
| 7446 | |
| 7447 | #if !defined(DUK_HBOUNDFUNC_H_INCLUDED) |
| 7448 | #define DUK_HBOUNDFUNC_H_INCLUDED |
| 7449 | |
| 7450 | /* Artificial limit for args length. Ensures arithmetic won't overflow |
| 7451 | * 32 bits when combining bound functions. |
| 7452 | */ |
| 7453 | #define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL |
| 7454 | |
| 7455 | #if defined(DUK_USE_ASSERTIONS) |
| 7456 | DUK_INTERNAL_DECL void duk_hboundfunc_assert_valid(duk_hboundfunc *h); |
| 7457 | #define DUK_HBOUNDFUNC_ASSERT_VALID(h) do { duk_hboundfunc_assert_valid((h)); } while (0) |
| 7458 | #else |
| 7459 | #define DUK_HBOUNDFUNC_ASSERT_VALID(h) do {} while (0) |
| 7460 | #endif |
| 7461 | |
| 7462 | struct duk_hboundfunc { |
| 7463 | /* Shared object part. */ |
| 7464 | duk_hobject obj; |
| 7465 | |
| 7466 | /* Final target function, stored as duk_tval so that lightfunc can be |
| 7467 | * represented too. |
| 7468 | */ |
| 7469 | duk_tval target; |
| 7470 | |
| 7471 | /* This binding. */ |
| 7472 | duk_tval this_binding; |
| 7473 | |
| 7474 | /* Arguments to prepend. */ |
| 7475 | duk_tval *args; /* Separate allocation. */ |
| 7476 | duk_idx_t nargs; |
| 7477 | }; |
| 7478 | |
| 7479 | #endif /* DUK_HBOUNDFUNC_H_INCLUDED */ |
| 7480 | /* #include duk_hbufobj.h */ |
| 7481 | #line 1 "duk_hbufobj.h" |
| 7482 | /* |
| 7483 | * Heap Buffer object representation. Used for all Buffer variants. |
| 7484 | */ |
| 7485 | |
| 7486 | #if !defined(DUK_HBUFOBJ_H_INCLUDED) |
| 7487 | #define DUK_HBUFOBJ_H_INCLUDED |
| 7488 | |
| 7489 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 7490 | |
| 7491 | /* All element accessors are host endian now (driven by TypedArray spec). */ |
| 7492 | #define DUK_HBUFOBJ_ELEM_UINT8 0 |
| 7493 | #define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1 |
| 7494 | #define DUK_HBUFOBJ_ELEM_INT8 2 |
| 7495 | #define DUK_HBUFOBJ_ELEM_UINT16 3 |
| 7496 | #define DUK_HBUFOBJ_ELEM_INT16 4 |
| 7497 | #define DUK_HBUFOBJ_ELEM_UINT32 5 |
| 7498 | #define DUK_HBUFOBJ_ELEM_INT32 6 |
| 7499 | #define DUK_HBUFOBJ_ELEM_FLOAT32 7 |
| 7500 | #define DUK_HBUFOBJ_ELEM_FLOAT64 8 |
| 7501 | #define DUK_HBUFOBJ_ELEM_MAX 8 |
| 7502 | |
| 7503 | #if defined(DUK_USE_ASSERTIONS) |
| 7504 | DUK_INTERNAL_DECL void duk_hbufobj_assert_valid(duk_hbufobj *h); |
| 7505 | #define DUK_HBUFOBJ_ASSERT_VALID(h) do { duk_hbufobj_assert_valid((h)); } while (0) |
| 7506 | #else |
| 7507 | #define DUK_HBUFOBJ_ASSERT_VALID(h) do {} while (0) |
| 7508 | #endif |
| 7509 | |
| 7510 | /* Get the current data pointer (caller must ensure buf != NULL) as a |
| 7511 | * duk_uint8_t ptr. Note that the result may be NULL if the underlying |
| 7512 | * buffer has zero size and is not a fixed buffer. |
| 7513 | */ |
| 7514 | #define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \ |
| 7515 | (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ |
| 7516 | (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset)) |
| 7517 | |
| 7518 | /* True if slice is full, i.e. offset is zero and length covers the entire |
| 7519 | * buffer. This status may change independently of the duk_hbufobj if |
| 7520 | * the underlying buffer is dynamic and changes without the hbufobj |
| 7521 | * being changed. |
| 7522 | */ |
| 7523 | #define DUK_HBUFOBJ_FULL_SLICE(h) \ |
| 7524 | (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ |
| 7525 | ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf))) |
| 7526 | |
| 7527 | /* Validate that the whole slice [0,length[ is contained in the underlying |
| 7528 | * buffer. Caller must ensure 'buf' != NULL. |
| 7529 | */ |
| 7530 | #define DUK_HBUFOBJ_VALID_SLICE(h) \ |
| 7531 | (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ |
| 7532 | ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf))) |
| 7533 | |
| 7534 | /* Validate byte read/write for virtual 'offset', i.e. check that the |
| 7535 | * offset, taking into account h->offset, is within the underlying |
| 7536 | * buffer size. This is a safety check which is needed to ensure |
| 7537 | * that even a misconfigured duk_hbufobj never causes memory unsafe |
| 7538 | * behavior (e.g. if an underlying dynamic buffer changes after being |
| 7539 | * setup). Caller must ensure 'buf' != NULL. |
| 7540 | */ |
| 7541 | #define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \ |
| 7542 | (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ |
| 7543 | ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf))) |
| 7544 | |
| 7545 | #define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \ |
| 7546 | (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \ |
| 7547 | ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf))) |
| 7548 | |
| 7549 | /* Clamp an input byte length (already assumed to be within the nominal |
| 7550 | * duk_hbufobj 'length') to the current dynamic buffer limits to yield |
| 7551 | * a byte length limit that's safe for memory accesses. This value can |
| 7552 | * be invalidated by any side effect because it may trigger a user |
| 7553 | * callback that resizes the underlying buffer. |
| 7554 | */ |
| 7555 | #define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \ |
| 7556 | (DUK_ASSERT_EXPR((h) != NULL), \ |
| 7557 | duk_hbufobj_clamp_bytelength((h), (len))) |
| 7558 | |
| 7559 | /* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */ |
| 7560 | #define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray) |
| 7561 | |
| 7562 | struct duk_hbufobj { |
| 7563 | /* Shared object part. */ |
| 7564 | duk_hobject obj; |
| 7565 | |
| 7566 | /* Underlying buffer (refcounted), may be NULL. */ |
| 7567 | duk_hbuffer *buf; |
| 7568 | |
| 7569 | /* .buffer reference to an ArrayBuffer, may be NULL. */ |
| 7570 | duk_hobject *buf_prop; |
| 7571 | |
| 7572 | /* Slice and accessor information. |
| 7573 | * |
| 7574 | * Because the underlying buffer may be dynamic, these may be |
| 7575 | * invalidated by the buffer being modified so that both offset |
| 7576 | * and length should be validated before every access. Behavior |
| 7577 | * when the underlying buffer has changed doesn't need to be clean: |
| 7578 | * virtual 'length' doesn't need to be affected, reads can return |
| 7579 | * zero/NaN, and writes can be ignored. |
| 7580 | * |
| 7581 | * Note that a data pointer cannot be precomputed because 'buf' may |
| 7582 | * be dynamic and its pointer unstable. |
| 7583 | */ |
| 7584 | |
| 7585 | duk_uint_t offset; /* byte offset to buf */ |
| 7586 | duk_uint_t length; /* byte index limit for element access, exclusive */ |
| 7587 | duk_uint8_t shift; /* element size shift: |
| 7588 | * 0 = u8/i8 |
| 7589 | * 1 = u16/i16 |
| 7590 | * 2 = u32/i32/float |
| 7591 | * 3 = double |
| 7592 | */ |
| 7593 | duk_uint8_t elem_type; /* element type */ |
| 7594 | duk_uint8_t is_typedarray; |
| 7595 | }; |
| 7596 | |
| 7597 | DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len); |
| 7598 | DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf); |
| 7599 | DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); |
| 7600 | DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size); |
| 7601 | DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx); |
| 7602 | |
| 7603 | #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 7604 | |
| 7605 | /* nothing */ |
| 7606 | |
| 7607 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 7608 | #endif /* DUK_HBUFOBJ_H_INCLUDED */ |
| 7609 | /* #include duk_hthread.h */ |
| 7610 | #line 1 "duk_hthread.h" |
| 7611 | /* |
| 7612 | * Heap thread object representation. |
| 7613 | * |
| 7614 | * duk_hthread is also the 'context' for public API functions via a |
| 7615 | * different typedef. Most API calls operate on the topmost frame |
| 7616 | * of the value stack only. |
| 7617 | */ |
| 7618 | |
| 7619 | #if !defined(DUK_HTHREAD_H_INCLUDED) |
| 7620 | #define DUK_HTHREAD_H_INCLUDED |
| 7621 | |
| 7622 | /* |
| 7623 | * Stack constants |
| 7624 | */ |
| 7625 | |
| 7626 | /* Initial valstack size, roughly 0.7kiB. */ |
| 7627 | #define DUK_VALSTACK_INITIAL_SIZE 96U |
| 7628 | |
| 7629 | /* Internal extra elements assumed on function entry, always added to |
| 7630 | * user-defined 'extra' for e.g. the duk_check_stack() call. |
| 7631 | */ |
| 7632 | #define 32U |
| 7633 | |
| 7634 | /* Number of elements guaranteed to be user accessible (in addition to call |
| 7635 | * arguments) on Duktape/C function entry. This is the major public API |
| 7636 | * commitment. |
| 7637 | */ |
| 7638 | #define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK |
| 7639 | |
| 7640 | /* |
| 7641 | * Activation defines |
| 7642 | */ |
| 7643 | |
| 7644 | #define DUK_ACT_FLAG_STRICT (1U << 0) /* function executes in strict mode */ |
| 7645 | #define DUK_ACT_FLAG_TAILCALLED (1U << 1) /* activation has tail called one or more times */ |
| 7646 | #define DUK_ACT_FLAG_CONSTRUCT (1U << 2) /* function executes as a constructor (called via "new") */ |
| 7647 | #define DUK_ACT_FLAG_PREVENT_YIELD (1U << 3) /* activation prevents yield (native call or "new") */ |
| 7648 | #define DUK_ACT_FLAG_DIRECT_EVAL (1U << 4) /* activation is a direct eval call */ |
| 7649 | #define DUK_ACT_FLAG_CONSTRUCT_PROXY (1U << 5) /* activation is for Proxy 'construct' call, special return value handling */ |
| 7650 | #define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1U << 6) /* activation has active breakpoint(s) */ |
| 7651 | |
| 7652 | #define DUK_ACT_GET_FUNC(act) ((act)->func) |
| 7653 | |
| 7654 | /* |
| 7655 | * Flags for __FILE__ / __LINE__ registered into tracedata |
| 7656 | */ |
| 7657 | |
| 7658 | #define DUK_TB_FLAG_NOBLAME_FILELINE (1U << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */ |
| 7659 | |
| 7660 | /* |
| 7661 | * Catcher defines |
| 7662 | */ |
| 7663 | |
| 7664 | /* XXX: remove catcher type entirely */ |
| 7665 | |
| 7666 | /* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */ |
| 7667 | #define DUK_CAT_TYPE_MASK 0x0000000fUL |
| 7668 | #define DUK_CAT_TYPE_BITS 4 |
| 7669 | #define DUK_CAT_LABEL_MASK 0xffffff00UL |
| 7670 | #define DUK_CAT_LABEL_BITS 24 |
| 7671 | #define DUK_CAT_LABEL_SHIFT 8 |
| 7672 | |
| 7673 | #define DUK_CAT_FLAG_CATCH_ENABLED (1U << 4) /* catch part will catch */ |
| 7674 | #define DUK_CAT_FLAG_FINALLY_ENABLED (1U << 5) /* finally part will catch */ |
| 7675 | #define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1U << 6) /* request to create catch binding */ |
| 7676 | #define DUK_CAT_FLAG_LEXENV_ACTIVE (1U << 7) /* catch or with binding is currently active */ |
| 7677 | |
| 7678 | #define DUK_CAT_TYPE_UNKNOWN 0 |
| 7679 | #define DUK_CAT_TYPE_TCF 1 |
| 7680 | #define DUK_CAT_TYPE_LABEL 2 |
| 7681 | |
| 7682 | #define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK) |
| 7683 | #define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT) |
| 7684 | |
| 7685 | #define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED) |
| 7686 | #define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED) |
| 7687 | #define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED) |
| 7688 | #define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE) |
| 7689 | |
| 7690 | #define DUK_CAT_SET_CATCH_ENABLED(c) do { \ |
| 7691 | (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \ |
| 7692 | } while (0) |
| 7693 | #define DUK_CAT_SET_FINALLY_ENABLED(c) do { \ |
| 7694 | (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \ |
| 7695 | } while (0) |
| 7696 | #define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \ |
| 7697 | (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \ |
| 7698 | } while (0) |
| 7699 | #define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \ |
| 7700 | (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \ |
| 7701 | } while (0) |
| 7702 | |
| 7703 | #define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \ |
| 7704 | (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \ |
| 7705 | } while (0) |
| 7706 | #define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \ |
| 7707 | (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \ |
| 7708 | } while (0) |
| 7709 | #define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \ |
| 7710 | (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \ |
| 7711 | } while (0) |
| 7712 | #define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \ |
| 7713 | (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \ |
| 7714 | } while (0) |
| 7715 | |
| 7716 | /* |
| 7717 | * Thread defines |
| 7718 | */ |
| 7719 | |
| 7720 | #if defined(DUK_USE_ROM_STRINGS) |
| 7721 | #define DUK_HTHREAD_GET_STRING(thr,idx) \ |
| 7722 | ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) |
| 7723 | #else /* DUK_USE_ROM_STRINGS */ |
| 7724 | #if defined(DUK_USE_HEAPPTR16) |
| 7725 | #define DUK_HTHREAD_GET_STRING(thr,idx) \ |
| 7726 | ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)])) |
| 7727 | #else |
| 7728 | #define DUK_HTHREAD_GET_STRING(thr,idx) \ |
| 7729 | ((thr)->strs[(idx)]) |
| 7730 | #endif |
| 7731 | #endif /* DUK_USE_ROM_STRINGS */ |
| 7732 | |
| 7733 | /* values for the state field */ |
| 7734 | #define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */ |
| 7735 | #define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */ |
| 7736 | #define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */ |
| 7737 | #define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */ |
| 7738 | #define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */ |
| 7739 | |
| 7740 | /* Executor interrupt default interval when nothing else requires a |
| 7741 | * smaller value. The default interval must be small enough to allow |
| 7742 | * for reasonable execution timeout checking but large enough to keep |
| 7743 | * impact on execution performance low. |
| 7744 | */ |
| 7745 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 7746 | #define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L) |
| 7747 | #endif |
| 7748 | |
| 7749 | /* |
| 7750 | * Assert context is valid: non-NULL pointer, fields look sane. |
| 7751 | * |
| 7752 | * This is used by public API call entrypoints to catch invalid 'ctx' pointers |
| 7753 | * as early as possible; invalid 'ctx' pointers cause very odd and difficult to |
| 7754 | * diagnose behavior so it's worth checking even when the check is not 100%. |
| 7755 | */ |
| 7756 | |
| 7757 | #if defined(DUK_USE_ASSERTIONS) |
| 7758 | /* Assertions for internals. */ |
| 7759 | DUK_INTERNAL_DECL void duk_hthread_assert_valid(duk_hthread *thr); |
| 7760 | #define DUK_HTHREAD_ASSERT_VALID(thr) do { duk_hthread_assert_valid((thr)); } while (0) |
| 7761 | |
| 7762 | /* Assertions for public API calls; a bit stronger. */ |
| 7763 | DUK_INTERNAL_DECL void duk_ctx_assert_valid(duk_hthread *thr); |
| 7764 | #define DUK_CTX_ASSERT_VALID(thr) do { duk_ctx_assert_valid((thr)); } while (0) |
| 7765 | #else |
| 7766 | #define DUK_HTHREAD_ASSERT_VALID(thr) do {} while (0) |
| 7767 | #define DUK_CTX_ASSERT_VALID(thr) do {} while (0) |
| 7768 | #endif |
| 7769 | |
| 7770 | /* Assertions for API call entry specifically. Checks 'ctx' but also may |
| 7771 | * check internal state (e.g. not in a debugger transport callback). |
| 7772 | */ |
| 7773 | #define DUK_ASSERT_API_ENTRY(thr) do { \ |
| 7774 | DUK_CTX_ASSERT_VALID((thr)); \ |
| 7775 | DUK_ASSERT((thr)->heap != NULL); \ |
| 7776 | DUK_ASSERT((thr)->heap->dbg_calling_transport == 0); \ |
| 7777 | } while (0) |
| 7778 | |
| 7779 | /* |
| 7780 | * Assertion helpers. |
| 7781 | */ |
| 7782 | |
| 7783 | #define DUK_ASSERT_STRIDX_VALID(val) \ |
| 7784 | DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS) |
| 7785 | |
| 7786 | #define DUK_ASSERT_BIDX_VALID(val) \ |
| 7787 | DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS) |
| 7788 | |
| 7789 | /* |
| 7790 | * Misc |
| 7791 | */ |
| 7792 | |
| 7793 | /* Fast access to 'this' binding. Assumes there's a call in progress. */ |
| 7794 | #define DUK_HTHREAD_THIS_PTR(thr) \ |
| 7795 | (DUK_ASSERT_EXPR((thr) != NULL), \ |
| 7796 | DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \ |
| 7797 | (thr)->valstack_bottom - 1) |
| 7798 | |
| 7799 | /* |
| 7800 | * Struct defines |
| 7801 | */ |
| 7802 | |
| 7803 | /* Fields are ordered for alignment/packing. */ |
| 7804 | struct duk_activation { |
| 7805 | duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */ |
| 7806 | duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */ |
| 7807 | duk_activation *parent; /* previous (parent) activation (or NULL if none) */ |
| 7808 | duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */ |
| 7809 | duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */ |
| 7810 | duk_catcher *cat; /* current catcher (or NULL) */ |
| 7811 | |
| 7812 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 7813 | /* Previous value of 'func' caller, restored when unwound. Only in use |
| 7814 | * when 'func' is non-strict. |
| 7815 | */ |
| 7816 | duk_hobject *prev_caller; |
| 7817 | #endif |
| 7818 | |
| 7819 | duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */ |
| 7820 | |
| 7821 | /* bottom_byteoff and retval_byteoff are only used for book-keeping |
| 7822 | * of ECMAScript-initiated calls, to allow returning to an ECMAScript |
| 7823 | * function properly. |
| 7824 | */ |
| 7825 | |
| 7826 | /* Bottom of valstack for this activation, used to reset |
| 7827 | * valstack_bottom on return; offset is absolute. There's |
| 7828 | * no need to track 'top' because native call handling deals |
| 7829 | * with that using locals, and for ECMAScript returns 'nregs' |
| 7830 | * indicates the necessary top. |
| 7831 | */ |
| 7832 | duk_size_t bottom_byteoff; |
| 7833 | |
| 7834 | /* Return value when returning to this activation (points to caller |
| 7835 | * reg, not callee reg); offset is absolute (only set if activation is |
| 7836 | * not topmost). |
| 7837 | * |
| 7838 | * Note: bottom_byteoff is always set, while retval_byteoff is only |
| 7839 | * applicable for activations below the topmost one. Currently |
| 7840 | * retval_byteoff for the topmost activation is considered garbage |
| 7841 | * (and it not initialized on entry or cleared on return; may contain |
| 7842 | * previous or garbage values). |
| 7843 | */ |
| 7844 | duk_size_t retval_byteoff; |
| 7845 | |
| 7846 | /* Current 'this' binding is the value just below bottom. |
| 7847 | * Previously, 'this' binding was handled with an index to the |
| 7848 | * (calling) valstack. This works for everything except tail |
| 7849 | * calls, which must not "accumulate" valstack temps. |
| 7850 | */ |
| 7851 | |
| 7852 | /* Value stack reserve (valstack_end) byte offset to be restored |
| 7853 | * when returning to this activation. Only used by the bytecode |
| 7854 | * executor. |
| 7855 | */ |
| 7856 | duk_size_t reserve_byteoff; |
| 7857 | |
| 7858 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 7859 | duk_uint32_t prev_line; /* needed for stepping */ |
| 7860 | #endif |
| 7861 | |
| 7862 | duk_small_uint_t flags; |
| 7863 | }; |
| 7864 | |
| 7865 | struct duk_catcher { |
| 7866 | duk_catcher *parent; /* previous (parent) catcher (or NULL if none) */ |
| 7867 | duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */ |
| 7868 | /* (reference is valid as long activation exists) */ |
| 7869 | duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */ |
| 7870 | duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */ |
| 7871 | duk_uint32_t flags; /* type and control flags, label number */ |
| 7872 | /* XXX: could pack 'flags' and 'idx_base' to same value in practice, |
| 7873 | * on 32-bit targets this would make duk_catcher 16 bytes. |
| 7874 | */ |
| 7875 | }; |
| 7876 | |
| 7877 | struct duk_hthread { |
| 7878 | /* Shared object part */ |
| 7879 | duk_hobject obj; |
| 7880 | |
| 7881 | /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy |
| 7882 | * the current PC back into the topmost activation when activation |
| 7883 | * state is about to change (or "syncing" is otherwise needed). This |
| 7884 | * is rather awkward but important for performance, see execution.rst. |
| 7885 | */ |
| 7886 | duk_instr_t **ptr_curr_pc; |
| 7887 | |
| 7888 | /* Backpointers. */ |
| 7889 | duk_heap *heap; |
| 7890 | |
| 7891 | /* Current strictness flag: affects API calls. */ |
| 7892 | duk_uint8_t strict; |
| 7893 | |
| 7894 | /* Thread state. */ |
| 7895 | duk_uint8_t state; |
| 7896 | duk_uint8_t unused1; |
| 7897 | duk_uint8_t unused2; |
| 7898 | |
| 7899 | /* XXX: Valstack and callstack are currently assumed to have non-NULL |
| 7900 | * pointers. Relaxing this would not lead to big benefits (except |
| 7901 | * perhaps for terminated threads). |
| 7902 | */ |
| 7903 | |
| 7904 | /* Value stack: these are expressed as pointers for faster stack |
| 7905 | * manipulation. [valstack,valstack_top[ is GC-reachable, |
| 7906 | * [valstack_top,valstack_alloc_end[ is not GC-reachable but kept |
| 7907 | * initialized as 'undefined'. [valstack,valstack_end[ is the |
| 7908 | * guaranteed/reserved space and the valstack cannot be resized to |
| 7909 | * a smaller size. [valstack_end,valstack_alloc_end[ is currently |
| 7910 | * allocated slack that can be used to grow the current guaranteed |
| 7911 | * space but may be shrunk away without notice. |
| 7912 | * |
| 7913 | * |
| 7914 | * <----------------------- guaranteed ---> |
| 7915 | * <---- slack ---> |
| 7916 | * <--- frame ---> |
| 7917 | * .-------------+=============+----------+--------------. |
| 7918 | * |xxxxxxxxxxxxx|yyyyyyyyyyyyy|uuuuuuuuuu|uuuuuuuuuuuuuu| |
| 7919 | * `-------------+=============+----------+--------------' |
| 7920 | * |
| 7921 | * ^ ^ ^ ^ ^ |
| 7922 | * | | | | | |
| 7923 | * valstack bottom top end alloc_end |
| 7924 | * |
| 7925 | * xxx = arbitrary values, below current frame |
| 7926 | * yyy = arbitrary values, inside current frame |
| 7927 | * uuu = outside active value stack, initialized to 'undefined' |
| 7928 | */ |
| 7929 | duk_tval *valstack; /* start of valstack allocation */ |
| 7930 | duk_tval *valstack_end; /* end of valstack reservation/guarantee (exclusive) */ |
| 7931 | duk_tval *valstack_alloc_end; /* end of valstack allocation */ |
| 7932 | duk_tval *valstack_bottom; /* bottom of current frame */ |
| 7933 | duk_tval *valstack_top; /* top of current frame (exclusive) */ |
| 7934 | |
| 7935 | /* Call stack, represented as a linked list starting from the current |
| 7936 | * activation (or NULL if nothing is active). |
| 7937 | */ |
| 7938 | duk_activation *callstack_curr; /* current activation (or NULL if none) */ |
| 7939 | duk_size_t callstack_top; /* number of activation records in callstack (0 if none) */ |
| 7940 | duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */ |
| 7941 | |
| 7942 | /* Yield/resume book-keeping. */ |
| 7943 | duk_hthread *resumer; /* who resumed us (if any) */ |
| 7944 | |
| 7945 | /* Current compiler state (if any), used for augmenting SyntaxErrors. */ |
| 7946 | duk_compiler_ctx *compile_ctx; |
| 7947 | |
| 7948 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 7949 | /* Interrupt counter for triggering a slow path check for execution |
| 7950 | * timeout, debugger interaction such as breakpoints, etc. The value |
| 7951 | * is valid for the current running thread, and both the init and |
| 7952 | * counter values are copied whenever a thread switch occurs. It's |
| 7953 | * important for the counter to be conveniently accessible for the |
| 7954 | * bytecode executor inner loop for performance reasons. |
| 7955 | */ |
| 7956 | duk_int_t interrupt_counter; /* countdown state */ |
| 7957 | duk_int_t interrupt_init; /* start value for current countdown */ |
| 7958 | #endif |
| 7959 | |
| 7960 | /* Builtin-objects; may or may not be shared with other threads, |
| 7961 | * threads existing in different "compartments" will have different |
| 7962 | * built-ins. Must be stored on a per-thread basis because there |
| 7963 | * is no intermediate structure for a thread group / compartment. |
| 7964 | * This takes quite a lot of space, currently 43x4 = 172 bytes on |
| 7965 | * 32-bit platforms. |
| 7966 | * |
| 7967 | * In some cases the builtins array could be ROM based, but it's |
| 7968 | * sometimes edited (e.g. for sandboxing) so it's better to keep |
| 7969 | * this array in RAM. |
| 7970 | */ |
| 7971 | duk_hobject *builtins[DUK_NUM_BUILTINS]; |
| 7972 | |
| 7973 | /* Convenience copies from heap/vm for faster access. */ |
| 7974 | #if defined(DUK_USE_ROM_STRINGS) |
| 7975 | /* No field needed when strings are in ROM. */ |
| 7976 | #else |
| 7977 | #if defined(DUK_USE_HEAPPTR16) |
| 7978 | duk_uint16_t *strs16; |
| 7979 | #else |
| 7980 | duk_hstring **strs; |
| 7981 | #endif |
| 7982 | #endif |
| 7983 | }; |
| 7984 | |
| 7985 | /* |
| 7986 | * Prototypes |
| 7987 | */ |
| 7988 | |
| 7989 | DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to); |
| 7990 | DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr); |
| 7991 | DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr); |
| 7992 | DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr); |
| 7993 | |
| 7994 | DUK_INTERNAL_DECL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr); |
| 7995 | DUK_INTERNAL_DECL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act); |
| 7996 | DUK_INTERNAL_DECL void duk_hthread_activation_unwind_norz(duk_hthread *thr); |
| 7997 | DUK_INTERNAL_DECL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr); |
| 7998 | DUK_INTERNAL_DECL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level); |
| 7999 | |
| 8000 | DUK_INTERNAL_DECL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr); |
| 8001 | DUK_INTERNAL_DECL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat); |
| 8002 | DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act); |
| 8003 | DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act); |
| 8004 | |
| 8005 | #if defined(DUK_USE_FINALIZER_TORTURE) |
| 8006 | DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr); |
| 8007 | #endif |
| 8008 | |
| 8009 | DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */ |
| 8010 | |
| 8011 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 8012 | DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act); |
| 8013 | #endif |
| 8014 | DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act); |
| 8015 | DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr); |
| 8016 | DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr); |
| 8017 | |
| 8018 | #endif /* DUK_HTHREAD_H_INCLUDED */ |
| 8019 | /* #include duk_harray.h */ |
| 8020 | #line 1 "duk_harray.h" |
| 8021 | /* |
| 8022 | * Array object representation, used for actual Array instances. |
| 8023 | * |
| 8024 | * All objects with the exotic array behavior (which must coincide with having |
| 8025 | * internal class array) MUST be duk_harrays. No other object can be a |
| 8026 | * duk_harray. However, duk_harrays may not always have an array part. |
| 8027 | */ |
| 8028 | |
| 8029 | #if !defined(DUK_HARRAY_H_INCLUDED) |
| 8030 | #define DUK_HARRAY_H_INCLUDED |
| 8031 | |
| 8032 | #if defined(DUK_USE_ASSERTIONS) |
| 8033 | DUK_INTERNAL_DECL void duk_harray_assert_valid(duk_harray *h); |
| 8034 | #define DUK_HARRAY_ASSERT_VALID(h) do { duk_harray_assert_valid((h)); } while (0) |
| 8035 | #else |
| 8036 | #define DUK_HARRAY_ASSERT_VALID(h) do {} while (0) |
| 8037 | #endif |
| 8038 | |
| 8039 | #define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable) |
| 8040 | #define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable) |
| 8041 | #define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0) |
| 8042 | #define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0) |
| 8043 | |
| 8044 | struct duk_harray { |
| 8045 | /* Shared object part. */ |
| 8046 | duk_hobject obj; |
| 8047 | |
| 8048 | /* Array .length. |
| 8049 | * |
| 8050 | * At present Array .length may be smaller, equal, or even larger |
| 8051 | * than the allocated underlying array part. Fast path code must |
| 8052 | * always take this into account carefully. |
| 8053 | */ |
| 8054 | duk_uint32_t length; |
| 8055 | |
| 8056 | /* Array .length property attributes. The property is always |
| 8057 | * non-enumerable and non-configurable. It's initially writable |
| 8058 | * but per Object.defineProperty() rules it can be made non-writable |
| 8059 | * even if it is non-configurable. Thus we need to track the |
| 8060 | * writability explicitly. |
| 8061 | * |
| 8062 | * XXX: this field to be eliminated and moved into duk_hobject |
| 8063 | * flags field to save space. |
| 8064 | */ |
| 8065 | duk_bool_t length_nonwritable; |
| 8066 | }; |
| 8067 | |
| 8068 | #endif /* DUK_HARRAY_H_INCLUDED */ |
| 8069 | /* #include duk_henv.h */ |
| 8070 | #line 1 "duk_henv.h" |
| 8071 | /* |
| 8072 | * Environment object representation. |
| 8073 | */ |
| 8074 | |
| 8075 | #if !defined(DUK_HENV_H_INCLUDED) |
| 8076 | #define DUK_HENV_H_INCLUDED |
| 8077 | |
| 8078 | #if defined(DUK_USE_ASSERTIONS) |
| 8079 | DUK_INTERNAL_DECL void duk_hdecenv_assert_valid(duk_hdecenv *h); |
| 8080 | DUK_INTERNAL_DECL void duk_hobjenv_assert_valid(duk_hobjenv *h); |
| 8081 | #define DUK_HDECENV_ASSERT_VALID(h) do { duk_hdecenv_assert_valid((h)); } while (0) |
| 8082 | #define DUK_HOBJENV_ASSERT_VALID(h) do { duk_hobjenv_assert_valid((h)); } while (0) |
| 8083 | #else |
| 8084 | #define DUK_HDECENV_ASSERT_VALID(h) do {} while (0) |
| 8085 | #define DUK_HOBJENV_ASSERT_VALID(h) do {} while (0) |
| 8086 | #endif |
| 8087 | |
| 8088 | struct duk_hdecenv { |
| 8089 | /* Shared object part. */ |
| 8090 | duk_hobject obj; |
| 8091 | |
| 8092 | /* These control variables provide enough information to access live |
| 8093 | * variables for a closure that is still open. If thread == NULL, |
| 8094 | * the record is closed and the identifiers are in the property table. |
| 8095 | */ |
| 8096 | duk_hthread *thread; |
| 8097 | duk_hobject *varmap; |
| 8098 | duk_size_t regbase_byteoff; |
| 8099 | }; |
| 8100 | |
| 8101 | struct duk_hobjenv { |
| 8102 | /* Shared object part. */ |
| 8103 | duk_hobject obj; |
| 8104 | |
| 8105 | /* Target object and 'this' binding for object binding. */ |
| 8106 | duk_hobject *target; |
| 8107 | |
| 8108 | /* The 'target' object is used as a this binding in only some object |
| 8109 | * environments. For example, the global environment does not provide |
| 8110 | * a this binding, but a with statement does. |
| 8111 | */ |
| 8112 | duk_bool_t has_this; |
| 8113 | }; |
| 8114 | |
| 8115 | #endif /* DUK_HENV_H_INCLUDED */ |
| 8116 | /* #include duk_hbuffer.h */ |
| 8117 | #line 1 "duk_hbuffer.h" |
| 8118 | /* |
| 8119 | * Heap buffer representation. |
| 8120 | * |
| 8121 | * Heap allocated user data buffer which is either: |
| 8122 | * |
| 8123 | * 1. A fixed size buffer (data follows header statically) |
| 8124 | * 2. A dynamic size buffer (data pointer follows header) |
| 8125 | * |
| 8126 | * The data pointer for a variable size buffer of zero size may be NULL. |
| 8127 | */ |
| 8128 | |
| 8129 | #if !defined(DUK_HBUFFER_H_INCLUDED) |
| 8130 | #define DUK_HBUFFER_H_INCLUDED |
| 8131 | |
| 8132 | /* |
| 8133 | * Flags |
| 8134 | * |
| 8135 | * Fixed buffer: 0 |
| 8136 | * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC |
| 8137 | * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL |
| 8138 | */ |
| 8139 | |
| 8140 | #define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */ |
| 8141 | #define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */ |
| 8142 | |
| 8143 | #define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) |
| 8144 | #define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) |
| 8145 | |
| 8146 | #define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) |
| 8147 | #define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) |
| 8148 | |
| 8149 | #define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC) |
| 8150 | #define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL) |
| 8151 | |
| 8152 | /* |
| 8153 | * Misc defines |
| 8154 | */ |
| 8155 | |
| 8156 | /* Impose a maximum buffer length for now. Restricted artificially to |
| 8157 | * ensure resize computations or adding a heap header length won't |
| 8158 | * overflow size_t and that a signed duk_int_t can hold a buffer |
| 8159 | * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN. |
| 8160 | */ |
| 8161 | |
| 8162 | #if defined(DUK_USE_BUFLEN16) |
| 8163 | #define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL) |
| 8164 | #else |
| 8165 | /* Intentionally not 0x7fffffffUL; at least JSON code expects that |
| 8166 | * 2*len + 2 fits in 32 bits. |
| 8167 | */ |
| 8168 | #define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL) |
| 8169 | #endif |
| 8170 | |
| 8171 | /* |
| 8172 | * Field access |
| 8173 | */ |
| 8174 | |
| 8175 | #if defined(DUK_USE_BUFLEN16) |
| 8176 | /* size stored in duk_heaphdr unused flag bits */ |
| 8177 | #define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16) |
| 8178 | #define DUK_HBUFFER_SET_SIZE(x,v) do { \ |
| 8179 | duk_size_t duk__v; \ |
| 8180 | duk__v = (v); \ |
| 8181 | DUK_ASSERT(duk__v <= 0xffffUL); \ |
| 8182 | (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \ |
| 8183 | } while (0) |
| 8184 | #define DUK_HBUFFER_ADD_SIZE(x,dv) do { \ |
| 8185 | (x)->hdr.h_flags += ((dv) << 16); \ |
| 8186 | } while (0) |
| 8187 | #define DUK_HBUFFER_SUB_SIZE(x,dv) do { \ |
| 8188 | (x)->hdr.h_flags -= ((dv) << 16); \ |
| 8189 | } while (0) |
| 8190 | #else |
| 8191 | #define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size) |
| 8192 | #define DUK_HBUFFER_SET_SIZE(x,v) do { \ |
| 8193 | ((duk_hbuffer *) (x))->size = (v); \ |
| 8194 | } while (0) |
| 8195 | #define DUK_HBUFFER_ADD_SIZE(x,dv) do { \ |
| 8196 | (x)->size += (dv); \ |
| 8197 | } while (0) |
| 8198 | #define DUK_HBUFFER_SUB_SIZE(x,dv) do { \ |
| 8199 | (x)->size -= (dv); \ |
| 8200 | } while (0) |
| 8201 | #endif |
| 8202 | |
| 8203 | #define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) |
| 8204 | #define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x)) |
| 8205 | |
| 8206 | #define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) |
| 8207 | #define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v)) |
| 8208 | #define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv)) |
| 8209 | #define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv)) |
| 8210 | |
| 8211 | #define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x)) |
| 8212 | #define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v)) |
| 8213 | |
| 8214 | #define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (void *) (x)) + 1)) |
| 8215 | |
| 8216 | #if defined(DUK_USE_HEAPPTR16) |
| 8217 | #define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \ |
| 8218 | ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16)) |
| 8219 | #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \ |
| 8220 | ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ |
| 8221 | } while (0) |
| 8222 | #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \ |
| 8223 | ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \ |
| 8224 | } while (0) |
| 8225 | #else |
| 8226 | #define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc) |
| 8227 | #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \ |
| 8228 | (x)->curr_alloc = (void *) (v); \ |
| 8229 | } while (0) |
| 8230 | #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \ |
| 8231 | (x)->curr_alloc = (void *) NULL; \ |
| 8232 | } while (0) |
| 8233 | #endif |
| 8234 | |
| 8235 | /* No pointer compression because pointer is potentially outside of |
| 8236 | * Duktape heap. |
| 8237 | */ |
| 8238 | #if defined(DUK_USE_HEAPPTR16) |
| 8239 | #define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \ |
| 8240 | ((void *) (x)->curr_alloc) |
| 8241 | #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \ |
| 8242 | (x)->curr_alloc = (void *) (v); \ |
| 8243 | } while (0) |
| 8244 | #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \ |
| 8245 | (x)->curr_alloc = (void *) NULL; \ |
| 8246 | } while (0) |
| 8247 | #else |
| 8248 | #define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \ |
| 8249 | ((void *) (x)->curr_alloc) |
| 8250 | #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \ |
| 8251 | (x)->curr_alloc = (void *) (v); \ |
| 8252 | } while (0) |
| 8253 | #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \ |
| 8254 | (x)->curr_alloc = (void *) NULL; \ |
| 8255 | } while (0) |
| 8256 | #endif |
| 8257 | |
| 8258 | /* Get a pointer to the current buffer contents (matching current allocation |
| 8259 | * size). May be NULL for zero size dynamic/external buffer. |
| 8260 | */ |
| 8261 | #if defined(DUK_USE_HEAPPTR16) |
| 8262 | #define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \ |
| 8263 | DUK_HBUFFER_HAS_DYNAMIC((x)) ? \ |
| 8264 | ( \ |
| 8265 | DUK_HBUFFER_HAS_EXTERNAL((x)) ? \ |
| 8266 | DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \ |
| 8267 | DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \ |
| 8268 | ) : \ |
| 8269 | DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \ |
| 8270 | ) |
| 8271 | #else |
| 8272 | /* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external |
| 8273 | * have the same layout so checking for fixed vs. dynamic (or external) is enough. |
| 8274 | */ |
| 8275 | #define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \ |
| 8276 | DUK_HBUFFER_HAS_DYNAMIC((x)) ? \ |
| 8277 | DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \ |
| 8278 | DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \ |
| 8279 | ) |
| 8280 | #endif |
| 8281 | |
| 8282 | /* Validity assert. */ |
| 8283 | #if defined(DUK_USE_ASSERTIONS) |
| 8284 | DUK_INTERNAL_DECL void duk_hbuffer_assert_valid(duk_hbuffer *h); |
| 8285 | #define DUK_HBUFFER_ASSERT_VALID(h) do { duk_hbuffer_assert_valid((h)); } while (0) |
| 8286 | #else |
| 8287 | #define DUK_HBUFFER_ASSERT_VALID(h) do {} while (0) |
| 8288 | #endif |
| 8289 | |
| 8290 | /* |
| 8291 | * Structs |
| 8292 | */ |
| 8293 | |
| 8294 | /* Shared prefix for all buffer types. */ |
| 8295 | struct duk_hbuffer { |
| 8296 | duk_heaphdr hdr; |
| 8297 | |
| 8298 | /* It's not strictly necessary to track the current size, but |
| 8299 | * it is useful for writing robust native code. |
| 8300 | */ |
| 8301 | |
| 8302 | /* Current size. */ |
| 8303 | #if defined(DUK_USE_BUFLEN16) |
| 8304 | /* Stored in duk_heaphdr unused flags. */ |
| 8305 | #else |
| 8306 | duk_size_t size; |
| 8307 | #endif |
| 8308 | |
| 8309 | /* |
| 8310 | * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC |
| 8311 | * flag. |
| 8312 | * |
| 8313 | * If the flag is clear (the buffer is a fixed size one), the buffer |
| 8314 | * data follows the header directly, consisting of 'size' bytes. |
| 8315 | * |
| 8316 | * If the flag is set, the actual buffer is allocated separately, and |
| 8317 | * a few control fields follow the header. Specifically: |
| 8318 | * |
| 8319 | * - a "void *" pointing to the current allocation |
| 8320 | * - a duk_size_t indicating the full allocated size (always >= 'size') |
| 8321 | * |
| 8322 | * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated |
| 8323 | * by user code, so that Duktape won't be able to resize it and won't |
| 8324 | * free it. This allows buffers to point to e.g. an externally |
| 8325 | * allocated structure such as a frame buffer. |
| 8326 | * |
| 8327 | * Unlike strings, no terminator byte (NUL) is guaranteed after the |
| 8328 | * data. This would be convenient, but would pad aligned user buffers |
| 8329 | * unnecessarily upwards in size. For instance, if user code requested |
| 8330 | * a 64-byte dynamic buffer, 65 bytes would actually be allocated which |
| 8331 | * would then potentially round upwards to perhaps 68 or 72 bytes. |
| 8332 | */ |
| 8333 | }; |
| 8334 | |
| 8335 | /* Fixed buffer; data follows struct, with proper alignment guaranteed by |
| 8336 | * struct size. |
| 8337 | */ |
| 8338 | #if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA) |
| 8339 | #pragma pack(push, 8) |
| 8340 | #endif |
| 8341 | struct duk_hbuffer_fixed { |
| 8342 | /* A union is used here as a portable struct size / alignment trick: |
| 8343 | * by adding a 32-bit or a 64-bit (unused) union member, the size of |
| 8344 | * the struct is effectively forced to be a multiple of 4 or 8 bytes |
| 8345 | * (respectively) without increasing the size of the struct unless |
| 8346 | * necessary. |
| 8347 | */ |
| 8348 | union { |
| 8349 | struct { |
| 8350 | duk_heaphdr hdr; |
| 8351 | #if defined(DUK_USE_BUFLEN16) |
| 8352 | /* Stored in duk_heaphdr unused flags. */ |
| 8353 | #else |
| 8354 | duk_size_t size; |
| 8355 | #endif |
| 8356 | } s; |
| 8357 | #if (DUK_USE_ALIGN_BY == 4) |
| 8358 | duk_uint32_t dummy_for_align4; |
| 8359 | #elif (DUK_USE_ALIGN_BY == 8) |
| 8360 | duk_double_t dummy_for_align8_1; |
| 8361 | #if defined(DUK_USE_64BIT_OPS) |
| 8362 | duk_uint64_t dummy_for_align8_2; |
| 8363 | #endif |
| 8364 | #elif (DUK_USE_ALIGN_BY == 1) |
| 8365 | /* no extra padding */ |
| 8366 | #else |
| 8367 | #error invalid DUK_USE_ALIGN_BY |
| 8368 | #endif |
| 8369 | } u; |
| 8370 | |
| 8371 | /* |
| 8372 | * Data follows the struct header. The struct size is padded by the |
| 8373 | * compiler based on the struct members. This guarantees that the |
| 8374 | * buffer data will be aligned-by-4 but not necessarily aligned-by-8. |
| 8375 | * |
| 8376 | * On platforms where alignment does not matter, the struct padding |
| 8377 | * could be removed (if there is any). On platforms where alignment |
| 8378 | * by 8 is required, the struct size must be forced to be a multiple |
| 8379 | * of 8 by some means. Without it, some user code may break, and also |
| 8380 | * Duktape itself breaks (e.g. the compiler stores duk_tvals in a |
| 8381 | * dynamic buffer). |
| 8382 | */ |
| 8383 | } |
| 8384 | #if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR) |
| 8385 | __attribute__ ((aligned (8))) |
| 8386 | #elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR) |
| 8387 | __attribute__ ((aligned (8))) |
| 8388 | #endif |
| 8389 | ; |
| 8390 | #if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA) |
| 8391 | #pragma pack(pop) |
| 8392 | #endif |
| 8393 | |
| 8394 | /* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using |
| 8395 | * heap allocation primitives. Also used for external buffers when low memory |
| 8396 | * options are not used. |
| 8397 | */ |
| 8398 | struct duk_hbuffer_dynamic { |
| 8399 | duk_heaphdr hdr; |
| 8400 | |
| 8401 | #if defined(DUK_USE_BUFLEN16) |
| 8402 | /* Stored in duk_heaphdr unused flags. */ |
| 8403 | #else |
| 8404 | duk_size_t size; |
| 8405 | #endif |
| 8406 | |
| 8407 | #if defined(DUK_USE_HEAPPTR16) |
| 8408 | /* Stored in duk_heaphdr h_extra16. */ |
| 8409 | #else |
| 8410 | void *curr_alloc; /* may be NULL if alloc_size == 0 */ |
| 8411 | #endif |
| 8412 | |
| 8413 | /* |
| 8414 | * Allocation size for 'curr_alloc' is alloc_size. There is no |
| 8415 | * automatic NUL terminator for buffers (see above for rationale). |
| 8416 | * |
| 8417 | * 'curr_alloc' is explicitly allocated with heap allocation |
| 8418 | * primitives and will thus always have alignment suitable for |
| 8419 | * e.g. duk_tval and an IEEE double. |
| 8420 | */ |
| 8421 | }; |
| 8422 | |
| 8423 | /* External buffer with 'curr_alloc' managed by user code and pointing to an |
| 8424 | * arbitrary address. When heap pointer compression is not used, this struct |
| 8425 | * has the same layout as duk_hbuffer_dynamic. |
| 8426 | */ |
| 8427 | struct duk_hbuffer_external { |
| 8428 | duk_heaphdr hdr; |
| 8429 | |
| 8430 | #if defined(DUK_USE_BUFLEN16) |
| 8431 | /* Stored in duk_heaphdr unused flags. */ |
| 8432 | #else |
| 8433 | duk_size_t size; |
| 8434 | #endif |
| 8435 | |
| 8436 | /* Cannot be compressed as a heap pointer because may point to |
| 8437 | * an arbitrary address. |
| 8438 | */ |
| 8439 | void *curr_alloc; /* may be NULL if alloc_size == 0 */ |
| 8440 | }; |
| 8441 | |
| 8442 | /* |
| 8443 | * Prototypes |
| 8444 | */ |
| 8445 | |
| 8446 | DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata); |
| 8447 | DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */ |
| 8448 | |
| 8449 | /* dynamic buffer ops */ |
| 8450 | DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size); |
| 8451 | DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf); |
| 8452 | |
| 8453 | #endif /* DUK_HBUFFER_H_INCLUDED */ |
| 8454 | /* #include duk_hproxy.h */ |
| 8455 | #line 1 "duk_hproxy.h" |
| 8456 | /* |
| 8457 | * Proxy object representation. |
| 8458 | */ |
| 8459 | |
| 8460 | #if !defined(DUK_HPROXY_H_INCLUDED) |
| 8461 | #define DUK_HPROXY_H_INCLUDED |
| 8462 | |
| 8463 | #if defined(DUK_USE_ASSERTIONS) |
| 8464 | DUK_INTERNAL_DECL void duk_hproxy_assert_valid(duk_hproxy *h); |
| 8465 | #define DUK_HPROXY_ASSERT_VALID(h) do { duk_hproxy_assert_valid((h)); } while (0) |
| 8466 | #else |
| 8467 | #define DUK_HPROXY_ASSERT_VALID(h) do {} while (0) |
| 8468 | #endif |
| 8469 | |
| 8470 | struct duk_hproxy { |
| 8471 | /* Shared object part. */ |
| 8472 | duk_hobject obj; |
| 8473 | |
| 8474 | /* Proxy target object. */ |
| 8475 | duk_hobject *target; |
| 8476 | |
| 8477 | /* Proxy handlers (traps). */ |
| 8478 | duk_hobject *handler; |
| 8479 | }; |
| 8480 | |
| 8481 | #endif /* DUK_HPROXY_H_INCLUDED */ |
| 8482 | /* #include duk_heap.h */ |
| 8483 | #line 1 "duk_heap.h" |
| 8484 | /* |
| 8485 | * Heap structure. |
| 8486 | * |
| 8487 | * Heap contains allocated heap objects, interned strings, and built-in |
| 8488 | * strings for one or more threads. |
| 8489 | */ |
| 8490 | |
| 8491 | #if !defined(DUK_HEAP_H_INCLUDED) |
| 8492 | #define DUK_HEAP_H_INCLUDED |
| 8493 | |
| 8494 | /* alloc function typedefs in duktape.h */ |
| 8495 | |
| 8496 | /* |
| 8497 | * Heap flags |
| 8498 | */ |
| 8499 | |
| 8500 | #define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1U << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */ |
| 8501 | #define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1U << 1) /* executor interrupt running (used to avoid nested interrupts) */ |
| 8502 | #define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1U << 2) /* heap destruction ongoing, finalizer rescue no longer possible */ |
| 8503 | #define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1U << 3) /* debugger is paused: talk with debug client until step/resume */ |
| 8504 | |
| 8505 | #define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits)) |
| 8506 | #define DUK__HEAP_SET_FLAGS(heap,bits) do { \ |
| 8507 | (heap)->flags |= (bits); \ |
| 8508 | } while (0) |
| 8509 | #define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \ |
| 8510 | (heap)->flags &= ~(bits); \ |
| 8511 | } while (0) |
| 8512 | |
| 8513 | #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) |
| 8514 | #define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) |
| 8515 | #define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
| 8516 | #define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) |
| 8517 | |
| 8518 | #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) |
| 8519 | #define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) |
| 8520 | #define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
| 8521 | #define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) |
| 8522 | |
| 8523 | #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED) |
| 8524 | #define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING) |
| 8525 | #define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE) |
| 8526 | #define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED) |
| 8527 | |
| 8528 | /* |
| 8529 | * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally') |
| 8530 | */ |
| 8531 | |
| 8532 | #define DUK_LJ_TYPE_UNKNOWN 0 /* unused */ |
| 8533 | #define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */ |
| 8534 | #define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */ |
| 8535 | #define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */ |
| 8536 | #define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */ |
| 8537 | #define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */ |
| 8538 | #define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */ |
| 8539 | #define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */ |
| 8540 | |
| 8541 | /* |
| 8542 | * Mark-and-sweep flags |
| 8543 | * |
| 8544 | * These are separate from heap level flags now but could be merged. |
| 8545 | * The heap structure only contains a 'base mark-and-sweep flags' |
| 8546 | * field and the GC caller can impose further flags. |
| 8547 | */ |
| 8548 | |
| 8549 | /* Emergency mark-and-sweep: try extra hard, even at the cost of |
| 8550 | * performance. |
| 8551 | */ |
| 8552 | #define DUK_MS_FLAG_EMERGENCY (1U << 0) |
| 8553 | |
| 8554 | /* Postpone rescue decisions for reachable objects with FINALIZED set. |
| 8555 | * Used during finalize_list processing to avoid incorrect rescue |
| 8556 | * decisions due to finalize_list being a reachability root. |
| 8557 | */ |
| 8558 | #define DUK_MS_FLAG_POSTPONE_RESCUE (1U << 1) |
| 8559 | |
| 8560 | /* Don't compact objects; needed during object property table resize |
| 8561 | * to prevent a recursive resize. It would suffice to protect only the |
| 8562 | * current object being resized, but this is not yet implemented. |
| 8563 | */ |
| 8564 | #define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1U << 2) |
| 8565 | |
| 8566 | /* |
| 8567 | * Thread switching |
| 8568 | * |
| 8569 | * To switch heap->curr_thread, use the macro below so that interrupt counters |
| 8570 | * get updated correctly. The macro allows a NULL target thread because that |
| 8571 | * happens e.g. in call handling. |
| 8572 | */ |
| 8573 | |
| 8574 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 8575 | #define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr)) |
| 8576 | #else |
| 8577 | #define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \ |
| 8578 | (heap)->curr_thread = (newthr); \ |
| 8579 | } while (0) |
| 8580 | #endif |
| 8581 | |
| 8582 | /* |
| 8583 | * Stats |
| 8584 | */ |
| 8585 | |
| 8586 | #if defined(DUK_USE_DEBUG) |
| 8587 | #define DUK_STATS_INC(heap,fieldname) do { \ |
| 8588 | (heap)->fieldname += 1; \ |
| 8589 | } while (0) |
| 8590 | #else |
| 8591 | #define DUK_STATS_INC(heap,fieldname) do {} while (0) |
| 8592 | #endif |
| 8593 | |
| 8594 | /* |
| 8595 | * Other heap related defines |
| 8596 | */ |
| 8597 | |
| 8598 | /* Mark-and-sweep interval is relative to combined count of objects and |
| 8599 | * strings kept in the heap during the latest mark-and-sweep pass. |
| 8600 | * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is |
| 8601 | * decreased by each (re)allocation attempt (regardless of size), and each |
| 8602 | * refzero processed object. |
| 8603 | * |
| 8604 | * 'SKIP' indicates how many (re)allocations to wait until a retry if |
| 8605 | * GC is skipped because there is no thread do it with yet (happens |
| 8606 | * only during init phases). |
| 8607 | */ |
| 8608 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 8609 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */ |
| 8610 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L |
| 8611 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L |
| 8612 | #else |
| 8613 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */ |
| 8614 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L |
| 8615 | #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L |
| 8616 | #endif |
| 8617 | |
| 8618 | /* GC torture. */ |
| 8619 | #if defined(DUK_USE_GC_TORTURE) |
| 8620 | #define DUK_GC_TORTURE(heap) do { duk_heap_mark_and_sweep((heap), 0); } while (0) |
| 8621 | #else |
| 8622 | #define DUK_GC_TORTURE(heap) do { } while (0) |
| 8623 | #endif |
| 8624 | |
| 8625 | /* Stringcache is used for speeding up char-offset-to-byte-offset |
| 8626 | * translations for non-ASCII strings. |
| 8627 | */ |
| 8628 | #define DUK_HEAP_STRCACHE_SIZE 4 |
| 8629 | #define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */ |
| 8630 | |
| 8631 | /* Some list management macros. */ |
| 8632 | #define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap), (hdr)) |
| 8633 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 8634 | #define DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap,hdr) duk_heap_remove_from_heap_allocated((heap), (hdr)) |
| 8635 | #endif |
| 8636 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 8637 | #define DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap,hdr) duk_heap_insert_into_finalize_list((heap), (hdr)) |
| 8638 | #define DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap,hdr) duk_heap_remove_from_finalize_list((heap), (hdr)) |
| 8639 | #endif |
| 8640 | |
| 8641 | /* |
| 8642 | * Built-in strings |
| 8643 | */ |
| 8644 | |
| 8645 | /* heap string indices are autogenerated in duk_strings.h */ |
| 8646 | #if defined(DUK_USE_ROM_STRINGS) |
| 8647 | #define DUK_HEAP_GET_STRING(heap,idx) \ |
| 8648 | ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)])) |
| 8649 | #else /* DUK_USE_ROM_STRINGS */ |
| 8650 | #if defined(DUK_USE_HEAPPTR16) |
| 8651 | #define DUK_HEAP_GET_STRING(heap,idx) \ |
| 8652 | ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)])) |
| 8653 | #else |
| 8654 | #define DUK_HEAP_GET_STRING(heap,idx) \ |
| 8655 | ((heap)->strs[(idx)]) |
| 8656 | #endif |
| 8657 | #endif /* DUK_USE_ROM_STRINGS */ |
| 8658 | |
| 8659 | /* |
| 8660 | * Raw memory calls: relative to heap, but no GC interaction |
| 8661 | */ |
| 8662 | |
| 8663 | #define DUK_ALLOC_RAW(heap,size) \ |
| 8664 | ((heap)->alloc_func((heap)->heap_udata, (size))) |
| 8665 | |
| 8666 | #define DUK_REALLOC_RAW(heap,ptr,newsize) \ |
| 8667 | ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize))) |
| 8668 | |
| 8669 | #define DUK_FREE_RAW(heap,ptr) \ |
| 8670 | ((heap)->free_func((heap)->heap_udata, (void *) (ptr))) |
| 8671 | |
| 8672 | /* |
| 8673 | * Memory calls: relative to heap, GC interaction, but no error throwing. |
| 8674 | * |
| 8675 | * XXX: Currently a mark-and-sweep triggered by memory allocation will run |
| 8676 | * using the heap->heap_thread. This thread is also used for running |
| 8677 | * mark-and-sweep finalization; this is not ideal because it breaks the |
| 8678 | * isolation between multiple global environments. |
| 8679 | * |
| 8680 | * Notes: |
| 8681 | * |
| 8682 | * - DUK_FREE() is required to ignore NULL and any other possible return |
| 8683 | * value of a zero-sized alloc/realloc (same as ANSI C free()). |
| 8684 | * |
| 8685 | * - There is no DUK_REALLOC_ZEROED because we don't assume to know the |
| 8686 | * old size. Caller must zero the reallocated memory. |
| 8687 | * |
| 8688 | * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered |
| 8689 | * by an allocation failure might invalidate the original 'ptr', thus |
| 8690 | * causing a realloc retry to use an invalid pointer. Example: we're |
| 8691 | * reallocating the value stack and a finalizer resizes the same value |
| 8692 | * stack during mark-and-sweep. The indirect variant requests for the |
| 8693 | * current location of the pointer being reallocated using a callback |
| 8694 | * right before every realloc attempt; this circuitous approach is used |
| 8695 | * to avoid strict aliasing issues in a more straightforward indirect |
| 8696 | * pointer (void **) approach. Note: the pointer in the storage |
| 8697 | * location is read but is NOT updated; the caller must do that. |
| 8698 | */ |
| 8699 | |
| 8700 | /* callback for indirect reallocs, request for current pointer */ |
| 8701 | typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud); |
| 8702 | |
| 8703 | #define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size)) |
| 8704 | #define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size)) |
| 8705 | #define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize)) |
| 8706 | #define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize)) |
| 8707 | #define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr)) |
| 8708 | |
| 8709 | /* |
| 8710 | * Checked allocation, relative to a thread |
| 8711 | * |
| 8712 | * DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument |
| 8713 | * for convenience. |
| 8714 | */ |
| 8715 | |
| 8716 | #define DUK_ALLOC_CHECKED(thr,size) duk_heap_mem_alloc_checked((thr), (size)) |
| 8717 | #define DUK_ALLOC_CHECKED_ZEROED(thr,size) duk_heap_mem_alloc_checked_zeroed((thr), (size)) |
| 8718 | #define DUK_FREE_CHECKED(thr,ptr) duk_heap_mem_free((thr)->heap, (ptr)) |
| 8719 | |
| 8720 | /* |
| 8721 | * Memory constants |
| 8722 | */ |
| 8723 | |
| 8724 | #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 10 /* Retry allocation after mark-and-sweep for this |
| 8725 | * many times. A single mark-and-sweep round is |
| 8726 | * not guaranteed to free all unreferenced memory |
| 8727 | * because of finalization (in fact, ANY number of |
| 8728 | * rounds is strictly not enough). |
| 8729 | */ |
| 8730 | |
| 8731 | #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode |
| 8732 | * for mark-and-sweep. |
| 8733 | */ |
| 8734 | |
| 8735 | /* |
| 8736 | * Debugger support |
| 8737 | */ |
| 8738 | |
| 8739 | /* Maximum number of breakpoints. Only breakpoints that are set are |
| 8740 | * consulted so increasing this has no performance impact. |
| 8741 | */ |
| 8742 | #define DUK_HEAP_MAX_BREAKPOINTS 16 |
| 8743 | |
| 8744 | /* Opcode interval for a Date-based status/peek rate limit check. Only |
| 8745 | * relevant when debugger is attached. Requesting a timestamp may be a |
| 8746 | * slow operation on some platforms so this shouldn't be too low. On the |
| 8747 | * other hand a high value makes Duktape react to a pause request slowly. |
| 8748 | */ |
| 8749 | #define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000 |
| 8750 | |
| 8751 | /* Milliseconds between status notify and transport peeks. */ |
| 8752 | #define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200 |
| 8753 | |
| 8754 | /* Debugger pause flags. */ |
| 8755 | #define DUK_PAUSE_FLAG_ONE_OPCODE (1U << 0) /* pause when a single opcode has been executed */ |
| 8756 | #define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1) /* one opcode pause actually active; artifact of current implementation */ |
| 8757 | #define DUK_PAUSE_FLAG_LINE_CHANGE (1U << 2) /* pause when current line number changes */ |
| 8758 | #define DUK_PAUSE_FLAG_FUNC_ENTRY (1U << 3) /* pause when entering a function */ |
| 8759 | #define DUK_PAUSE_FLAG_FUNC_EXIT (1U << 4) /* pause when exiting current function */ |
| 8760 | #define DUK_PAUSE_FLAG_CAUGHT_ERROR (1U << 5) /* pause when about to throw an error that is caught */ |
| 8761 | #define DUK_PAUSE_FLAG_UNCAUGHT_ERROR (1U << 6) /* pause when about to throw an error that won't be caught */ |
| 8762 | |
| 8763 | struct duk_breakpoint { |
| 8764 | duk_hstring *filename; |
| 8765 | duk_uint32_t line; |
| 8766 | }; |
| 8767 | |
| 8768 | /* |
| 8769 | * String cache should ideally be at duk_hthread level, but that would |
| 8770 | * cause string finalization to slow down relative to the number of |
| 8771 | * threads; string finalization must check the string cache for "weak" |
| 8772 | * references to the string being finalized to avoid dead pointers. |
| 8773 | * |
| 8774 | * Thus, string caches are now at the heap level now. |
| 8775 | */ |
| 8776 | |
| 8777 | struct duk_strcache_entry { |
| 8778 | duk_hstring *h; |
| 8779 | duk_uint32_t bidx; |
| 8780 | duk_uint32_t cidx; |
| 8781 | }; |
| 8782 | |
| 8783 | /* |
| 8784 | * Longjmp state, contains the information needed to perform a longjmp. |
| 8785 | * Longjmp related values are written to value1, value2, and iserror. |
| 8786 | */ |
| 8787 | |
| 8788 | struct duk_ljstate { |
| 8789 | duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */ |
| 8790 | duk_small_uint_t type; /* longjmp type */ |
| 8791 | duk_bool_t iserror; /* isError flag for yield */ |
| 8792 | duk_tval value1; /* 1st related value (type specific) */ |
| 8793 | duk_tval value2; /* 2nd related value (type specific) */ |
| 8794 | }; |
| 8795 | |
| 8796 | #define DUK_ASSERT_LJSTATE_UNSET(heap) do { \ |
| 8797 | DUK_ASSERT(heap != NULL); \ |
| 8798 | DUK_ASSERT(heap->lj.type == DUK_LJ_TYPE_UNKNOWN); \ |
| 8799 | DUK_ASSERT(heap->lj.iserror == 0); \ |
| 8800 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value1)); \ |
| 8801 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value2)); \ |
| 8802 | } while (0) |
| 8803 | #define DUK_ASSERT_LJSTATE_SET(heap) do { \ |
| 8804 | DUK_ASSERT(heap != NULL); \ |
| 8805 | DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \ |
| 8806 | } while (0) |
| 8807 | |
| 8808 | /* |
| 8809 | * Literal intern cache |
| 8810 | */ |
| 8811 | |
| 8812 | struct duk_litcache_entry { |
| 8813 | const duk_uint8_t *addr; |
| 8814 | duk_hstring *h; |
| 8815 | }; |
| 8816 | |
| 8817 | /* |
| 8818 | * Main heap structure |
| 8819 | */ |
| 8820 | |
| 8821 | #if defined(DUK_USE_ASSERTIONS) |
| 8822 | DUK_INTERNAL_DECL void duk_heap_assert_valid(duk_heap *heap); |
| 8823 | #define DUK_HEAP_ASSERT_VALID(heap) do { duk_heap_assert_valid((heap)); } while (0) |
| 8824 | #else |
| 8825 | #define DUK_HEAP_ASSERT_VALID(heap) do {} while (0) |
| 8826 | #endif |
| 8827 | |
| 8828 | struct duk_heap { |
| 8829 | duk_small_uint_t flags; |
| 8830 | |
| 8831 | /* Allocator functions. */ |
| 8832 | duk_alloc_function alloc_func; |
| 8833 | duk_realloc_function realloc_func; |
| 8834 | duk_free_function free_func; |
| 8835 | |
| 8836 | /* Heap udata, used for allocator functions but also for other heap |
| 8837 | * level callbacks like fatal function, pointer compression, etc. |
| 8838 | */ |
| 8839 | void *heap_udata; |
| 8840 | |
| 8841 | /* Fatal error handling, called e.g. when a longjmp() is needed but |
| 8842 | * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not |
| 8843 | * declared as "noreturn" because doing that for typedefs is a bit |
| 8844 | * challenging portability-wise. |
| 8845 | */ |
| 8846 | duk_fatal_function fatal_func; |
| 8847 | |
| 8848 | /* Main list of allocated heap objects. Objects are either here, |
| 8849 | * in finalize_list waiting for processing, or in refzero_list |
| 8850 | * temporarily while a DECREF refzero cascade finishes. |
| 8851 | */ |
| 8852 | duk_heaphdr *heap_allocated; |
| 8853 | |
| 8854 | /* Temporary work list for freeing a cascade of objects when a DECREF |
| 8855 | * (or DECREF_NORZ) encounters a zero refcount. Using a work list |
| 8856 | * allows fixed C stack size when refcounts go to zero for a chain of |
| 8857 | * objects. Outside of DECREF this is always a NULL because DECREF is |
| 8858 | * processed without side effects (only memory free calls). |
| 8859 | */ |
| 8860 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 8861 | duk_heaphdr *refzero_list; |
| 8862 | #endif |
| 8863 | |
| 8864 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 8865 | /* Work list for objects to be finalized. */ |
| 8866 | duk_heaphdr *finalize_list; |
| 8867 | #if defined(DUK_USE_ASSERTIONS) |
| 8868 | /* Object whose finalizer is executing right now (no nesting). */ |
| 8869 | duk_heaphdr *currently_finalizing; |
| 8870 | #endif |
| 8871 | #endif |
| 8872 | |
| 8873 | /* Freelist for duk_activations and duk_catchers. */ |
| 8874 | #if defined(DUK_USE_CACHE_ACTIVATION) |
| 8875 | duk_activation *activation_free; |
| 8876 | #endif |
| 8877 | #if defined(DUK_USE_CACHE_CATCHER) |
| 8878 | duk_catcher *catcher_free; |
| 8879 | #endif |
| 8880 | |
| 8881 | /* Voluntary mark-and-sweep trigger counter. Intentionally signed |
| 8882 | * because we continue decreasing the value when voluntary GC cannot |
| 8883 | * run. |
| 8884 | */ |
| 8885 | #if defined(DUK_USE_VOLUNTARY_GC) |
| 8886 | duk_int_t ms_trigger_counter; |
| 8887 | #endif |
| 8888 | |
| 8889 | /* Mark-and-sweep recursion control: too deep recursion causes |
| 8890 | * multi-pass processing to avoid growing C stack without bound. |
| 8891 | */ |
| 8892 | duk_uint_t ms_recursion_depth; |
| 8893 | |
| 8894 | /* Mark-and-sweep flags automatically active (used for critical sections). */ |
| 8895 | duk_small_uint_t ms_base_flags; |
| 8896 | |
| 8897 | /* Mark-and-sweep running flag. Prevents re-entry, and also causes |
| 8898 | * refzero events to be ignored (= objects won't be queued to refzero_list). |
| 8899 | * |
| 8900 | * 0: mark-and-sweep not running |
| 8901 | * 1: mark-and-sweep is running |
| 8902 | * 2: heap destruction active or debugger active, prevent mark-and-sweep |
| 8903 | * and refzero processing (but mark-and-sweep not itself running) |
| 8904 | */ |
| 8905 | duk_uint_t ms_running; |
| 8906 | |
| 8907 | /* Mark-and-sweep prevent count, stacking. Used to avoid M&S side |
| 8908 | * effects (besides finalizers which are controlled separately) such |
| 8909 | * as compacting the string table or object property tables. This |
| 8910 | * is also bumped when ms_running is set to prevent recursive re-entry. |
| 8911 | * Can also be bumped when mark-and-sweep is not running. |
| 8912 | */ |
| 8913 | duk_uint_t ms_prevent_count; |
| 8914 | |
| 8915 | /* Finalizer processing prevent count, stacking. Bumped when finalizers |
| 8916 | * are processed to prevent recursive finalizer processing (first call site |
| 8917 | * processing finalizers handles all finalizers until the list is empty). |
| 8918 | * Can also be bumped explicitly to prevent finalizer execution. |
| 8919 | */ |
| 8920 | duk_uint_t pf_prevent_count; |
| 8921 | |
| 8922 | /* When processing finalize_list, don't actually run finalizers but |
| 8923 | * queue finalizable objects back to heap_allocated as is. This is |
| 8924 | * used during heap destruction to deal with finalizers that keep |
| 8925 | * on creating more finalizable garbage. |
| 8926 | */ |
| 8927 | duk_uint_t pf_skip_finalizers; |
| 8928 | |
| 8929 | #if defined(DUK_USE_ASSERTIONS) |
| 8930 | /* Set when we're in a critical path where an error throw would cause |
| 8931 | * e.g. sandboxing/protected call violations or state corruption. This |
| 8932 | * is just used for asserts. |
| 8933 | */ |
| 8934 | duk_bool_t error_not_allowed; |
| 8935 | #endif |
| 8936 | |
| 8937 | #if defined(DUK_USE_ASSERTIONS) |
| 8938 | /* Set when heap is still being initialized, helps with writing |
| 8939 | * some assertions. |
| 8940 | */ |
| 8941 | duk_bool_t heap_initializing; |
| 8942 | #endif |
| 8943 | |
| 8944 | /* Marker for detecting internal "double faults", errors thrown when |
| 8945 | * we're trying to create an error object, see duk_error_throw.c. |
| 8946 | */ |
| 8947 | duk_bool_t creating_error; |
| 8948 | |
| 8949 | /* Marker for indicating we're calling a user error augmentation |
| 8950 | * (errCreate/errThrow) function. Errors created/thrown during |
| 8951 | * such a call are not augmented. |
| 8952 | */ |
| 8953 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 8954 | duk_bool_t augmenting_error; |
| 8955 | #endif |
| 8956 | |
| 8957 | /* Longjmp state. */ |
| 8958 | duk_ljstate lj; |
| 8959 | |
| 8960 | /* Heap thread, used internally and for finalization. */ |
| 8961 | duk_hthread *heap_thread; |
| 8962 | |
| 8963 | /* Current running thread. */ |
| 8964 | duk_hthread *curr_thread; |
| 8965 | |
| 8966 | /* Heap level "stash" object (e.g., various reachability roots). */ |
| 8967 | duk_hobject *heap_object; |
| 8968 | |
| 8969 | /* duk_handle_call / duk_handle_safe_call recursion depth limiting */ |
| 8970 | duk_int_t call_recursion_depth; |
| 8971 | duk_int_t call_recursion_limit; |
| 8972 | |
| 8973 | /* Mix-in value for computing string hashes; should be reasonably unpredictable. */ |
| 8974 | duk_uint32_t hash_seed; |
| 8975 | |
| 8976 | /* Random number state for duk_util_tinyrandom.c. */ |
| 8977 | #if !defined(DUK_USE_GET_RANDOM_DOUBLE) |
| 8978 | #if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) |
| 8979 | duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */ |
| 8980 | #else |
| 8981 | duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */ |
| 8982 | #endif |
| 8983 | #endif |
| 8984 | |
| 8985 | /* Counter for unique local symbol creation. */ |
| 8986 | /* XXX: When 64-bit types are available, it would be more efficient to |
| 8987 | * use a duk_uint64_t at least for incrementing but maybe also for |
| 8988 | * string formatting in the Symbol constructor. |
| 8989 | */ |
| 8990 | duk_uint32_t sym_counter[2]; |
| 8991 | |
| 8992 | /* For manual debugging: instruction count based on executor and |
| 8993 | * interrupt counter book-keeping. Inspect debug logs to see how |
| 8994 | * they match up. |
| 8995 | */ |
| 8996 | #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) |
| 8997 | duk_int_t inst_count_exec; |
| 8998 | duk_int_t inst_count_interrupt; |
| 8999 | #endif |
| 9000 | |
| 9001 | /* Debugger state. */ |
| 9002 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 9003 | /* Callbacks and udata; dbg_read_cb != NULL is used to indicate attached state. */ |
| 9004 | duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */ |
| 9005 | duk_debug_write_function dbg_write_cb; /* required */ |
| 9006 | duk_debug_peek_function dbg_peek_cb; |
| 9007 | duk_debug_read_flush_function dbg_read_flush_cb; |
| 9008 | duk_debug_write_flush_function dbg_write_flush_cb; |
| 9009 | duk_debug_request_function dbg_request_cb; |
| 9010 | duk_debug_detached_function dbg_detached_cb; |
| 9011 | void *dbg_udata; |
| 9012 | |
| 9013 | /* The following are only relevant when debugger is attached. */ |
| 9014 | duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */ |
| 9015 | duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */ |
| 9016 | duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */ |
| 9017 | duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */ |
| 9018 | duk_small_uint_t dbg_pause_flags; /* flags for automatic pause behavior */ |
| 9019 | duk_activation *dbg_pause_act; /* activation related to pause behavior (pause on line change, function entry/exit) */ |
| 9020 | duk_uint32_t dbg_pause_startline; /* starting line number for line change related pause behavior */ |
| 9021 | duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */ |
| 9022 | duk_small_uint_t dbg_breakpoint_count; |
| 9023 | duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */ |
| 9024 | /* XXX: make active breakpoints actual copies instead of pointers? */ |
| 9025 | |
| 9026 | /* These are for rate limiting Status notifications and transport peeking. */ |
| 9027 | duk_uint_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */ |
| 9028 | duk_uint_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */ |
| 9029 | duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */ |
| 9030 | |
| 9031 | /* Used to support single-byte stream lookahead. */ |
| 9032 | duk_bool_t dbg_have_next_byte; |
| 9033 | duk_uint8_t dbg_next_byte; |
| 9034 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 9035 | #if defined(DUK_USE_ASSERTIONS) |
| 9036 | duk_bool_t dbg_calling_transport; /* transport call in progress, calling into Duktape forbidden */ |
| 9037 | #endif |
| 9038 | |
| 9039 | /* String intern table (weak refs). */ |
| 9040 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 9041 | duk_uint16_t *strtable16; |
| 9042 | #else |
| 9043 | duk_hstring **strtable; |
| 9044 | #endif |
| 9045 | duk_uint32_t st_mask; /* mask for lookup, st_size - 1 */ |
| 9046 | duk_uint32_t st_size; /* stringtable size */ |
| 9047 | #if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) |
| 9048 | duk_uint32_t st_count; /* string count for resize load factor checks */ |
| 9049 | #endif |
| 9050 | duk_bool_t st_resizing; /* string table is being resized; avoid recursive resize */ |
| 9051 | |
| 9052 | /* String access cache (codepoint offset -> byte offset) for fast string |
| 9053 | * character looping; 'weak' reference which needs special handling in GC. |
| 9054 | */ |
| 9055 | duk_strcache_entry strcache[DUK_HEAP_STRCACHE_SIZE]; |
| 9056 | |
| 9057 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 9058 | /* Literal intern cache. When enabled, strings interned as literals |
| 9059 | * (e.g. duk_push_literal()) will be pinned and cached for the lifetime |
| 9060 | * of the heap. |
| 9061 | */ |
| 9062 | duk_litcache_entry litcache[DUK_USE_LITCACHE_SIZE]; |
| 9063 | #endif |
| 9064 | |
| 9065 | /* Built-in strings. */ |
| 9066 | #if defined(DUK_USE_ROM_STRINGS) |
| 9067 | /* No field needed when strings are in ROM. */ |
| 9068 | #else |
| 9069 | #if defined(DUK_USE_HEAPPTR16) |
| 9070 | duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS]; |
| 9071 | #else |
| 9072 | duk_hstring *strs[DUK_HEAP_NUM_STRINGS]; |
| 9073 | #endif |
| 9074 | #endif |
| 9075 | |
| 9076 | /* Stats. */ |
| 9077 | #if defined(DUK_USE_DEBUG) |
| 9078 | duk_int_t stats_exec_opcodes; |
| 9079 | duk_int_t stats_exec_interrupt; |
| 9080 | duk_int_t stats_exec_throw; |
| 9081 | duk_int_t stats_call_all; |
| 9082 | duk_int_t stats_call_tailcall; |
| 9083 | duk_int_t stats_call_ecmatoecma; |
| 9084 | duk_int_t stats_safecall_all; |
| 9085 | duk_int_t stats_safecall_nothrow; |
| 9086 | duk_int_t stats_safecall_throw; |
| 9087 | duk_int_t stats_ms_try_count; |
| 9088 | duk_int_t stats_ms_skip_count; |
| 9089 | duk_int_t stats_ms_emergency_count; |
| 9090 | duk_int_t stats_strtab_intern_hit; |
| 9091 | duk_int_t stats_strtab_intern_miss; |
| 9092 | duk_int_t stats_strtab_resize_check; |
| 9093 | duk_int_t stats_strtab_resize_grow; |
| 9094 | duk_int_t stats_strtab_resize_shrink; |
| 9095 | duk_int_t stats_strtab_litcache_hit; |
| 9096 | duk_int_t stats_strtab_litcache_miss; |
| 9097 | duk_int_t stats_strtab_litcache_pin; |
| 9098 | duk_int_t stats_object_realloc_props; |
| 9099 | duk_int_t stats_object_abandon_array; |
| 9100 | duk_int_t stats_getownpropdesc_count; |
| 9101 | duk_int_t stats_getownpropdesc_hit; |
| 9102 | duk_int_t stats_getownpropdesc_miss; |
| 9103 | duk_int_t stats_getpropdesc_count; |
| 9104 | duk_int_t stats_getpropdesc_hit; |
| 9105 | duk_int_t stats_getpropdesc_miss; |
| 9106 | duk_int_t stats_getprop_all; |
| 9107 | duk_int_t stats_getprop_arrayidx; |
| 9108 | duk_int_t stats_getprop_bufobjidx; |
| 9109 | duk_int_t stats_getprop_bufferidx; |
| 9110 | duk_int_t stats_getprop_bufferlen; |
| 9111 | duk_int_t stats_getprop_stringidx; |
| 9112 | duk_int_t stats_getprop_stringlen; |
| 9113 | duk_int_t stats_getprop_proxy; |
| 9114 | duk_int_t stats_getprop_arguments; |
| 9115 | duk_int_t stats_putprop_all; |
| 9116 | duk_int_t stats_putprop_arrayidx; |
| 9117 | duk_int_t stats_putprop_bufobjidx; |
| 9118 | duk_int_t stats_putprop_bufferidx; |
| 9119 | duk_int_t stats_putprop_proxy; |
| 9120 | duk_int_t stats_getvar_all; |
| 9121 | duk_int_t stats_putvar_all; |
| 9122 | duk_int_t stats_envrec_delayedcreate; |
| 9123 | duk_int_t stats_envrec_create; |
| 9124 | duk_int_t stats_envrec_newenv; |
| 9125 | duk_int_t stats_envrec_oldenv; |
| 9126 | duk_int_t stats_envrec_pushclosure; |
| 9127 | #endif |
| 9128 | }; |
| 9129 | |
| 9130 | /* |
| 9131 | * Prototypes |
| 9132 | */ |
| 9133 | |
| 9134 | DUK_INTERNAL_DECL |
| 9135 | duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, |
| 9136 | duk_realloc_function realloc_func, |
| 9137 | duk_free_function free_func, |
| 9138 | void *heap_udata, |
| 9139 | duk_fatal_function fatal_func); |
| 9140 | DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap); |
| 9141 | DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h); |
| 9142 | DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h); |
| 9143 | DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h); |
| 9144 | DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr); |
| 9145 | |
| 9146 | DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); |
| 9147 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 9148 | DUK_INTERNAL_DECL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr); |
| 9149 | #endif |
| 9150 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 9151 | DUK_INTERNAL_DECL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr); |
| 9152 | DUK_INTERNAL_DECL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr); |
| 9153 | #endif |
| 9154 | #if defined(DUK_USE_ASSERTIONS) |
| 9155 | DUK_INTERNAL_DECL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr); |
| 9156 | #endif |
| 9157 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 9158 | DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr); |
| 9159 | #endif |
| 9160 | |
| 9161 | DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen); |
| 9162 | DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len); |
| 9163 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 9164 | DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen); |
| 9165 | #endif |
| 9166 | DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val); |
| 9167 | DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val); |
| 9168 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 9169 | DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h); |
| 9170 | #endif |
| 9171 | DUK_INTERNAL_DECL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev); |
| 9172 | DUK_INTERNAL_DECL void duk_heap_strtable_force_resize(duk_heap *heap); |
| 9173 | DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap); |
| 9174 | #if defined(DUK_USE_DEBUG) |
| 9175 | DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap); |
| 9176 | #endif |
| 9177 | |
| 9178 | DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h); |
| 9179 | DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset); |
| 9180 | |
| 9181 | #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) |
| 9182 | DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size); |
| 9183 | DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize); |
| 9184 | DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr); |
| 9185 | #endif |
| 9186 | |
| 9187 | DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size); |
| 9188 | DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size); |
| 9189 | DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size); |
| 9190 | DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size); |
| 9191 | DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize); |
| 9192 | DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize); |
| 9193 | DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr); |
| 9194 | |
| 9195 | DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap); |
| 9196 | |
| 9197 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 9198 | DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj); |
| 9199 | DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap); |
| 9200 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 9201 | |
| 9202 | DUK_INTERNAL_DECL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags); |
| 9203 | |
| 9204 | DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len); |
| 9205 | |
| 9206 | #endif /* DUK_HEAP_H_INCLUDED */ |
| 9207 | /* #include duk_debugger.h */ |
| 9208 | #line 1 "duk_debugger.h" |
| 9209 | #if !defined(DUK_DEBUGGER_H_INCLUDED) |
| 9210 | #define DUK_DEBUGGER_H_INCLUDED |
| 9211 | |
| 9212 | /* Debugger protocol version is defined in the public API header. */ |
| 9213 | |
| 9214 | /* Initial bytes for markers. */ |
| 9215 | #define DUK_DBG_IB_EOM 0x00 |
| 9216 | #define DUK_DBG_IB_REQUEST 0x01 |
| 9217 | #define DUK_DBG_IB_REPLY 0x02 |
| 9218 | #define DUK_DBG_IB_ERROR 0x03 |
| 9219 | #define DUK_DBG_IB_NOTIFY 0x04 |
| 9220 | |
| 9221 | /* Other initial bytes. */ |
| 9222 | #define DUK_DBG_IB_INT4 0x10 |
| 9223 | #define DUK_DBG_IB_STR4 0x11 |
| 9224 | #define DUK_DBG_IB_STR2 0x12 |
| 9225 | #define DUK_DBG_IB_BUF4 0x13 |
| 9226 | #define DUK_DBG_IB_BUF2 0x14 |
| 9227 | #define DUK_DBG_IB_UNUSED 0x15 |
| 9228 | #define DUK_DBG_IB_UNDEFINED 0x16 |
| 9229 | #define DUK_DBG_IB_NULL 0x17 |
| 9230 | #define DUK_DBG_IB_TRUE 0x18 |
| 9231 | #define DUK_DBG_IB_FALSE 0x19 |
| 9232 | #define DUK_DBG_IB_NUMBER 0x1a |
| 9233 | #define DUK_DBG_IB_OBJECT 0x1b |
| 9234 | #define DUK_DBG_IB_POINTER 0x1c |
| 9235 | #define DUK_DBG_IB_LIGHTFUNC 0x1d |
| 9236 | #define DUK_DBG_IB_HEAPPTR 0x1e |
| 9237 | /* The short string/integer initial bytes starting from 0x60 don't have |
| 9238 | * defines now. |
| 9239 | */ |
| 9240 | |
| 9241 | /* Error codes. */ |
| 9242 | #define DUK_DBG_ERR_UNKNOWN 0x00 |
| 9243 | #define DUK_DBG_ERR_UNSUPPORTED 0x01 |
| 9244 | #define DUK_DBG_ERR_TOOMANY 0x02 |
| 9245 | #define DUK_DBG_ERR_NOTFOUND 0x03 |
| 9246 | #define DUK_DBG_ERR_APPLICATION 0x04 |
| 9247 | |
| 9248 | /* Commands and notifys initiated by Duktape. */ |
| 9249 | #define DUK_DBG_CMD_STATUS 0x01 |
| 9250 | #define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */ |
| 9251 | #define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */ |
| 9252 | #define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */ |
| 9253 | #define DUK_DBG_CMD_THROW 0x05 |
| 9254 | #define DUK_DBG_CMD_DETACHING 0x06 |
| 9255 | #define DUK_DBG_CMD_APPNOTIFY 0x07 |
| 9256 | |
| 9257 | /* Commands initiated by debug client. */ |
| 9258 | #define DUK_DBG_CMD_BASICINFO 0x10 |
| 9259 | #define DUK_DBG_CMD_TRIGGERSTATUS 0x11 |
| 9260 | #define DUK_DBG_CMD_PAUSE 0x12 |
| 9261 | #define DUK_DBG_CMD_RESUME 0x13 |
| 9262 | #define DUK_DBG_CMD_STEPINTO 0x14 |
| 9263 | #define DUK_DBG_CMD_STEPOVER 0x15 |
| 9264 | #define DUK_DBG_CMD_STEPOUT 0x16 |
| 9265 | #define DUK_DBG_CMD_LISTBREAK 0x17 |
| 9266 | #define DUK_DBG_CMD_ADDBREAK 0x18 |
| 9267 | #define DUK_DBG_CMD_DELBREAK 0x19 |
| 9268 | #define DUK_DBG_CMD_GETVAR 0x1a |
| 9269 | #define DUK_DBG_CMD_PUTVAR 0x1b |
| 9270 | #define DUK_DBG_CMD_GETCALLSTACK 0x1c |
| 9271 | #define DUK_DBG_CMD_GETLOCALS 0x1d |
| 9272 | #define DUK_DBG_CMD_EVAL 0x1e |
| 9273 | #define DUK_DBG_CMD_DETACH 0x1f |
| 9274 | #define DUK_DBG_CMD_DUMPHEAP 0x20 |
| 9275 | #define DUK_DBG_CMD_GETBYTECODE 0x21 |
| 9276 | #define DUK_DBG_CMD_APPREQUEST 0x22 |
| 9277 | #define DUK_DBG_CMD_GETHEAPOBJINFO 0x23 |
| 9278 | #define DUK_DBG_CMD_GETOBJPROPDESC 0x24 |
| 9279 | #define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25 |
| 9280 | |
| 9281 | /* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx. |
| 9282 | * The remaining flags are specific to the debugger. |
| 9283 | */ |
| 9284 | #define DUK_DBG_PROPFLAG_SYMBOL (1U << 8) |
| 9285 | #define DUK_DBG_PROPFLAG_HIDDEN (1U << 9) |
| 9286 | |
| 9287 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 9288 | DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap); |
| 9289 | |
| 9290 | DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr); |
| 9291 | DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr); |
| 9292 | |
| 9293 | DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length); |
| 9294 | DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr); |
| 9295 | |
| 9296 | DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length); |
| 9297 | DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr); |
| 9298 | DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr); |
| 9299 | DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr); |
| 9300 | /* XXX: exposed duk_debug_read_pointer */ |
| 9301 | /* XXX: exposed duk_debug_read_buffer */ |
| 9302 | /* XXX: exposed duk_debug_read_hbuffer */ |
| 9303 | #if 0 |
| 9304 | DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr); |
| 9305 | #endif |
| 9306 | #if defined(DUK_USE_DEBUGGER_INSPECT) |
| 9307 | DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr); |
| 9308 | #endif |
| 9309 | DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr); |
| 9310 | |
| 9311 | DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length); |
| 9312 | DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x); |
| 9313 | DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr); |
| 9314 | DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr); |
| 9315 | #if defined(DUK_USE_DEBUGGER_INSPECT) |
| 9316 | DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr); |
| 9317 | #endif |
| 9318 | DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val); |
| 9319 | DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x); |
| 9320 | DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x); |
| 9321 | DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length); |
| 9322 | DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data); |
| 9323 | DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h); |
| 9324 | DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length); |
| 9325 | DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h); |
| 9326 | DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr); |
| 9327 | #if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT) |
| 9328 | DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h); |
| 9329 | #endif |
| 9330 | DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj); |
| 9331 | DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv); |
| 9332 | #if 0 /* unused */ |
| 9333 | DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command); |
| 9334 | #endif |
| 9335 | DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr); |
| 9336 | DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg); |
| 9337 | DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command); |
| 9338 | DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr); |
| 9339 | |
| 9340 | DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr); |
| 9341 | DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr); |
| 9342 | #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) |
| 9343 | DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal); |
| 9344 | #endif |
| 9345 | |
| 9346 | DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc); |
| 9347 | DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block); |
| 9348 | |
| 9349 | DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line); |
| 9350 | DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index); |
| 9351 | |
| 9352 | DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap); |
| 9353 | DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap); |
| 9354 | DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap); |
| 9355 | DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap); |
| 9356 | DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap); |
| 9357 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 9358 | |
| 9359 | #endif /* DUK_DEBUGGER_H_INCLUDED */ |
| 9360 | /* #include duk_debug.h */ |
| 9361 | #line 1 "duk_debug.h" |
| 9362 | /* |
| 9363 | * Debugging macros, DUK_DPRINT() and its variants in particular. |
| 9364 | * |
| 9365 | * DUK_DPRINT() allows formatted debug prints, and supports standard |
| 9366 | * and Duktape specific formatters. See duk_debug_vsnprintf.c for details. |
| 9367 | * |
| 9368 | * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros |
| 9369 | * for technical reasons. They are concretely used to hide 'x' from the |
| 9370 | * compiler when the corresponding log level is disabled. This allows |
| 9371 | * clean builds on non-C99 compilers, at the cost of more verbose code. |
| 9372 | * Examples: |
| 9373 | * |
| 9374 | * DUK_D(DUK_DPRINT("foo")); |
| 9375 | * DUK_DD(DUK_DDPRINT("foo")); |
| 9376 | * DUK_DDD(DUK_DDDPRINT("foo")); |
| 9377 | * |
| 9378 | * This approach is preferable to the old "double parentheses" hack because |
| 9379 | * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can |
| 9380 | * no longer be added transparently without going through globals, which |
| 9381 | * works poorly with threading. |
| 9382 | */ |
| 9383 | |
| 9384 | #if !defined(DUK_DEBUG_H_INCLUDED) |
| 9385 | #define DUK_DEBUG_H_INCLUDED |
| 9386 | |
| 9387 | #if defined(DUK_USE_DEBUG) |
| 9388 | |
| 9389 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) |
| 9390 | #define DUK_D(x) x |
| 9391 | #else |
| 9392 | #define DUK_D(x) do { } while (0) /* omit */ |
| 9393 | #endif |
| 9394 | |
| 9395 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) |
| 9396 | #define DUK_DD(x) x |
| 9397 | #else |
| 9398 | #define DUK_DD(x) do { } while (0) /* omit */ |
| 9399 | #endif |
| 9400 | |
| 9401 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 9402 | #define DUK_DDD(x) x |
| 9403 | #else |
| 9404 | #define DUK_DDD(x) do { } while (0) /* omit */ |
| 9405 | #endif |
| 9406 | |
| 9407 | /* |
| 9408 | * Exposed debug macros: debugging enabled |
| 9409 | */ |
| 9410 | |
| 9411 | #if defined(DUK_USE_VARIADIC_MACROS) |
| 9412 | |
| 9413 | /* Note: combining __FILE__, __LINE__, and __func__ into fmt would be |
| 9414 | * possible compile time, but waste some space with shared function names. |
| 9415 | */ |
| 9416 | #define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__); |
| 9417 | |
| 9418 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) |
| 9419 | #define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__) |
| 9420 | #else |
| 9421 | #define DUK_DPRINT(...) |
| 9422 | #endif |
| 9423 | |
| 9424 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) |
| 9425 | #define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__) |
| 9426 | #else |
| 9427 | #define DUK_DDPRINT(...) |
| 9428 | #endif |
| 9429 | |
| 9430 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 9431 | #define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__) |
| 9432 | #else |
| 9433 | #define DUK_DDDPRINT(...) |
| 9434 | #endif |
| 9435 | |
| 9436 | #else /* DUK_USE_VARIADIC_MACROS */ |
| 9437 | |
| 9438 | #define DUK__DEBUG_STASH(lev) \ |
| 9439 | (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \ |
| 9440 | (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \ |
| 9441 | (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \ |
| 9442 | (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \ |
| 9443 | (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \ |
| 9444 | (void) (duk_debug_level_stash = (lev)) |
| 9445 | |
| 9446 | /* Without variadic macros resort to comma expression trickery to handle debug |
| 9447 | * prints. This generates a lot of harmless warnings. These hacks are not |
| 9448 | * needed normally because DUK_D() and friends will hide the entire debug log |
| 9449 | * statement from the compiler. |
| 9450 | */ |
| 9451 | |
| 9452 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0) |
| 9453 | #define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */ |
| 9454 | #else |
| 9455 | #define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ |
| 9456 | #endif |
| 9457 | |
| 9458 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) |
| 9459 | #define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */ |
| 9460 | #else |
| 9461 | #define DUK_DDPRINT 0 && /* args */ |
| 9462 | #endif |
| 9463 | |
| 9464 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 9465 | #define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */ |
| 9466 | #else |
| 9467 | #define DUK_DDDPRINT 0 && /* args */ |
| 9468 | #endif |
| 9469 | |
| 9470 | #endif /* DUK_USE_VARIADIC_MACROS */ |
| 9471 | |
| 9472 | #else /* DUK_USE_DEBUG */ |
| 9473 | |
| 9474 | /* |
| 9475 | * Exposed debug macros: debugging disabled |
| 9476 | */ |
| 9477 | |
| 9478 | #define DUK_D(x) do { } while (0) /* omit */ |
| 9479 | #define DUK_DD(x) do { } while (0) /* omit */ |
| 9480 | #define DUK_DDD(x) do { } while (0) /* omit */ |
| 9481 | |
| 9482 | #if defined(DUK_USE_VARIADIC_MACROS) |
| 9483 | |
| 9484 | #define DUK_DPRINT(...) |
| 9485 | #define DUK_DDPRINT(...) |
| 9486 | #define DUK_DDDPRINT(...) |
| 9487 | |
| 9488 | #else /* DUK_USE_VARIADIC_MACROS */ |
| 9489 | |
| 9490 | #define DUK_DPRINT 0 && /* args go here as a comma expression in parens */ |
| 9491 | #define DUK_DDPRINT 0 && /* args */ |
| 9492 | #define DUK_DDDPRINT 0 && /* args */ |
| 9493 | |
| 9494 | #endif /* DUK_USE_VARIADIC_MACROS */ |
| 9495 | |
| 9496 | #endif /* DUK_USE_DEBUG */ |
| 9497 | |
| 9498 | /* |
| 9499 | * Structs |
| 9500 | */ |
| 9501 | |
| 9502 | #if defined(DUK_USE_DEBUG) |
| 9503 | struct duk_fixedbuffer { |
| 9504 | duk_uint8_t *buffer; |
| 9505 | duk_size_t length; |
| 9506 | duk_size_t offset; |
| 9507 | duk_bool_t truncated; |
| 9508 | }; |
| 9509 | #endif |
| 9510 | |
| 9511 | /* |
| 9512 | * Prototypes |
| 9513 | */ |
| 9514 | |
| 9515 | #if defined(DUK_USE_DEBUG) |
| 9516 | DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap); |
| 9517 | #if 0 /*unused*/ |
| 9518 | DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...); |
| 9519 | #endif |
| 9520 | DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size); |
| 9521 | |
| 9522 | #if defined(DUK_USE_VARIADIC_MACROS) |
| 9523 | DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...); |
| 9524 | #else /* DUK_USE_VARIADIC_MACROS */ |
| 9525 | /* parameter passing, not thread safe */ |
| 9526 | #define DUK_DEBUG_STASH_SIZE 128 |
| 9527 | #if !defined(DUK_SINGLE_FILE) |
| 9528 | DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; |
| 9529 | DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash; |
| 9530 | DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; |
| 9531 | DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash; |
| 9532 | #endif |
| 9533 | DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...); |
| 9534 | #endif /* DUK_USE_VARIADIC_MACROS */ |
| 9535 | |
| 9536 | DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length); |
| 9537 | DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x); |
| 9538 | DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x); |
| 9539 | DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...); |
| 9540 | DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size); |
| 9541 | DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb); |
| 9542 | |
| 9543 | #endif /* DUK_USE_DEBUG */ |
| 9544 | |
| 9545 | #endif /* DUK_DEBUG_H_INCLUDED */ |
| 9546 | /* #include duk_error.h */ |
| 9547 | #line 1 "duk_error.h" |
| 9548 | /* |
| 9549 | * Error handling macros, assertion macro, error codes. |
| 9550 | * |
| 9551 | * There are three types of 'errors': |
| 9552 | * |
| 9553 | * 1. Ordinary errors relative to a thread, cause a longjmp, catchable. |
| 9554 | * 2. Fatal errors relative to a heap, cause fatal handler to be called. |
| 9555 | * 3. Fatal errors without context, cause the default (not heap specific) |
| 9556 | * fatal handler to be called. |
| 9557 | * |
| 9558 | * Fatal errors without context are used by debug code such as assertions. |
| 9559 | * By providing a fatal error handler for a Duktape heap, user code can |
| 9560 | * avoid fatal errors without context in non-debug builds. |
| 9561 | */ |
| 9562 | |
| 9563 | #if !defined(DUK_ERROR_H_INCLUDED) |
| 9564 | #define DUK_ERROR_H_INCLUDED |
| 9565 | |
| 9566 | /* |
| 9567 | * Error codes: defined in duktape.h |
| 9568 | * |
| 9569 | * Error codes are used as a shorthand to throw exceptions from inside |
| 9570 | * the implementation. The appropriate ECMAScript object is constructed |
| 9571 | * based on the code. ECMAScript code throws objects directly. The error |
| 9572 | * codes are defined in the public API header because they are also used |
| 9573 | * by calling code. |
| 9574 | */ |
| 9575 | |
| 9576 | /* |
| 9577 | * Normal error |
| 9578 | * |
| 9579 | * Normal error is thrown with a longjmp() through the current setjmp() |
| 9580 | * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap |
| 9581 | * identifies the throwing thread. |
| 9582 | * |
| 9583 | * Error formatting is usually unnecessary. The error macros provide a |
| 9584 | * zero argument version (no formatting) and separate macros for small |
| 9585 | * argument counts. Variadic macros are not used to avoid portability |
| 9586 | * issues and avoid the need for stash-based workarounds when they're not |
| 9587 | * available. Vararg calls are avoided for non-formatted error calls |
| 9588 | * because vararg call sites are larger than normal, and there are a lot |
| 9589 | * of call sites with no formatting. |
| 9590 | * |
| 9591 | * Note that special formatting provided by debug macros is NOT available. |
| 9592 | * |
| 9593 | * The _RAW variants allow the caller to specify file and line. This makes |
| 9594 | * it easier to write checked calls which want to use the call site of the |
| 9595 | * checked function, not the error macro call inside the checked function. |
| 9596 | */ |
| 9597 | |
| 9598 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 9599 | |
| 9600 | /* Because there are quite many call sites, pack error code (require at most |
| 9601 | * 8-bit) into a single argument. |
| 9602 | */ |
| 9603 | #define DUK_ERROR(thr,err,msg) do { \ |
| 9604 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ |
| 9605 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9606 | duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \ |
| 9607 | } while (0) |
| 9608 | #define DUK_ERROR_RAW(thr,file,line,err,msg) do { \ |
| 9609 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ |
| 9610 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9611 | duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \ |
| 9612 | } while (0) |
| 9613 | |
| 9614 | #define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \ |
| 9615 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ |
| 9616 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9617 | duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \ |
| 9618 | } while (0) |
| 9619 | #define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \ |
| 9620 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ |
| 9621 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9622 | duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \ |
| 9623 | } while (0) |
| 9624 | |
| 9625 | #define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \ |
| 9626 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ |
| 9627 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9628 | duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \ |
| 9629 | } while (0) |
| 9630 | #define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \ |
| 9631 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ |
| 9632 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9633 | duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \ |
| 9634 | } while (0) |
| 9635 | |
| 9636 | #define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \ |
| 9637 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ |
| 9638 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9639 | duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \ |
| 9640 | } while (0) |
| 9641 | #define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \ |
| 9642 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ |
| 9643 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9644 | duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \ |
| 9645 | } while (0) |
| 9646 | |
| 9647 | #define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \ |
| 9648 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \ |
| 9649 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9650 | duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \ |
| 9651 | } while (0) |
| 9652 | #define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \ |
| 9653 | duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \ |
| 9654 | DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \ |
| 9655 | duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \ |
| 9656 | } while (0) |
| 9657 | |
| 9658 | #else /* DUK_USE_VERBOSE_ERRORS */ |
| 9659 | |
| 9660 | #define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err)) |
| 9661 | #define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err)) |
| 9662 | |
| 9663 | #define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt)) |
| 9664 | #define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) |
| 9665 | |
| 9666 | #define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt)) |
| 9667 | #define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) |
| 9668 | |
| 9669 | #define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt)) |
| 9670 | #define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) |
| 9671 | |
| 9672 | #define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt)) |
| 9673 | #define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt)) |
| 9674 | |
| 9675 | #endif /* DUK_USE_VERBOSE_ERRORS */ |
| 9676 | |
| 9677 | /* |
| 9678 | * Fatal error without context |
| 9679 | * |
| 9680 | * The macro is an expression to make it compatible with DUK_ASSERT_EXPR(). |
| 9681 | */ |
| 9682 | |
| 9683 | #define DUK_FATAL_WITHOUT_CONTEXT(msg) \ |
| 9684 | duk_default_fatal_handler(NULL, (msg)) |
| 9685 | |
| 9686 | /* |
| 9687 | * Error throwing helpers |
| 9688 | * |
| 9689 | * The goal is to provide verbose and configurable error messages. Call |
| 9690 | * sites should be clean in source code and compile to a small footprint. |
| 9691 | * Small footprint is also useful for performance because small cold paths |
| 9692 | * reduce code cache pressure. Adding macros here only makes sense if there |
| 9693 | * are enough call sites to get concrete benefits. |
| 9694 | * |
| 9695 | * DUK_ERROR_xxx() macros are generic and can be used anywhere. |
| 9696 | * |
| 9697 | * DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where |
| 9698 | * the "return DUK_RET_xxx;" shorthand is available for low memory targets. |
| 9699 | * The DUK_DCERROR_xxx() macros always either throw or perform a |
| 9700 | * 'return DUK_RET_xxx' from the calling function. |
| 9701 | */ |
| 9702 | |
| 9703 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 9704 | /* Verbose errors with key/value summaries (non-paranoid) or without key/value |
| 9705 | * summaries (paranoid, for some security sensitive environments), the paranoid |
| 9706 | * vs. non-paranoid distinction affects only a few specific errors. |
| 9707 | */ |
| 9708 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 9709 | #define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ |
| 9710 | duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \ |
| 9711 | } while (0) |
| 9712 | #else /* DUK_USE_PARANOID_ERRORS */ |
| 9713 | #define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ |
| 9714 | duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \ |
| 9715 | } while (0) |
| 9716 | #endif /* DUK_USE_PARANOID_ERRORS */ |
| 9717 | |
| 9718 | #define DUK_ERROR_INTERNAL(thr) do { \ |
| 9719 | duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ |
| 9720 | } while (0) |
| 9721 | #define DUK_DCERROR_INTERNAL(thr) do { \ |
| 9722 | DUK_ERROR_INTERNAL((thr)); \ |
| 9723 | return 0; \ |
| 9724 | } while (0) |
| 9725 | #define DUK_ERROR_ALLOC_FAILED(thr) do { \ |
| 9726 | duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ |
| 9727 | } while (0) |
| 9728 | #define DUK_ERROR_UNSUPPORTED(thr) do { \ |
| 9729 | DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \ |
| 9730 | } while (0) |
| 9731 | #define DUK_DCERROR_UNSUPPORTED(thr) do { \ |
| 9732 | DUK_ERROR_UNSUPPORTED((thr)); \ |
| 9733 | return 0; \ |
| 9734 | } while (0) |
| 9735 | #define DUK_ERROR_ERROR(thr,msg) do { \ |
| 9736 | duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ |
| 9737 | } while (0) |
| 9738 | #define DUK_ERROR_RANGE_INDEX(thr,idx) do { \ |
| 9739 | duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \ |
| 9740 | } while (0) |
| 9741 | #define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \ |
| 9742 | duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ |
| 9743 | } while (0) |
| 9744 | #define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \ |
| 9745 | DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \ |
| 9746 | } while (0) |
| 9747 | #define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \ |
| 9748 | DUK_ERROR_RANGE_INVALID_ARGS((thr)); \ |
| 9749 | return 0; \ |
| 9750 | } while (0) |
| 9751 | #define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \ |
| 9752 | DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \ |
| 9753 | } while (0) |
| 9754 | #define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \ |
| 9755 | DUK_ERROR_RANGE_INVALID_COUNT((thr)); \ |
| 9756 | return 0; \ |
| 9757 | } while (0) |
| 9758 | #define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \ |
| 9759 | DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \ |
| 9760 | } while (0) |
| 9761 | #define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \ |
| 9762 | DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \ |
| 9763 | return 0; \ |
| 9764 | } while (0) |
| 9765 | #define DUK_ERROR_RANGE(thr,msg) do { \ |
| 9766 | duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \ |
| 9767 | } while (0) |
| 9768 | #define DUK_ERROR_EVAL(thr,msg) do { \ |
| 9769 | DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \ |
| 9770 | } while (0) |
| 9771 | #define DUK_ERROR_REFERENCE(thr,msg) do { \ |
| 9772 | DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \ |
| 9773 | } while (0) |
| 9774 | #define DUK_ERROR_SYNTAX(thr,msg) do { \ |
| 9775 | DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \ |
| 9776 | } while (0) |
| 9777 | #define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \ |
| 9778 | duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ |
| 9779 | } while (0) |
| 9780 | #define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \ |
| 9781 | DUK_ERROR_TYPE_INVALID_ARGS((thr)); \ |
| 9782 | return 0; \ |
| 9783 | } while (0) |
| 9784 | #define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \ |
| 9785 | duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ |
| 9786 | } while (0) |
| 9787 | #define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \ |
| 9788 | DUK_ERROR_TYPE_INVALID_STATE((thr)); \ |
| 9789 | return 0; \ |
| 9790 | } while (0) |
| 9791 | #define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ |
| 9792 | duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \ |
| 9793 | } while (0) |
| 9794 | #define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ |
| 9795 | DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \ |
| 9796 | } while (0) |
| 9797 | #define DUK_ERROR_TYPE(thr,msg) do { \ |
| 9798 | DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \ |
| 9799 | } while (0) |
| 9800 | #define DUK_ERROR_URI(thr,msg) do { \ |
| 9801 | DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \ |
| 9802 | } while (0) |
| 9803 | #else /* DUK_USE_VERBOSE_ERRORS */ |
| 9804 | /* Non-verbose errors for low memory targets: no file, line, or message. */ |
| 9805 | |
| 9806 | #define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \ |
| 9807 | duk_err_type((thr)); \ |
| 9808 | } while (0) |
| 9809 | |
| 9810 | #define DUK_ERROR_INTERNAL(thr) do { \ |
| 9811 | duk_err_error((thr)); \ |
| 9812 | } while (0) |
| 9813 | #define DUK_DCERROR_INTERNAL(thr) do { \ |
| 9814 | DUK_UNREF((thr)); \ |
| 9815 | return DUK_RET_ERROR; \ |
| 9816 | } while (0) |
| 9817 | #define DUK_ERROR_ALLOC_FAILED(thr) do { \ |
| 9818 | duk_err_error((thr)); \ |
| 9819 | } while (0) |
| 9820 | #define DUK_ERROR_UNSUPPORTED(thr) do { \ |
| 9821 | duk_err_error((thr)); \ |
| 9822 | } while (0) |
| 9823 | #define DUK_DCERROR_UNSUPPORTED(thr) do { \ |
| 9824 | DUK_UNREF((thr)); \ |
| 9825 | return DUK_RET_ERROR; \ |
| 9826 | } while (0) |
| 9827 | #define DUK_ERROR_ERROR(thr,msg) do { \ |
| 9828 | duk_err_error((thr)); \ |
| 9829 | } while (0) |
| 9830 | #define DUK_ERROR_RANGE_INDEX(thr,idx) do { \ |
| 9831 | duk_err_range((thr)); \ |
| 9832 | } while (0) |
| 9833 | #define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \ |
| 9834 | duk_err_range((thr)); \ |
| 9835 | } while (0) |
| 9836 | #define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \ |
| 9837 | duk_err_range((thr)); \ |
| 9838 | } while (0) |
| 9839 | #define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \ |
| 9840 | DUK_UNREF((thr)); \ |
| 9841 | return DUK_RET_RANGE_ERROR; \ |
| 9842 | } while (0) |
| 9843 | #define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \ |
| 9844 | duk_err_range((thr)); \ |
| 9845 | } while (0) |
| 9846 | #define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \ |
| 9847 | DUK_UNREF((thr)); \ |
| 9848 | return DUK_RET_RANGE_ERROR; \ |
| 9849 | } while (0) |
| 9850 | #define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \ |
| 9851 | duk_err_range((thr)); \ |
| 9852 | } while (0) |
| 9853 | #define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \ |
| 9854 | DUK_UNREF((thr)); \ |
| 9855 | return DUK_RET_RANGE_ERROR; \ |
| 9856 | } while (0) |
| 9857 | #define DUK_ERROR_RANGE(thr,msg) do { \ |
| 9858 | duk_err_range((thr)); \ |
| 9859 | } while (0) |
| 9860 | #define DUK_ERROR_EVAL(thr,msg) do { \ |
| 9861 | duk_err_eval((thr)); \ |
| 9862 | } while (0) |
| 9863 | #define DUK_ERROR_REFERENCE(thr,msg) do { \ |
| 9864 | duk_err_reference((thr)); \ |
| 9865 | } while (0) |
| 9866 | #define DUK_ERROR_SYNTAX(thr,msg) do { \ |
| 9867 | duk_err_syntax((thr)); \ |
| 9868 | } while (0) |
| 9869 | #define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \ |
| 9870 | duk_err_type((thr)); \ |
| 9871 | } while (0) |
| 9872 | #define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \ |
| 9873 | DUK_UNREF((thr)); \ |
| 9874 | return DUK_RET_TYPE_ERROR; \ |
| 9875 | } while (0) |
| 9876 | #define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \ |
| 9877 | duk_err_type((thr)); \ |
| 9878 | } while (0) |
| 9879 | #define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \ |
| 9880 | duk_err_type((thr)); \ |
| 9881 | } while (0) |
| 9882 | #define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ |
| 9883 | duk_err_type((thr)); \ |
| 9884 | } while (0) |
| 9885 | #define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ |
| 9886 | DUK_UNREF((thr)); \ |
| 9887 | return DUK_RET_TYPE_ERROR; \ |
| 9888 | } while (0) |
| 9889 | #define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \ |
| 9890 | duk_err_type((thr)); \ |
| 9891 | } while (0) |
| 9892 | #define DUK_ERROR_TYPE(thr,msg) do { \ |
| 9893 | duk_err_type((thr)); \ |
| 9894 | } while (0) |
| 9895 | #define DUK_ERROR_URI(thr,msg) do { \ |
| 9896 | duk_err_uri((thr)); \ |
| 9897 | } while (0) |
| 9898 | #endif /* DUK_USE_VERBOSE_ERRORS */ |
| 9899 | |
| 9900 | /* |
| 9901 | * Assert macro: failure causes a fatal error. |
| 9902 | * |
| 9903 | * NOTE: since the assert macro doesn't take a heap/context argument, there's |
| 9904 | * no way to look up a heap/context specific fatal error handler which may have |
| 9905 | * been given by the application. Instead, assertion failures always use the |
| 9906 | * internal default fatal error handler; it can be replaced via duk_config.h |
| 9907 | * and then applies to all Duktape heaps. |
| 9908 | */ |
| 9909 | |
| 9910 | #if defined(DUK_USE_ASSERTIONS) |
| 9911 | |
| 9912 | /* The message should be a compile time constant without formatting (less risk); |
| 9913 | * we don't care about assertion text size because they're not used in production |
| 9914 | * builds. |
| 9915 | */ |
| 9916 | #define DUK_ASSERT(x) do { \ |
| 9917 | if (!(x)) { \ |
| 9918 | DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \ |
| 9919 | " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \ |
| 9920 | } \ |
| 9921 | } while (0) |
| 9922 | |
| 9923 | /* Assertion compatible inside a comma expression, evaluates to void. */ |
| 9924 | #define DUK_ASSERT_EXPR(x) \ |
| 9925 | ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \ |
| 9926 | " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0))) |
| 9927 | |
| 9928 | #else /* DUK_USE_ASSERTIONS */ |
| 9929 | |
| 9930 | #define DUK_ASSERT(x) do { /* assertion omitted */ } while (0) |
| 9931 | |
| 9932 | #define DUK_ASSERT_EXPR(x) ((void) 0) |
| 9933 | |
| 9934 | #endif /* DUK_USE_ASSERTIONS */ |
| 9935 | |
| 9936 | /* this variant is used when an assert would generate a compile warning by |
| 9937 | * being always true (e.g. >= 0 comparison for an unsigned value |
| 9938 | */ |
| 9939 | #define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0) |
| 9940 | |
| 9941 | /* |
| 9942 | * Assertion helpers |
| 9943 | */ |
| 9944 | |
| 9945 | #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) |
| 9946 | #define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \ |
| 9947 | DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \ |
| 9948 | } while (0) |
| 9949 | #define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \ |
| 9950 | if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \ |
| 9951 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \ |
| 9952 | } \ |
| 9953 | } while (0) |
| 9954 | #else |
| 9955 | #define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */ |
| 9956 | #define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */ |
| 9957 | #endif |
| 9958 | |
| 9959 | #define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n)) |
| 9960 | |
| 9961 | #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL) |
| 9962 | #define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \ |
| 9963 | duk_double_union duk__assert_tmp_du; \ |
| 9964 | duk__assert_tmp_du.d = (dval); \ |
| 9965 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \ |
| 9966 | } while (0) |
| 9967 | #else |
| 9968 | #define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */ |
| 9969 | #endif |
| 9970 | |
| 9971 | #define DUK_ASSERT_VS_SPACE(thr) \ |
| 9972 | DUK_ASSERT(thr->valstack_top < thr->valstack_end) |
| 9973 | |
| 9974 | /* |
| 9975 | * Helper to initialize a memory area (e.g. struct) with garbage when |
| 9976 | * assertions enabled. |
| 9977 | */ |
| 9978 | |
| 9979 | #if defined(DUK_USE_ASSERTIONS) |
| 9980 | #define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \ |
| 9981 | duk_memset_unsafe((void *) (ptr), 0x5a, size); \ |
| 9982 | } while (0) |
| 9983 | #else |
| 9984 | #define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0) |
| 9985 | #endif |
| 9986 | |
| 9987 | /* |
| 9988 | * Helper for valstack space |
| 9989 | * |
| 9990 | * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries |
| 9991 | * required for its own use, and any child calls which are not (a) Duktape API calls |
| 9992 | * or (b) Duktape calls which involve extending the valstack (e.g. getter call). |
| 9993 | */ |
| 9994 | |
| 9995 | #define 5 /* this is added to checks to allow for Duktape |
| 9996 | * API calls in addition to function's own use |
| 9997 | */ |
| 9998 | #if defined(DUK_USE_ASSERTIONS) |
| 9999 | #define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \ |
| 10000 | DUK_ASSERT((thr) != NULL); \ |
| 10001 | DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \ |
| 10002 | } while (0) |
| 10003 | #else |
| 10004 | #define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */ |
| 10005 | #endif |
| 10006 | |
| 10007 | /* |
| 10008 | * Prototypes |
| 10009 | */ |
| 10010 | |
| 10011 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 10012 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg)); |
| 10013 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...)); |
| 10014 | #else /* DUK_USE_VERBOSE_ERRORS */ |
| 10015 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code)); |
| 10016 | #endif /* DUK_USE_VERBOSE_ERRORS */ |
| 10017 | |
| 10018 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 10019 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line)); |
| 10020 | #else |
| 10021 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code)); |
| 10022 | #endif |
| 10023 | |
| 10024 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc)); |
| 10025 | |
| 10026 | #define DUK_AUGMENT_FLAG_NOBLAME_FILELINE (1U << 0) /* if set, don't blame C file/line for .fileName and .lineNumber */ |
| 10027 | #define DUK_AUGMENT_FLAG_SKIP_ONE (1U << 1) /* if set, skip topmost activation in traceback construction */ |
| 10028 | |
| 10029 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 10030 | DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_small_uint_t flags); |
| 10031 | #endif |
| 10032 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) |
| 10033 | DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr); |
| 10034 | #endif |
| 10035 | |
| 10036 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 10037 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 10038 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name)); |
| 10039 | #else |
| 10040 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name)); |
| 10041 | #endif |
| 10042 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber)); |
| 10043 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber)); |
| 10044 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); |
| 10045 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx)); |
| 10046 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber)); |
| 10047 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message)); |
| 10048 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber)); |
| 10049 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber)); |
| 10050 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber)); |
| 10051 | #else /* DUK_VERBOSE_ERRORS */ |
| 10052 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr)); |
| 10053 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr)); |
| 10054 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr)); |
| 10055 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr)); |
| 10056 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr)); |
| 10057 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr)); |
| 10058 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr)); |
| 10059 | #endif /* DUK_VERBOSE_ERRORS */ |
| 10060 | |
| 10061 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr)); |
| 10062 | |
| 10063 | DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg)); |
| 10064 | |
| 10065 | DUK_INTERNAL_DECL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val); |
| 10066 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 10067 | DUK_INTERNAL_DECL void duk_err_check_debugger_integration(duk_hthread *thr); |
| 10068 | #endif |
| 10069 | |
| 10070 | DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code); |
| 10071 | |
| 10072 | #endif /* DUK_ERROR_H_INCLUDED */ |
| 10073 | /* #include duk_unicode.h */ |
| 10074 | #line 1 "duk_unicode.h" |
| 10075 | /* |
| 10076 | * Unicode helpers |
| 10077 | */ |
| 10078 | |
| 10079 | #if !defined(DUK_UNICODE_H_INCLUDED) |
| 10080 | #define DUK_UNICODE_H_INCLUDED |
| 10081 | |
| 10082 | /* |
| 10083 | * UTF-8 / XUTF-8 / CESU-8 constants |
| 10084 | */ |
| 10085 | |
| 10086 | #define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */ |
| 10087 | #define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */ |
| 10088 | #define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */ |
| 10089 | #define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */ |
| 10090 | |
| 10091 | /* |
| 10092 | * Useful Unicode codepoints |
| 10093 | * |
| 10094 | * Integer constants must be signed to avoid unexpected coercions |
| 10095 | * in comparisons. |
| 10096 | */ |
| 10097 | |
| 10098 | #define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */ |
| 10099 | #define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */ |
| 10100 | #define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */ |
| 10101 | |
| 10102 | /* |
| 10103 | * ASCII character constants |
| 10104 | * |
| 10105 | * C character literals like 'x' have a platform specific value and do |
| 10106 | * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use |
| 10107 | * these (admittedly awkward) constants instead. These constants must |
| 10108 | * also have signed values to avoid unexpected coercions in comparisons. |
| 10109 | * |
| 10110 | * http://en.wikipedia.org/wiki/ASCII |
| 10111 | */ |
| 10112 | |
| 10113 | #define DUK_ASC_NUL 0x00 |
| 10114 | #define DUK_ASC_SOH 0x01 |
| 10115 | #define DUK_ASC_STX 0x02 |
| 10116 | #define DUK_ASC_ETX 0x03 |
| 10117 | #define DUK_ASC_EOT 0x04 |
| 10118 | #define DUK_ASC_ENQ 0x05 |
| 10119 | #define DUK_ASC_ACK 0x06 |
| 10120 | #define DUK_ASC_BEL 0x07 |
| 10121 | #define DUK_ASC_BS 0x08 |
| 10122 | #define DUK_ASC_HT 0x09 |
| 10123 | #define DUK_ASC_LF 0x0a |
| 10124 | #define DUK_ASC_VT 0x0b |
| 10125 | #define DUK_ASC_FF 0x0c |
| 10126 | #define DUK_ASC_CR 0x0d |
| 10127 | #define DUK_ASC_SO 0x0e |
| 10128 | #define DUK_ASC_SI 0x0f |
| 10129 | #define DUK_ASC_DLE 0x10 |
| 10130 | #define DUK_ASC_DC1 0x11 |
| 10131 | #define DUK_ASC_DC2 0x12 |
| 10132 | #define DUK_ASC_DC3 0x13 |
| 10133 | #define DUK_ASC_DC4 0x14 |
| 10134 | #define DUK_ASC_NAK 0x15 |
| 10135 | #define DUK_ASC_SYN 0x16 |
| 10136 | #define DUK_ASC_ETB 0x17 |
| 10137 | #define DUK_ASC_CAN 0x18 |
| 10138 | #define DUK_ASC_EM 0x19 |
| 10139 | #define DUK_ASC_SUB 0x1a |
| 10140 | #define DUK_ASC_ESC 0x1b |
| 10141 | #define DUK_ASC_FS 0x1c |
| 10142 | #define DUK_ASC_GS 0x1d |
| 10143 | #define DUK_ASC_RS 0x1e |
| 10144 | #define DUK_ASC_US 0x1f |
| 10145 | #define DUK_ASC_SPACE 0x20 |
| 10146 | #define DUK_ASC_EXCLAMATION 0x21 |
| 10147 | #define DUK_ASC_DOUBLEQUOTE 0x22 |
| 10148 | #define DUK_ASC_HASH 0x23 |
| 10149 | #define DUK_ASC_DOLLAR 0x24 |
| 10150 | #define DUK_ASC_PERCENT 0x25 |
| 10151 | #define DUK_ASC_AMP 0x26 |
| 10152 | #define DUK_ASC_SINGLEQUOTE 0x27 |
| 10153 | #define DUK_ASC_LPAREN 0x28 |
| 10154 | #define DUK_ASC_RPAREN 0x29 |
| 10155 | #define DUK_ASC_STAR 0x2a |
| 10156 | #define DUK_ASC_PLUS 0x2b |
| 10157 | #define DUK_ASC_COMMA 0x2c |
| 10158 | #define DUK_ASC_MINUS 0x2d |
| 10159 | #define DUK_ASC_PERIOD 0x2e |
| 10160 | #define DUK_ASC_SLASH 0x2f |
| 10161 | #define DUK_ASC_0 0x30 |
| 10162 | #define DUK_ASC_1 0x31 |
| 10163 | #define DUK_ASC_2 0x32 |
| 10164 | #define DUK_ASC_3 0x33 |
| 10165 | #define DUK_ASC_4 0x34 |
| 10166 | #define DUK_ASC_5 0x35 |
| 10167 | #define DUK_ASC_6 0x36 |
| 10168 | #define DUK_ASC_7 0x37 |
| 10169 | #define DUK_ASC_8 0x38 |
| 10170 | #define DUK_ASC_9 0x39 |
| 10171 | #define DUK_ASC_COLON 0x3a |
| 10172 | #define DUK_ASC_SEMICOLON 0x3b |
| 10173 | #define DUK_ASC_LANGLE 0x3c |
| 10174 | #define DUK_ASC_EQUALS 0x3d |
| 10175 | #define DUK_ASC_RANGLE 0x3e |
| 10176 | #define DUK_ASC_QUESTION 0x3f |
| 10177 | #define DUK_ASC_ATSIGN 0x40 |
| 10178 | #define DUK_ASC_UC_A 0x41 |
| 10179 | #define DUK_ASC_UC_B 0x42 |
| 10180 | #define DUK_ASC_UC_C 0x43 |
| 10181 | #define DUK_ASC_UC_D 0x44 |
| 10182 | #define DUK_ASC_UC_E 0x45 |
| 10183 | #define DUK_ASC_UC_F 0x46 |
| 10184 | #define DUK_ASC_UC_G 0x47 |
| 10185 | #define DUK_ASC_UC_H 0x48 |
| 10186 | #define DUK_ASC_UC_I 0x49 |
| 10187 | #define DUK_ASC_UC_J 0x4a |
| 10188 | #define DUK_ASC_UC_K 0x4b |
| 10189 | #define DUK_ASC_UC_L 0x4c |
| 10190 | #define DUK_ASC_UC_M 0x4d |
| 10191 | #define DUK_ASC_UC_N 0x4e |
| 10192 | #define DUK_ASC_UC_O 0x4f |
| 10193 | #define DUK_ASC_UC_P 0x50 |
| 10194 | #define DUK_ASC_UC_Q 0x51 |
| 10195 | #define DUK_ASC_UC_R 0x52 |
| 10196 | #define DUK_ASC_UC_S 0x53 |
| 10197 | #define DUK_ASC_UC_T 0x54 |
| 10198 | #define DUK_ASC_UC_U 0x55 |
| 10199 | #define DUK_ASC_UC_V 0x56 |
| 10200 | #define DUK_ASC_UC_W 0x57 |
| 10201 | #define DUK_ASC_UC_X 0x58 |
| 10202 | #define DUK_ASC_UC_Y 0x59 |
| 10203 | #define DUK_ASC_UC_Z 0x5a |
| 10204 | #define DUK_ASC_LBRACKET 0x5b |
| 10205 | #define DUK_ASC_BACKSLASH 0x5c |
| 10206 | #define DUK_ASC_RBRACKET 0x5d |
| 10207 | #define DUK_ASC_CARET 0x5e |
| 10208 | #define DUK_ASC_UNDERSCORE 0x5f |
| 10209 | #define DUK_ASC_GRAVE 0x60 |
| 10210 | #define DUK_ASC_LC_A 0x61 |
| 10211 | #define DUK_ASC_LC_B 0x62 |
| 10212 | #define DUK_ASC_LC_C 0x63 |
| 10213 | #define DUK_ASC_LC_D 0x64 |
| 10214 | #define DUK_ASC_LC_E 0x65 |
| 10215 | #define DUK_ASC_LC_F 0x66 |
| 10216 | #define DUK_ASC_LC_G 0x67 |
| 10217 | #define DUK_ASC_LC_H 0x68 |
| 10218 | #define DUK_ASC_LC_I 0x69 |
| 10219 | #define DUK_ASC_LC_J 0x6a |
| 10220 | #define DUK_ASC_LC_K 0x6b |
| 10221 | #define DUK_ASC_LC_L 0x6c |
| 10222 | #define DUK_ASC_LC_M 0x6d |
| 10223 | #define DUK_ASC_LC_N 0x6e |
| 10224 | #define DUK_ASC_LC_O 0x6f |
| 10225 | #define DUK_ASC_LC_P 0x70 |
| 10226 | #define DUK_ASC_LC_Q 0x71 |
| 10227 | #define DUK_ASC_LC_R 0x72 |
| 10228 | #define DUK_ASC_LC_S 0x73 |
| 10229 | #define DUK_ASC_LC_T 0x74 |
| 10230 | #define DUK_ASC_LC_U 0x75 |
| 10231 | #define DUK_ASC_LC_V 0x76 |
| 10232 | #define DUK_ASC_LC_W 0x77 |
| 10233 | #define DUK_ASC_LC_X 0x78 |
| 10234 | #define DUK_ASC_LC_Y 0x79 |
| 10235 | #define DUK_ASC_LC_Z 0x7a |
| 10236 | #define DUK_ASC_LCURLY 0x7b |
| 10237 | #define DUK_ASC_PIPE 0x7c |
| 10238 | #define DUK_ASC_RCURLY 0x7d |
| 10239 | #define DUK_ASC_TILDE 0x7e |
| 10240 | #define DUK_ASC_DEL 0x7f |
| 10241 | |
| 10242 | /* |
| 10243 | * Miscellaneous |
| 10244 | */ |
| 10245 | |
| 10246 | /* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase |
| 10247 | * to lowercase. |
| 10248 | */ |
| 10249 | #define DUK_LOWERCASE_CHAR_ASCII(x) ((x) | 0x20) |
| 10250 | |
| 10251 | /* |
| 10252 | * Unicode tables |
| 10253 | */ |
| 10254 | |
| 10255 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 10256 | /* |
| 10257 | * Automatically generated by extract_chars.py, do not edit! |
| 10258 | */ |
| 10259 | |
| 10260 | extern const duk_uint8_t duk_unicode_ids_noa[1116]; |
| 10261 | #else |
| 10262 | /* |
| 10263 | * Automatically generated by extract_chars.py, do not edit! |
| 10264 | */ |
| 10265 | |
| 10266 | extern const duk_uint8_t duk_unicode_ids_noabmp[625]; |
| 10267 | #endif |
| 10268 | |
| 10269 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 10270 | /* |
| 10271 | * Automatically generated by extract_chars.py, do not edit! |
| 10272 | */ |
| 10273 | |
| 10274 | extern const duk_uint8_t duk_unicode_ids_m_let_noa[42]; |
| 10275 | #else |
| 10276 | /* |
| 10277 | * Automatically generated by extract_chars.py, do not edit! |
| 10278 | */ |
| 10279 | |
| 10280 | extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24]; |
| 10281 | #endif |
| 10282 | |
| 10283 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 10284 | /* |
| 10285 | * Automatically generated by extract_chars.py, do not edit! |
| 10286 | */ |
| 10287 | |
| 10288 | extern const duk_uint8_t duk_unicode_idp_m_ids_noa[576]; |
| 10289 | #else |
| 10290 | /* |
| 10291 | * Automatically generated by extract_chars.py, do not edit! |
| 10292 | */ |
| 10293 | |
| 10294 | extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358]; |
| 10295 | #endif |
| 10296 | |
| 10297 | /* |
| 10298 | * Automatically generated by extract_caseconv.py, do not edit! |
| 10299 | */ |
| 10300 | |
| 10301 | extern const duk_uint8_t duk_unicode_caseconv_uc[1411]; |
| 10302 | extern const duk_uint8_t duk_unicode_caseconv_lc[706]; |
| 10303 | |
| 10304 | #if defined(DUK_USE_REGEXP_CANON_WORKAROUND) |
| 10305 | /* |
| 10306 | * Automatically generated by extract_caseconv.py, do not edit! |
| 10307 | */ |
| 10308 | |
| 10309 | extern const duk_uint16_t duk_unicode_re_canon_lookup[65536]; |
| 10310 | #endif |
| 10311 | |
| 10312 | #if defined(DUK_USE_REGEXP_CANON_BITMAP) |
| 10313 | /* |
| 10314 | * Automatically generated by extract_caseconv.py, do not edit! |
| 10315 | */ |
| 10316 | |
| 10317 | #define DUK_CANON_BITMAP_BLKSIZE 32 |
| 10318 | #define DUK_CANON_BITMAP_BLKSHIFT 5 |
| 10319 | #define DUK_CANON_BITMAP_BLKMASK 31 |
| 10320 | extern const duk_uint8_t duk_unicode_re_canon_bitmap[256]; |
| 10321 | #endif |
| 10322 | |
| 10323 | /* |
| 10324 | * Extern |
| 10325 | */ |
| 10326 | |
| 10327 | /* duk_unicode_support.c */ |
| 10328 | #if !defined(DUK_SINGLE_FILE) |
| 10329 | DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7]; |
| 10330 | DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2]; |
| 10331 | DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22]; |
| 10332 | DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8]; |
| 10333 | DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4]; |
| 10334 | DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24]; |
| 10335 | DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10]; |
| 10336 | DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128]; |
| 10337 | #endif /* !DUK_SINGLE_FILE */ |
| 10338 | |
| 10339 | /* |
| 10340 | * Prototypes |
| 10341 | */ |
| 10342 | |
| 10343 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp); |
| 10344 | #if defined(DUK_USE_ASSERTIONS) |
| 10345 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp); |
| 10346 | #endif |
| 10347 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out); |
| 10348 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out); |
| 10349 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp); |
| 10350 | DUK_INTERNAL_DECL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end); |
| 10351 | DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen); |
| 10352 | DUK_INTERNAL_DECL duk_bool_t duk_unicode_is_utf8_compatible(const duk_uint8_t *buf, duk_size_t len); |
| 10353 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp); |
| 10354 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp); |
| 10355 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp); |
| 10356 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp); |
| 10357 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp); |
| 10358 | DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase); |
| 10359 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 10360 | DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp); |
| 10361 | DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp); |
| 10362 | #endif |
| 10363 | |
| 10364 | #endif /* DUK_UNICODE_H_INCLUDED */ |
| 10365 | /* #include duk_json.h */ |
| 10366 | #line 1 "duk_json.h" |
| 10367 | /* |
| 10368 | * Defines for JSON, especially duk_bi_json.c. |
| 10369 | */ |
| 10370 | |
| 10371 | #if !defined(DUK_JSON_H_INCLUDED) |
| 10372 | #define DUK_JSON_H_INCLUDED |
| 10373 | |
| 10374 | /* Encoding/decoding flags */ |
| 10375 | #define DUK_JSON_FLAG_ASCII_ONLY (1U << 0) /* escape any non-ASCII characters */ |
| 10376 | #define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1U << 1) /* avoid key quotes when key is an ASCII Identifier */ |
| 10377 | #define DUK_JSON_FLAG_EXT_CUSTOM (1U << 2) /* extended types: custom encoding */ |
| 10378 | #define DUK_JSON_FLAG_EXT_COMPATIBLE (1U << 3) /* extended types: compatible encoding */ |
| 10379 | |
| 10380 | /* How much stack to require on entry to object/array encode */ |
| 10381 | #define DUK_JSON_ENC_REQSTACK 32 |
| 10382 | |
| 10383 | /* How much stack to require on entry to object/array decode */ |
| 10384 | #define DUK_JSON_DEC_REQSTACK 32 |
| 10385 | |
| 10386 | /* How large a loop detection stack to use */ |
| 10387 | #define DUK_JSON_ENC_LOOPARRAY 64 |
| 10388 | |
| 10389 | /* Encoding state. Heap object references are all borrowed. */ |
| 10390 | typedef struct { |
| 10391 | duk_hthread *thr; |
| 10392 | duk_bufwriter_ctx bw; /* output bufwriter */ |
| 10393 | duk_hobject *h_replacer; /* replacer function */ |
| 10394 | duk_hstring *h_gap; /* gap (if empty string, NULL) */ |
| 10395 | duk_idx_t idx_proplist; /* explicit PropertyList */ |
| 10396 | duk_idx_t idx_loop; /* valstack index of loop detection object */ |
| 10397 | duk_small_uint_t flags; |
| 10398 | duk_small_uint_t flag_ascii_only; |
| 10399 | duk_small_uint_t flag_avoid_key_quotes; |
| 10400 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 10401 | duk_small_uint_t flag_ext_custom; |
| 10402 | duk_small_uint_t flag_ext_compatible; |
| 10403 | duk_small_uint_t flag_ext_custom_or_compatible; |
| 10404 | #endif |
| 10405 | duk_uint_t recursion_depth; |
| 10406 | duk_uint_t recursion_limit; |
| 10407 | duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */ |
| 10408 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 10409 | duk_small_uint_t stridx_custom_undefined; |
| 10410 | duk_small_uint_t stridx_custom_nan; |
| 10411 | duk_small_uint_t stridx_custom_neginf; |
| 10412 | duk_small_uint_t stridx_custom_posinf; |
| 10413 | duk_small_uint_t stridx_custom_function; |
| 10414 | #endif |
| 10415 | duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */ |
| 10416 | } duk_json_enc_ctx; |
| 10417 | |
| 10418 | typedef struct { |
| 10419 | duk_hthread *thr; |
| 10420 | const duk_uint8_t *p; |
| 10421 | const duk_uint8_t *p_start; |
| 10422 | const duk_uint8_t *p_end; |
| 10423 | duk_idx_t idx_reviver; |
| 10424 | duk_small_uint_t flags; |
| 10425 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 10426 | duk_small_uint_t flag_ext_custom; |
| 10427 | duk_small_uint_t flag_ext_compatible; |
| 10428 | duk_small_uint_t flag_ext_custom_or_compatible; |
| 10429 | #endif |
| 10430 | duk_int_t recursion_depth; |
| 10431 | duk_int_t recursion_limit; |
| 10432 | } duk_json_dec_ctx; |
| 10433 | |
| 10434 | #endif /* DUK_JSON_H_INCLUDED */ |
| 10435 | /* #include duk_js.h */ |
| 10436 | #line 1 "duk_js.h" |
| 10437 | /* |
| 10438 | * ECMAScript execution, support primitives. |
| 10439 | */ |
| 10440 | |
| 10441 | #if !defined(DUK_JS_H_INCLUDED) |
| 10442 | #define DUK_JS_H_INCLUDED |
| 10443 | |
| 10444 | /* Flags for call handling. Lowest flags must match bytecode DUK_BC_CALL_FLAG_xxx 1:1. */ |
| 10445 | #define DUK_CALL_FLAG_TAILCALL (1U << 0) /* setup for a tail call */ |
| 10446 | #define DUK_CALL_FLAG_CONSTRUCT (1U << 1) /* constructor call (i.e. called as 'new Foo()') */ |
| 10447 | #define DUK_CALL_FLAG_CALLED_AS_EVAL (1U << 2) /* call was made using the identifier 'eval' */ |
| 10448 | #define DUK_CALL_FLAG_ALLOW_ECMATOECMA (1U << 3) /* ecma-to-ecma call with executor reuse is possible */ |
| 10449 | #define DUK_CALL_FLAG_DIRECT_EVAL (1U << 4) /* call is a direct eval call */ |
| 10450 | #define DUK_CALL_FLAG_CONSTRUCT_PROXY (1U << 5) /* handled via 'construct' proxy trap, check return value invariant(s) */ |
| 10451 | #define DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED (1U << 6) /* prototype of 'default instance' updated, temporary flag in call handling */ |
| 10452 | |
| 10453 | /* Flags for duk_js_equals_helper(). */ |
| 10454 | #define DUK_EQUALS_FLAG_SAMEVALUE (1U << 0) /* use SameValue instead of non-strict equality */ |
| 10455 | #define DUK_EQUALS_FLAG_STRICT (1U << 1) /* use strict equality instead of non-strict equality */ |
| 10456 | |
| 10457 | /* Flags for duk_js_compare_helper(). */ |
| 10458 | #define DUK_COMPARE_FLAG_NEGATE (1U << 0) /* negate result */ |
| 10459 | #define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1U << 1) /* eval left argument first */ |
| 10460 | |
| 10461 | /* conversions, coercions, comparison, etc */ |
| 10462 | DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv); |
| 10463 | DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv); |
| 10464 | DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x); |
| 10465 | DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv); |
| 10466 | DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv); |
| 10467 | DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv); |
| 10468 | DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv); |
| 10469 | DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen); |
| 10470 | #if !defined(DUK_USE_HSTRING_ARRIDX) |
| 10471 | DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h); |
| 10472 | DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h); |
| 10473 | #endif |
| 10474 | DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags); |
| 10475 | DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2); |
| 10476 | DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2); |
| 10477 | #if 0 /* unused */ |
| 10478 | DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2); |
| 10479 | #endif |
| 10480 | DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags); |
| 10481 | DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); |
| 10482 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 10483 | DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); |
| 10484 | #endif |
| 10485 | DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y); |
| 10486 | DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x); |
| 10487 | DUK_INTERNAL_DECL duk_bool_t duk_js_isarray_hobject(duk_hobject *h); |
| 10488 | DUK_INTERNAL_DECL duk_bool_t duk_js_isarray(duk_tval *tv); |
| 10489 | |
| 10490 | /* arithmetic */ |
| 10491 | DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y); |
| 10492 | DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y); |
| 10493 | |
| 10494 | #define duk_js_equals(thr,tv_x,tv_y) \ |
| 10495 | duk_js_equals_helper((thr), (tv_x), (tv_y), 0) |
| 10496 | #define duk_js_strict_equals(tv_x,tv_y) \ |
| 10497 | duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT) |
| 10498 | #define duk_js_samevalue(tv_x,tv_y) \ |
| 10499 | duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE) |
| 10500 | |
| 10501 | /* E5 Sections 11.8.1, 11.8.5; x < y */ |
| 10502 | #define duk_js_lessthan(thr,tv_x,tv_y) \ |
| 10503 | duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) |
| 10504 | |
| 10505 | /* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */ |
| 10506 | #define duk_js_greaterthan(thr,tv_x,tv_y) \ |
| 10507 | duk_js_compare_helper((thr), (tv_y), (tv_x), 0) |
| 10508 | |
| 10509 | /* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */ |
| 10510 | #define duk_js_lessthanorequal(thr,tv_x,tv_y) \ |
| 10511 | duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE) |
| 10512 | |
| 10513 | /* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */ |
| 10514 | #define duk_js_greaterthanorequal(thr,tv_x,tv_y) \ |
| 10515 | duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE) |
| 10516 | |
| 10517 | /* identifiers and environment handling */ |
| 10518 | #if 0 /*unused*/ |
| 10519 | DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name); |
| 10520 | #endif |
| 10521 | DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag); |
| 10522 | DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag); |
| 10523 | DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict); |
| 10524 | DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict); |
| 10525 | #if 0 /*unused*/ |
| 10526 | DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name); |
| 10527 | #endif |
| 10528 | DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name); |
| 10529 | DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_uint_t prop_flags, duk_bool_t is_func_decl); |
| 10530 | DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act); |
| 10531 | DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env); |
| 10532 | DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t bottom_byteoff); |
| 10533 | DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, |
| 10534 | duk_hcompfunc *fun_temp, |
| 10535 | duk_hobject *outer_var_env, |
| 10536 | duk_hobject *outer_lex_env, |
| 10537 | duk_bool_t add_auto_proto); |
| 10538 | |
| 10539 | /* call handling */ |
| 10540 | DUK_INTERNAL_DECL void duk_native_stack_check(duk_hthread *thr); |
| 10541 | DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t idx_func, duk_small_uint_t call_flags); |
| 10542 | DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags); |
| 10543 | DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t num_stack_args, duk_idx_t num_stack_res); |
| 10544 | DUK_INTERNAL_DECL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant); |
| 10545 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 10546 | DUK_INTERNAL_DECL void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_base, duk_tval *tv_key); |
| 10547 | #endif |
| 10548 | |
| 10549 | /* bytecode execution */ |
| 10550 | DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr); |
| 10551 | |
| 10552 | #endif /* DUK_JS_H_INCLUDED */ |
| 10553 | /* #include duk_numconv.h */ |
| 10554 | #line 1 "duk_numconv.h" |
| 10555 | /* |
| 10556 | * Number-to-string conversion. The semantics of these is very tightly |
| 10557 | * bound with the ECMAScript semantics required for call sites. |
| 10558 | */ |
| 10559 | |
| 10560 | #if !defined(DUK_NUMCONV_H_INCLUDED) |
| 10561 | #define DUK_NUMCONV_H_INCLUDED |
| 10562 | |
| 10563 | /* Output a specified number of digits instead of using the shortest |
| 10564 | * form. Used for toPrecision() and toFixed(). |
| 10565 | */ |
| 10566 | #define DUK_N2S_FLAG_FIXED_FORMAT (1U << 0) |
| 10567 | |
| 10568 | /* Force exponential format. Used for toExponential(). */ |
| 10569 | #define DUK_N2S_FLAG_FORCE_EXP (1U << 1) |
| 10570 | |
| 10571 | /* If number would need zero padding (for whole number part), use |
| 10572 | * exponential format instead. E.g. if input number is 12300, 3 |
| 10573 | * digits are generated ("123"), output "1.23e+4" instead of "12300". |
| 10574 | * Used for toPrecision(). |
| 10575 | */ |
| 10576 | #define DUK_N2S_FLAG_NO_ZERO_PAD (1U << 2) |
| 10577 | |
| 10578 | /* Digit count indicates number of fractions (i.e. an absolute |
| 10579 | * digit index instead of a relative one). Used together with |
| 10580 | * DUK_N2S_FLAG_FIXED_FORMAT for toFixed(). |
| 10581 | */ |
| 10582 | #define DUK_N2S_FLAG_FRACTION_DIGITS (1U << 3) |
| 10583 | |
| 10584 | /* |
| 10585 | * String-to-number conversion |
| 10586 | */ |
| 10587 | |
| 10588 | /* Maximum exponent value when parsing numbers. This is not strictly |
| 10589 | * compliant as there should be no upper limit, but as we parse the |
| 10590 | * exponent without a bigint, impose some limit. The limit should be |
| 10591 | * small enough that multiplying it (or limit-1 to be precise) won't |
| 10592 | * overflow signed 32-bit integer range. Exponent is only parsed with |
| 10593 | * radix 10, but with maximum radix (36) a safe limit is: |
| 10594 | * (10000000*36).toString(16) -> '15752a00' |
| 10595 | */ |
| 10596 | #define DUK_S2N_MAX_EXPONENT 10000000L |
| 10597 | |
| 10598 | /* Trim white space (= allow leading and trailing whitespace) */ |
| 10599 | #define DUK_S2N_FLAG_TRIM_WHITE (1U << 0) |
| 10600 | |
| 10601 | /* Allow exponent */ |
| 10602 | #define DUK_S2N_FLAG_ALLOW_EXP (1U << 1) |
| 10603 | |
| 10604 | /* Allow trailing garbage (e.g. treat "123foo" as "123) */ |
| 10605 | #define DUK_S2N_FLAG_ALLOW_GARBAGE (1U << 2) |
| 10606 | |
| 10607 | /* Allow leading plus sign */ |
| 10608 | #define DUK_S2N_FLAG_ALLOW_PLUS (1U << 3) |
| 10609 | |
| 10610 | /* Allow leading minus sign */ |
| 10611 | #define DUK_S2N_FLAG_ALLOW_MINUS (1U << 4) |
| 10612 | |
| 10613 | /* Allow 'Infinity' */ |
| 10614 | #define DUK_S2N_FLAG_ALLOW_INF (1U << 5) |
| 10615 | |
| 10616 | /* Allow fraction part */ |
| 10617 | #define DUK_S2N_FLAG_ALLOW_FRAC (1U << 6) |
| 10618 | |
| 10619 | /* Allow naked fraction (e.g. ".123") */ |
| 10620 | #define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1U << 7) |
| 10621 | |
| 10622 | /* Allow empty fraction (e.g. "123.") */ |
| 10623 | #define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1U << 8) |
| 10624 | |
| 10625 | /* Allow empty string to be interpreted as 0 */ |
| 10626 | #define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1U << 9) |
| 10627 | |
| 10628 | /* Allow leading zeroes (e.g. "0123" -> "123") */ |
| 10629 | #define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1U << 10) |
| 10630 | |
| 10631 | /* Allow automatic detection of hex base ("0x" or "0X" prefix), |
| 10632 | * overrides radix argument and forces integer mode. |
| 10633 | */ |
| 10634 | #define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1U << 11) |
| 10635 | |
| 10636 | /* Allow automatic detection of legacy octal base ("0n"), |
| 10637 | * overrides radix argument and forces integer mode. |
| 10638 | */ |
| 10639 | #define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1U << 12) |
| 10640 | |
| 10641 | /* Allow automatic detection of ES2015 octal base ("0o123"), |
| 10642 | * overrides radix argument and forces integer mode. |
| 10643 | */ |
| 10644 | #define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1U << 13) |
| 10645 | |
| 10646 | /* Allow automatic detection of ES2015 binary base ("0b10001"), |
| 10647 | * overrides radix argument and forces integer mode. |
| 10648 | */ |
| 10649 | #define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1U << 14) |
| 10650 | |
| 10651 | /* |
| 10652 | * Prototypes |
| 10653 | */ |
| 10654 | |
| 10655 | DUK_INTERNAL_DECL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags); |
| 10656 | DUK_INTERNAL_DECL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags); |
| 10657 | |
| 10658 | #endif /* DUK_NUMCONV_H_INCLUDED */ |
| 10659 | /* #include duk_bi_protos.h */ |
| 10660 | #line 1 "duk_bi_protos.h" |
| 10661 | /* |
| 10662 | * Prototypes for built-in functions not automatically covered by the |
| 10663 | * header declarations emitted by genbuiltins.py. |
| 10664 | */ |
| 10665 | |
| 10666 | #if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED) |
| 10667 | #define DUK_BUILTIN_PROTOS_H_INCLUDED |
| 10668 | |
| 10669 | /* Buffer size needed for ISO 8601 formatting. |
| 10670 | * Accurate value is 32 + 1 for NUL termination: |
| 10671 | * >>> len('+123456-01-23T12:34:56.123+12:34') |
| 10672 | * 32 |
| 10673 | * Include additional space to be safe. |
| 10674 | */ |
| 10675 | #define DUK_BI_DATE_ISO8601_BUFSIZE 40 |
| 10676 | |
| 10677 | /* Helpers exposed for internal use */ |
| 10678 | DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags); |
| 10679 | DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags); |
| 10680 | DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year); |
| 10681 | DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x); |
| 10682 | DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year); |
| 10683 | DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x); |
| 10684 | /* Built-in providers */ |
| 10685 | #if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) |
| 10686 | DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void); |
| 10687 | #endif |
| 10688 | #if defined(DUK_USE_DATE_NOW_TIME) |
| 10689 | DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void); |
| 10690 | #endif |
| 10691 | #if defined(DUK_USE_DATE_NOW_WINDOWS) |
| 10692 | DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void); |
| 10693 | #endif |
| 10694 | #if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) |
| 10695 | DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void); |
| 10696 | #endif |
| 10697 | #if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME) |
| 10698 | DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d); |
| 10699 | #endif |
| 10700 | #if defined(DUK_USE_DATE_TZO_WINDOWS) |
| 10701 | DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d); |
| 10702 | #endif |
| 10703 | #if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) |
| 10704 | DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d); |
| 10705 | #endif |
| 10706 | #if defined(DUK_USE_DATE_PRS_STRPTIME) |
| 10707 | DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str); |
| 10708 | #endif |
| 10709 | #if defined(DUK_USE_DATE_PRS_GETDATE) |
| 10710 | DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str); |
| 10711 | #endif |
| 10712 | #if defined(DUK_USE_DATE_FMT_STRFTIME) |
| 10713 | DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags); |
| 10714 | #endif |
| 10715 | |
| 10716 | #if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME) |
| 10717 | DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void); |
| 10718 | #endif |
| 10719 | #if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) |
| 10720 | DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void); |
| 10721 | #endif |
| 10722 | |
| 10723 | DUK_INTERNAL_DECL |
| 10724 | void duk_bi_json_parse_helper(duk_hthread *thr, |
| 10725 | duk_idx_t idx_value, |
| 10726 | duk_idx_t idx_reviver, |
| 10727 | duk_small_uint_t flags); |
| 10728 | DUK_INTERNAL_DECL |
| 10729 | void duk_bi_json_stringify_helper(duk_hthread *thr, |
| 10730 | duk_idx_t idx_value, |
| 10731 | duk_idx_t idx_replacer, |
| 10732 | duk_idx_t idx_space, |
| 10733 | duk_small_uint_t flags); |
| 10734 | |
| 10735 | DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr); |
| 10736 | |
| 10737 | #if defined(DUK_USE_ES6_PROXY) |
| 10738 | DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags); |
| 10739 | #endif |
| 10740 | |
| 10741 | #endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */ |
| 10742 | /* #include duk_selftest.h */ |
| 10743 | #line 1 "duk_selftest.h" |
| 10744 | /* |
| 10745 | * Selftest code |
| 10746 | */ |
| 10747 | |
| 10748 | #if !defined(DUK_SELFTEST_H_INCLUDED) |
| 10749 | #define DUK_SELFTEST_H_INCLUDED |
| 10750 | |
| 10751 | #if defined(DUK_USE_SELF_TESTS) |
| 10752 | DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func, |
| 10753 | duk_realloc_function realloc_func, |
| 10754 | duk_free_function free_func, |
| 10755 | void *udata); |
| 10756 | #endif |
| 10757 | |
| 10758 | #endif /* DUK_SELFTEST_H_INCLUDED */ |
| 10759 | #line 76 "duk_internal.h" |
| 10760 | |
| 10761 | #endif /* DUK_INTERNAL_H_INCLUDED */ |
| 10762 | #line 10 "duk_replacements.c" |
| 10763 | |
| 10764 | #if defined(DUK_USE_COMPUTED_NAN) |
| 10765 | DUK_INTERNAL double duk_computed_nan; |
| 10766 | #endif |
| 10767 | |
| 10768 | #if defined(DUK_USE_COMPUTED_INFINITY) |
| 10769 | DUK_INTERNAL double duk_computed_infinity; |
| 10770 | #endif |
| 10771 | |
| 10772 | #if defined(DUK_USE_REPL_FPCLASSIFY) |
| 10773 | DUK_INTERNAL int duk_repl_fpclassify(double x) { |
| 10774 | duk_double_union u; |
| 10775 | duk_uint_fast16_t expt; |
| 10776 | duk_small_int_t mzero; |
| 10777 | |
| 10778 | u.d = x; |
| 10779 | expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL); |
| 10780 | if (expt > 0x0000UL && expt < 0x7ff0UL) { |
| 10781 | /* expt values [0x001,0x7fe] = normal */ |
| 10782 | return DUK_FP_NORMAL; |
| 10783 | } |
| 10784 | |
| 10785 | mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0); |
| 10786 | if (expt == 0x0000UL) { |
| 10787 | /* expt 0x000 is zero/subnormal */ |
| 10788 | if (mzero) { |
| 10789 | return DUK_FP_ZERO; |
| 10790 | } else { |
| 10791 | return DUK_FP_SUBNORMAL; |
| 10792 | } |
| 10793 | } else { |
| 10794 | /* expt 0xfff is infinite/nan */ |
| 10795 | if (mzero) { |
| 10796 | return DUK_FP_INFINITE; |
| 10797 | } else { |
| 10798 | return DUK_FP_NAN; |
| 10799 | } |
| 10800 | } |
| 10801 | } |
| 10802 | #endif |
| 10803 | |
| 10804 | #if defined(DUK_USE_REPL_SIGNBIT) |
| 10805 | DUK_INTERNAL int duk_repl_signbit(double x) { |
| 10806 | duk_double_union u; |
| 10807 | u.d = x; |
| 10808 | return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL); |
| 10809 | } |
| 10810 | #endif |
| 10811 | |
| 10812 | #if defined(DUK_USE_REPL_ISFINITE) |
| 10813 | DUK_INTERNAL int duk_repl_isfinite(double x) { |
| 10814 | int c = DUK_FPCLASSIFY(x); |
| 10815 | if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { |
| 10816 | return 0; |
| 10817 | } else { |
| 10818 | return 1; |
| 10819 | } |
| 10820 | } |
| 10821 | #endif |
| 10822 | |
| 10823 | #if defined(DUK_USE_REPL_ISNAN) |
| 10824 | DUK_INTERNAL int duk_repl_isnan(double x) { |
| 10825 | int c = DUK_FPCLASSIFY(x); |
| 10826 | return (c == DUK_FP_NAN); |
| 10827 | } |
| 10828 | #endif |
| 10829 | |
| 10830 | #if defined(DUK_USE_REPL_ISINF) |
| 10831 | DUK_INTERNAL int duk_repl_isinf(double x) { |
| 10832 | int c = DUK_FPCLASSIFY(x); |
| 10833 | return (c == DUK_FP_INFINITE); |
| 10834 | } |
| 10835 | #endif |
| 10836 | #line 1 "duk_debug_macros.c" |
| 10837 | /* |
| 10838 | * Debugging macro calls. |
| 10839 | */ |
| 10840 | |
| 10841 | /* #include duk_internal.h -> already included */ |
| 10842 | |
| 10843 | #if defined(DUK_USE_DEBUG) |
| 10844 | |
| 10845 | /* |
| 10846 | * Debugging enabled |
| 10847 | */ |
| 10848 | |
| 10849 | #include <stdio.h> |
| 10850 | #include <stdlib.h> |
| 10851 | #include <stdarg.h> |
| 10852 | |
| 10853 | #if !defined(DUK_USE_DEBUG_WRITE) |
| 10854 | #error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined |
| 10855 | #endif |
| 10856 | |
| 10857 | #define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE |
| 10858 | |
| 10859 | #if defined(DUK_USE_VARIADIC_MACROS) |
| 10860 | |
| 10861 | DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) { |
| 10862 | va_list ap; |
| 10863 | long arg_level; |
| 10864 | const char *arg_file; |
| 10865 | long arg_line; |
| 10866 | const char *arg_func; |
| 10867 | const char *arg_msg; |
| 10868 | char buf[DUK__DEBUG_BUFSIZE]; |
| 10869 | |
| 10870 | va_start(ap, fmt); |
| 10871 | |
| 10872 | duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); |
| 10873 | duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); |
| 10874 | |
| 10875 | arg_level = (long) level; |
| 10876 | arg_file = (const char *) file; |
| 10877 | arg_line = (long) line; |
| 10878 | arg_func = (const char *) func; |
| 10879 | arg_msg = (const char *) buf; |
| 10880 | DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg); |
| 10881 | |
| 10882 | va_end(ap); |
| 10883 | } |
| 10884 | |
| 10885 | #else /* DUK_USE_VARIADIC_MACROS */ |
| 10886 | |
| 10887 | DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE]; |
| 10888 | DUK_INTERNAL duk_int_t duk_debug_line_stash; |
| 10889 | DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE]; |
| 10890 | DUK_INTERNAL duk_int_t duk_debug_level_stash; |
| 10891 | |
| 10892 | DUK_INTERNAL void duk_debug_log(const char *fmt, ...) { |
| 10893 | va_list ap; |
| 10894 | long arg_level; |
| 10895 | const char *arg_file; |
| 10896 | long arg_line; |
| 10897 | const char *arg_func; |
| 10898 | const char *arg_msg; |
| 10899 | char buf[DUK__DEBUG_BUFSIZE]; |
| 10900 | |
| 10901 | va_start(ap, fmt); |
| 10902 | |
| 10903 | duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE); |
| 10904 | duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap); |
| 10905 | |
| 10906 | arg_level = (long) duk_debug_level_stash; |
| 10907 | arg_file = (const char *) duk_debug_file_stash; |
| 10908 | arg_line = (long) duk_debug_line_stash; |
| 10909 | arg_func = (const char *) duk_debug_func_stash; |
| 10910 | arg_msg = (const char *) buf; |
| 10911 | DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg); |
| 10912 | |
| 10913 | va_end(ap); |
| 10914 | } |
| 10915 | |
| 10916 | #endif /* DUK_USE_VARIADIC_MACROS */ |
| 10917 | |
| 10918 | #else /* DUK_USE_DEBUG */ |
| 10919 | |
| 10920 | /* |
| 10921 | * Debugging disabled |
| 10922 | */ |
| 10923 | |
| 10924 | #endif /* DUK_USE_DEBUG */ |
| 10925 | |
| 10926 | /* automatic undefs */ |
| 10927 | #undef DUK__DEBUG_BUFSIZE |
| 10928 | #line 1 "duk_builtins.c" |
| 10929 | /* |
| 10930 | * Automatically generated by genbuiltins.py, do not edit! |
| 10931 | */ |
| 10932 | |
| 10933 | /* #include duk_internal.h -> already included */ |
| 10934 | |
| 10935 | #if defined(DUK_USE_ASSERTIONS) |
| 10936 | #define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/ |
| 10937 | #else |
| 10938 | #define DUK__REFCINIT(refc) (refc) /*actual*/ |
| 10939 | #endif |
| 10940 | |
| 10941 | #if defined(DUK_USE_ROM_STRINGS) |
| 10942 | #error ROM support not enabled, rerun configure.py with --rom-support |
| 10943 | #else /* DUK_USE_ROM_STRINGS */ |
| 10944 | DUK_INTERNAL const duk_uint8_t duk_strings_data[972] = { |
| 10945 | 79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103, |
| 10946 | 35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31, |
| 10947 | 129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132, |
| 10948 | 140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224, |
| 10949 | 193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32, |
| 10950 | 196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8, |
| 10951 | 196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11, |
| 10952 | 229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10, |
| 10953 | 183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32, |
| 10954 | 184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64, |
| 10955 | 178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18, |
| 10956 | 32,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156, |
| 10957 | 113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115, |
| 10958 | 119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137, |
| 10959 | 101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75, |
| 10960 | 226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64, |
| 10961 | 52,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133, |
| 10962 | 67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2, |
| 10963 | 249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190, |
| 10964 | 186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12, |
| 10965 | 32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226, |
| 10966 | 231,146,51,192,204,73,140,224,145,221,102,241,68,196,169,248,30,75,12,11, |
| 10967 | 151,242,233,187,143,138,24,137,162,164,255,253,63,3,201,97,129,114,254,92, |
| 10968 | 112,75,136,108,166,6,136,159,255,167,224,121,44,48,46,95,203,166,238,74, |
| 10969 | 113,67,77,201,128,223,255,223,224,121,44,48,46,95,203,145,46,9,205,16,39, |
| 10970 | 201,62,36,0,192,21,147,255,238,145,39,199,197,211,116,240,242,113,197,78, |
| 10971 | 214,211,226,233,187,107,105,19,119,37,56,161,166,52,221,212,201,205,36,240, |
| 10972 | 242,16,96,152,12,26,20,164,137,150,70,154,103,28,137,50,202,96,18,132,241, |
| 10973 | 41,104,105,56,218,48,36,138,183,57,56,128,68,24,38,2,52,12,34,10,133,147, |
| 10974 | 141,3,8,119,185,13,153,34,125,206,76,17,49,38,93,206,52,151,154,119,56,28, |
| 10975 | 76,130,112,200,141,206,21,209,96,23,35,238,114,160,139,0,243,238,114,78, |
| 10976 | 164,68,68,110,113,226,210,90,26,66,110,113,128,121,247,57,80,68,141,170, |
| 10977 | 183,56,84,52,11,70,73,19,110,114,160,93,8,113,57,143,66,200,84,53,244,154, |
| 10978 | 73,24,240,81,32,38,68,18,49,228,207,23,88,100,109,70,114,92,193,4,137,173, |
| 10979 | 168,36,220,73,19,247,247,182,168,209,144,187,223,58,156,104,79,190,183,127, |
| 10980 | 123,105,160,110,247,206,167,26,19,239,173,223,222,218,67,75,189,243,169, |
| 10981 | 198,132,251,235,183,247,182,154,134,151,123,231,83,141,9,247,215,111,239, |
| 10982 | 109,22,141,22,247,206,167,26,19,239,172,223,218,45,26,47,157,78,52,39,223, |
| 10983 | 74,24,144,10,32,129,34,20,64,152,142,129,57,179,67,104,68,12,129,161,140, |
| 10984 | 72,156,100,40,40,185,152,100,89,38,65,13,196,34,228,67,149,13,2,215,129, |
| 10985 | 149,209,65,104,209,77,14,104,144,81,33,170,67,101,48,52,68,113,70,210,88, |
| 10986 | 209,36,233,22,154,86,68,196,114,76,232,145,102,120,186,195,156,112,105,225, |
| 10987 | 228,113,71,80,68,162,115,101,50,85,200,25,108,116,44,132,178,38,114,137,96, |
| 10988 | 148,136,70,209,134,37,222,232,204,228,188,200,209,200,200,99,221,25,150,84, |
| 10989 | 121,34,70,209,107,36,227,66,20,160,92,136,164,49,235,35,8,217,201,40,108, |
| 10990 | 201,18,128,68,26,201,51,188,2,80,12,67,190,40,168,38,68,190,46,153,5,50,12, |
| 10991 | 207,160,86,129,26,83,4,208,34,225,4,88,192, |
| 10992 | }; |
| 10993 | #endif /* DUK_USE_ROM_STRINGS */ |
| 10994 | |
| 10995 | #if defined(DUK_USE_ROM_OBJECTS) |
| 10996 | #error ROM support not enabled, rerun configure.py with --rom-support |
| 10997 | #else /* DUK_USE_ROM_OBJECTS */ |
| 10998 | /* native functions: 185 */ |
| 10999 | DUK_INTERNAL const duk_c_function duk_bi_native_functions[185] = { |
| 11000 | NULL, |
| 11001 | duk_bi_array_constructor, |
| 11002 | duk_bi_array_constructor_is_array, |
| 11003 | duk_bi_array_prototype_concat, |
| 11004 | duk_bi_array_prototype_indexof_shared, |
| 11005 | duk_bi_array_prototype_iter_shared, |
| 11006 | duk_bi_array_prototype_join_shared, |
| 11007 | duk_bi_array_prototype_pop, |
| 11008 | duk_bi_array_prototype_push, |
| 11009 | duk_bi_array_prototype_reduce_shared, |
| 11010 | duk_bi_array_prototype_reverse, |
| 11011 | duk_bi_array_prototype_shift, |
| 11012 | duk_bi_array_prototype_slice, |
| 11013 | duk_bi_array_prototype_sort, |
| 11014 | duk_bi_array_prototype_splice, |
| 11015 | duk_bi_array_prototype_to_string, |
| 11016 | duk_bi_array_prototype_unshift, |
| 11017 | duk_bi_arraybuffer_constructor, |
| 11018 | duk_bi_arraybuffer_isview, |
| 11019 | duk_bi_boolean_constructor, |
| 11020 | duk_bi_boolean_prototype_tostring_shared, |
| 11021 | duk_bi_buffer_compare_shared, |
| 11022 | duk_bi_buffer_readfield, |
| 11023 | duk_bi_buffer_slice_shared, |
| 11024 | duk_bi_buffer_writefield, |
| 11025 | duk_bi_cbor_decode, |
| 11026 | duk_bi_cbor_encode, |
| 11027 | duk_bi_dataview_constructor, |
| 11028 | duk_bi_date_constructor, |
| 11029 | duk_bi_date_constructor_now, |
| 11030 | duk_bi_date_constructor_parse, |
| 11031 | duk_bi_date_constructor_utc, |
| 11032 | duk_bi_date_prototype_get_shared, |
| 11033 | duk_bi_date_prototype_get_timezone_offset, |
| 11034 | duk_bi_date_prototype_set_shared, |
| 11035 | duk_bi_date_prototype_set_time, |
| 11036 | duk_bi_date_prototype_to_json, |
| 11037 | duk_bi_date_prototype_toprimitive, |
| 11038 | duk_bi_date_prototype_tostring_shared, |
| 11039 | duk_bi_date_prototype_value_of, |
| 11040 | duk_bi_duktape_object_act, |
| 11041 | duk_bi_duktape_object_compact, |
| 11042 | duk_bi_duktape_object_dec, |
| 11043 | duk_bi_duktape_object_enc, |
| 11044 | duk_bi_duktape_object_fin, |
| 11045 | duk_bi_duktape_object_gc, |
| 11046 | duk_bi_duktape_object_info, |
| 11047 | duk_bi_error_constructor_shared, |
| 11048 | duk_bi_error_prototype_filename_getter, |
| 11049 | duk_bi_error_prototype_filename_setter, |
| 11050 | duk_bi_error_prototype_linenumber_getter, |
| 11051 | duk_bi_error_prototype_linenumber_setter, |
| 11052 | duk_bi_error_prototype_stack_getter, |
| 11053 | duk_bi_error_prototype_stack_setter, |
| 11054 | duk_bi_error_prototype_to_string, |
| 11055 | duk_bi_function_constructor, |
| 11056 | duk_bi_function_prototype, |
| 11057 | duk_bi_function_prototype_apply, |
| 11058 | duk_bi_function_prototype_bind, |
| 11059 | duk_bi_function_prototype_call, |
| 11060 | duk_bi_function_prototype_hasinstance, |
| 11061 | duk_bi_function_prototype_to_string, |
| 11062 | duk_bi_global_object_decode_uri, |
| 11063 | duk_bi_global_object_decode_uri_component, |
| 11064 | duk_bi_global_object_encode_uri, |
| 11065 | duk_bi_global_object_encode_uri_component, |
| 11066 | duk_bi_global_object_escape, |
| 11067 | duk_bi_global_object_eval, |
| 11068 | duk_bi_global_object_is_finite, |
| 11069 | duk_bi_global_object_is_nan, |
| 11070 | duk_bi_global_object_parse_float, |
| 11071 | duk_bi_global_object_parse_int, |
| 11072 | duk_bi_global_object_unescape, |
| 11073 | duk_bi_json_object_parse, |
| 11074 | duk_bi_json_object_stringify, |
| 11075 | duk_bi_math_object_clz32, |
| 11076 | duk_bi_math_object_hypot, |
| 11077 | duk_bi_math_object_imul, |
| 11078 | duk_bi_math_object_max, |
| 11079 | duk_bi_math_object_min, |
| 11080 | duk_bi_math_object_onearg_shared, |
| 11081 | duk_bi_math_object_random, |
| 11082 | duk_bi_math_object_sign, |
| 11083 | duk_bi_math_object_twoarg_shared, |
| 11084 | duk_bi_native_function_length, |
| 11085 | duk_bi_native_function_name, |
| 11086 | duk_bi_nodejs_buffer_byte_length, |
| 11087 | duk_bi_nodejs_buffer_concat, |
| 11088 | duk_bi_nodejs_buffer_constructor, |
| 11089 | duk_bi_nodejs_buffer_copy, |
| 11090 | duk_bi_nodejs_buffer_fill, |
| 11091 | duk_bi_nodejs_buffer_is_buffer, |
| 11092 | duk_bi_nodejs_buffer_is_encoding, |
| 11093 | duk_bi_nodejs_buffer_tojson, |
| 11094 | duk_bi_nodejs_buffer_tostring, |
| 11095 | duk_bi_nodejs_buffer_write, |
| 11096 | duk_bi_number_check_shared, |
| 11097 | duk_bi_number_constructor, |
| 11098 | duk_bi_number_prototype_to_exponential, |
| 11099 | duk_bi_number_prototype_to_fixed, |
| 11100 | duk_bi_number_prototype_to_locale_string, |
| 11101 | duk_bi_number_prototype_to_precision, |
| 11102 | duk_bi_number_prototype_to_string, |
| 11103 | duk_bi_number_prototype_value_of, |
| 11104 | duk_bi_object_constructor, |
| 11105 | duk_bi_object_constructor_assign, |
| 11106 | duk_bi_object_constructor_create, |
| 11107 | duk_bi_object_constructor_define_properties, |
| 11108 | duk_bi_object_constructor_define_property, |
| 11109 | duk_bi_object_constructor_get_own_property_descriptor, |
| 11110 | duk_bi_object_constructor_is, |
| 11111 | duk_bi_object_constructor_is_extensible, |
| 11112 | duk_bi_object_constructor_is_sealed_frozen_shared, |
| 11113 | duk_bi_object_constructor_keys_shared, |
| 11114 | duk_bi_object_constructor_prevent_extensions, |
| 11115 | duk_bi_object_constructor_seal_freeze_shared, |
| 11116 | duk_bi_object_getprototype_shared, |
| 11117 | duk_bi_object_prototype_defineaccessor, |
| 11118 | duk_bi_object_prototype_has_own_property, |
| 11119 | duk_bi_object_prototype_is_prototype_of, |
| 11120 | duk_bi_object_prototype_lookupaccessor, |
| 11121 | duk_bi_object_prototype_property_is_enumerable, |
| 11122 | duk_bi_object_prototype_to_locale_string, |
| 11123 | duk_bi_object_prototype_to_string, |
| 11124 | duk_bi_object_prototype_value_of, |
| 11125 | duk_bi_object_setprototype_shared, |
| 11126 | duk_bi_performance_now, |
| 11127 | duk_bi_pointer_constructor, |
| 11128 | duk_bi_pointer_prototype_tostring_shared, |
| 11129 | duk_bi_proxy_constructor, |
| 11130 | duk_bi_reflect_apply, |
| 11131 | duk_bi_reflect_construct, |
| 11132 | duk_bi_reflect_object_delete_property, |
| 11133 | duk_bi_reflect_object_get, |
| 11134 | duk_bi_reflect_object_has, |
| 11135 | duk_bi_reflect_object_set, |
| 11136 | duk_bi_regexp_constructor, |
| 11137 | duk_bi_regexp_prototype_exec, |
| 11138 | duk_bi_regexp_prototype_flags, |
| 11139 | duk_bi_regexp_prototype_shared_getter, |
| 11140 | duk_bi_regexp_prototype_test, |
| 11141 | duk_bi_regexp_prototype_tostring, |
| 11142 | duk_bi_string_constructor, |
| 11143 | duk_bi_string_constructor_from_char_code, |
| 11144 | duk_bi_string_constructor_from_code_point, |
| 11145 | duk_bi_string_prototype_caseconv_shared, |
| 11146 | duk_bi_string_prototype_char_at, |
| 11147 | duk_bi_string_prototype_char_code_at, |
| 11148 | duk_bi_string_prototype_concat, |
| 11149 | duk_bi_string_prototype_includes, |
| 11150 | duk_bi_string_prototype_indexof_shared, |
| 11151 | duk_bi_string_prototype_locale_compare, |
| 11152 | duk_bi_string_prototype_match, |
| 11153 | duk_bi_string_prototype_repeat, |
| 11154 | duk_bi_string_prototype_replace, |
| 11155 | duk_bi_string_prototype_search, |
| 11156 | duk_bi_string_prototype_slice, |
| 11157 | duk_bi_string_prototype_split, |
| 11158 | duk_bi_string_prototype_startswith_endswith, |
| 11159 | duk_bi_string_prototype_substr, |
| 11160 | duk_bi_string_prototype_substring, |
| 11161 | duk_bi_string_prototype_to_string, |
| 11162 | duk_bi_string_prototype_trim, |
| 11163 | duk_bi_symbol_constructor_shared, |
| 11164 | duk_bi_symbol_key_for, |
| 11165 | duk_bi_symbol_toprimitive, |
| 11166 | duk_bi_symbol_tostring_shared, |
| 11167 | duk_bi_textdecoder_constructor, |
| 11168 | duk_bi_textdecoder_prototype_decode, |
| 11169 | duk_bi_textdecoder_prototype_shared_getter, |
| 11170 | duk_bi_textencoder_constructor, |
| 11171 | duk_bi_textencoder_prototype_encode, |
| 11172 | duk_bi_textencoder_prototype_encoding_getter, |
| 11173 | duk_bi_thread_constructor, |
| 11174 | duk_bi_thread_current, |
| 11175 | duk_bi_thread_resume, |
| 11176 | duk_bi_thread_yield, |
| 11177 | duk_bi_type_error_thrower, |
| 11178 | duk_bi_typedarray_buffer_getter, |
| 11179 | duk_bi_typedarray_bytelength_getter, |
| 11180 | duk_bi_typedarray_byteoffset_getter, |
| 11181 | duk_bi_typedarray_constructor, |
| 11182 | duk_bi_typedarray_set, |
| 11183 | duk_bi_uint8array_allocplain, |
| 11184 | duk_bi_uint8array_plainof, |
| 11185 | }; |
| 11186 | #if defined(DUK_USE_DOUBLE_LE) |
| 11187 | DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = { |
| 11188 | 144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245, |
| 11189 | 124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33, |
| 11190 | 167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228, |
| 11191 | 64,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46, |
| 11192 | 142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240, |
| 11193 | 242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0, |
| 11194 | 1,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, |
| 11195 | 33,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237, |
| 11196 | 198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181, |
| 11197 | 10,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62, |
| 11198 | 53,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45, |
| 11199 | 84,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53, |
| 11200 | 109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61, |
| 11201 | 11,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232, |
| 11202 | 145,153,136,0,0,0,0,0,0,31,15,249,152,0,0,0,0,0,0,30,15,249,120,144,13,96, |
| 11203 | 155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,23, |
| 11204 | 194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104, |
| 11205 | 137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156, |
| 11206 | 36,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5, |
| 11207 | 209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85, |
| 11208 | 144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30, |
| 11209 | 122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19, |
| 11210 | 136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137, |
| 11211 | 195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13, |
| 11212 | 17,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154, |
| 11213 | 2,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205, |
| 11214 | 35,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11, |
| 11215 | 174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32, |
| 11216 | 0,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12, |
| 11217 | 73,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199, |
| 11218 | 89,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40, |
| 11219 | 144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26, |
| 11220 | 78,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23, |
| 11221 | 196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249, |
| 11222 | 132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8, |
| 11223 | 162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164, |
| 11224 | 160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224, |
| 11225 | 151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242, |
| 11226 | 113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84, |
| 11227 | 129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144, |
| 11228 | 168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147, |
| 11229 | 153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212, |
| 11230 | 36,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163, |
| 11231 | 203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17, |
| 11232 | 136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189, |
| 11233 | 207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11, |
| 11234 | 37,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103, |
| 11235 | 44,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138, |
| 11236 | 231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1, |
| 11237 | 30,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5, |
| 11238 | 196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56, |
| 11239 | 35,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135, |
| 11240 | 34,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4, |
| 11241 | 120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115, |
| 11242 | 68,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23, |
| 11243 | 228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15, |
| 11244 | 18,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39, |
| 11245 | 249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4, |
| 11246 | 102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4, |
| 11247 | 9,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12, |
| 11248 | 255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26, |
| 11249 | 57,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246, |
| 11250 | 130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84, |
| 11251 | 11,161,32,127,255,255,255,255,255,247,191,137,235,16,221,170,129,116,36,0, |
| 11252 | 16,0,0,0,0,0,0,12,196,0,0,0,0,0,0,15,135,242,61,123,164,137,162,164,218,67, |
| 11253 | 74,134,162,120,128,0,0,0,0,0,1,224,254,71,173,33,129,52,84,155,72,105,80, |
| 11254 | 212,79,16,0,0,0,0,0,0,60,63,195,244,143,146,22,230,192,0,0,0,0,0,0,176,60, |
| 11255 | 33,214,2,251,82,1,73,180,134,204,134,36,96,127,255,255,255,255,255,159,161, |
| 11256 | 144,235,16,221,169,0,164,218,67,102,67,18,48,63,255,255,255,255,255,207, |
| 11257 | 240,196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34, |
| 11258 | 92,42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187, |
| 11259 | 194,80,212,75,146,1,73,196,54,100,49,35,188,38,57,37,56,240,0,0,0,0,0,0,0, |
| 11260 | 0,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238, |
| 11261 | 18,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3, |
| 11262 | 5,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,0,0,0, |
| 11263 | 0,0,0,248,127,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155, |
| 11264 | 185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193, |
| 11265 | 130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41, |
| 11266 | 197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77, |
| 11267 | 12,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139, |
| 11268 | 218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210, |
| 11269 | 98,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16, |
| 11270 | 250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97, |
| 11271 | 40,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10, |
| 11272 | 49,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97, |
| 11273 | 56,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28, |
| 11274 | 173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51, |
| 11275 | 168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89, |
| 11276 | 18,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149, |
| 11277 | 210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62, |
| 11278 | 72,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5, |
| 11279 | 72,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146, |
| 11280 | 186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82, |
| 11281 | 50,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151, |
| 11282 | 74,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103, |
| 11283 | 186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189, |
| 11284 | 162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2, |
| 11285 | 55,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127, |
| 11286 | 48,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94, |
| 11287 | 82,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207, |
| 11288 | 144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21, |
| 11289 | 221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32, |
| 11290 | 105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104, |
| 11291 | 137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35, |
| 11292 | 23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165, |
| 11293 | 19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70, |
| 11294 | 72,115,96,0,0,0,0,0,15,106,32,91,60,165,195,201,194,8,134,149,216,162,0, |
| 11295 | 192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176, |
| 11296 | 195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20, |
| 11297 | 1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219, |
| 11298 | 36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0, |
| 11299 | 0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1, |
| 11300 | 102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48, |
| 11301 | 20,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179, |
| 11302 | 216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235, |
| 11303 | 81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168, |
| 11304 | 166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149, |
| 11305 | 20,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96, |
| 11306 | 68,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68, |
| 11307 | 159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148, |
| 11308 | 67,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194, |
| 11309 | 173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44, |
| 11310 | 140,35,103,0,0,0,0,0,0,3,192,252,206,25,228,35,208,226,100,150,211,201,29, |
| 11311 | 162,44,140,35,103,0,0,0,0,0,0,3,192,252,206,25,244,35,208,226,100,150,211, |
| 11312 | 201,29,162,44,140,35,103,0,0,0,0,0,0,3,192,252,206,26,4,35,208,226,100,150, |
| 11313 | 211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,1,0,206,26,20,35,208,226,100, |
| 11314 | 150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,1,0,206,26,36,35,208,226, |
| 11315 | 100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,52,35,208, |
| 11316 | 226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,68,35, |
| 11317 | 208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,84, |
| 11318 | 35,208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,129,0,195, |
| 11319 | 154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150, |
| 11320 | 25,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232, |
| 11321 | 235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7, |
| 11322 | 196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80, |
| 11323 | 200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165, |
| 11324 | 213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10, |
| 11325 | 183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224, |
| 11326 | 221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128, |
| 11327 | 31,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19, |
| 11328 | 18,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153, |
| 11329 | 59,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19, |
| 11330 | 39,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232, |
| 11331 | 73,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27, |
| 11332 | 61,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217, |
| 11333 | 67,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103, |
| 11334 | 167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209, |
| 11335 | 68,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104, |
| 11336 | 193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2, |
| 11337 | 178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76, |
| 11338 | 157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180, |
| 11339 | 81,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196, |
| 11340 | 133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0, |
| 11341 | 22,209,68,201,187,129,4,2,8,3,132,64,60,36,6,149,113,72,176,171,240,84,0, |
| 11342 | 157,91,116,116,32,11,42,218,221,216,181,129,32,3,234,219,165,3,188,231,235, |
| 11343 | 249,8,187,152,252,47,86,227,105,18,7,244,17,91,42,56,175,185,248,110,173, |
| 11344 | 198,209,208,36,0,238,82,97,87,188,189,179,240,93,122,32,12,22,162,42,125, |
| 11345 | 144,132,160,7,236,161,25,232,237,105,64,205,59,127,102,158,160,230,63,11, |
| 11346 | 217,66,51,210,129,154,118,254,205,61,65,236,127,171,197,34,168,48,6,90,194, |
| 11347 | 1,0,39,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0, |
| 11348 | 65,6,51,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88, |
| 11349 | 80,0,201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25, |
| 11350 | 69,234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176, |
| 11351 | 165,1,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230, |
| 11352 | 107,64,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146, |
| 11353 | 132,103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17, |
| 11354 | 145,52,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0, |
| 11355 | 104,146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128, |
| 11356 | 56,18,52,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141, |
| 11357 | 47,129,6,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69, |
| 11358 | 15,155,163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254, |
| 11359 | 36,3,17,46,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108, |
| 11360 | 248,75,204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2, |
| 11361 | 206,9,113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2, |
| 11362 | 178,66,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136, |
| 11363 | 38,232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55, |
| 11364 | 38,3,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37, |
| 11365 | 202,160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248, |
| 11366 | 0,0,179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11, |
| 11367 | 181,192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218, |
| 11368 | 121,35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,153,188,56,132,122,28,76, |
| 11369 | 146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,168,160,45,110,23, |
| 11370 | 30,176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56, |
| 11371 | 153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63,51,120,145,8,244, |
| 11372 | 56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,120,161,8, |
| 11373 | 244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,120,177, |
| 11374 | 8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,120, |
| 11375 | 193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51, |
| 11376 | 120,209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64, |
| 11377 | 51,120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,32, |
| 11378 | 64,32,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16, |
| 11379 | 137,112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120, |
| 11380 | 34,74,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66, |
| 11381 | 8,35,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240, |
| 11382 | 117,96,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82, |
| 11383 | 32,148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81, |
| 11384 | 238,2,3,107,173,218,3,192, |
| 11385 | }; |
| 11386 | #elif defined(DUK_USE_DOUBLE_BE) |
| 11387 | DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = { |
| 11388 | 144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245, |
| 11389 | 124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33, |
| 11390 | 167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228, |
| 11391 | 64,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46, |
| 11392 | 142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240, |
| 11393 | 242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0, |
| 11394 | 1,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, |
| 11395 | 33,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237, |
| 11396 | 198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181, |
| 11397 | 10,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62, |
| 11398 | 53,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45, |
| 11399 | 84,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53, |
| 11400 | 109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61, |
| 11401 | 11,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232, |
| 11402 | 145,153,136,15,255,0,0,0,0,0,0,25,152,15,254,0,0,0,0,0,0,25,120,144,13,96, |
| 11403 | 155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,23, |
| 11404 | 194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104, |
| 11405 | 137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156, |
| 11406 | 36,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5, |
| 11407 | 209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85, |
| 11408 | 144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30, |
| 11409 | 122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19, |
| 11410 | 136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137, |
| 11411 | 195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13, |
| 11412 | 17,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154, |
| 11413 | 2,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205, |
| 11414 | 35,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11, |
| 11415 | 174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32, |
| 11416 | 0,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12, |
| 11417 | 73,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199, |
| 11418 | 89,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40, |
| 11419 | 144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26, |
| 11420 | 78,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23, |
| 11421 | 196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249, |
| 11422 | 132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8, |
| 11423 | 162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164, |
| 11424 | 160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224, |
| 11425 | 151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242, |
| 11426 | 113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84, |
| 11427 | 129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144, |
| 11428 | 168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147, |
| 11429 | 153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212, |
| 11430 | 36,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163, |
| 11431 | 203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17, |
| 11432 | 136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189, |
| 11433 | 207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11, |
| 11434 | 37,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103, |
| 11435 | 44,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138, |
| 11436 | 231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1, |
| 11437 | 30,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5, |
| 11438 | 196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56, |
| 11439 | 35,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135, |
| 11440 | 34,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4, |
| 11441 | 120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115, |
| 11442 | 68,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23, |
| 11443 | 228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15, |
| 11444 | 18,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39, |
| 11445 | 249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4, |
| 11446 | 102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4, |
| 11447 | 9,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12, |
| 11448 | 255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26, |
| 11449 | 57,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246, |
| 11450 | 130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84, |
| 11451 | 11,161,32,63,247,255,255,255,255,255,255,137,235,16,221,170,129,116,36,0,0, |
| 11452 | 0,0,0,0,0,0,28,196,7,255,128,0,0,0,0,0,2,61,123,164,137,162,164,218,67,74, |
| 11453 | 134,162,120,128,255,224,0,0,0,0,0,0,71,173,33,129,52,84,155,72,105,80,212, |
| 11454 | 79,16,63,252,0,0,0,0,0,0,3,244,143,146,22,230,192,60,176,0,0,0,0,0,0,33, |
| 11455 | 214,2,251,82,1,73,180,134,204,134,36,96,33,159,255,255,255,255,255,255,144, |
| 11456 | 235,16,221,169,0,164,218,67,102,67,18,48,48,207,255,255,255,255,255,255, |
| 11457 | 196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34,92, |
| 11458 | 42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187, |
| 11459 | 194,80,212,75,146,1,73,196,54,100,49,35,188,38,57,37,56,240,0,0,0,0,0,0,0, |
| 11460 | 0,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238, |
| 11461 | 18,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3, |
| 11462 | 5,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,127, |
| 11463 | 248,0,0,0,0,0,0,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155, |
| 11464 | 185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193, |
| 11465 | 130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41, |
| 11466 | 197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77, |
| 11467 | 12,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139, |
| 11468 | 218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210, |
| 11469 | 98,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16, |
| 11470 | 250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97, |
| 11471 | 40,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10, |
| 11472 | 49,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97, |
| 11473 | 56,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28, |
| 11474 | 173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51, |
| 11475 | 168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89, |
| 11476 | 18,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149, |
| 11477 | 210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62, |
| 11478 | 72,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5, |
| 11479 | 72,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146, |
| 11480 | 186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82, |
| 11481 | 50,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151, |
| 11482 | 74,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103, |
| 11483 | 186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189, |
| 11484 | 162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2, |
| 11485 | 55,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127, |
| 11486 | 48,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94, |
| 11487 | 82,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207, |
| 11488 | 144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21, |
| 11489 | 221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32, |
| 11490 | 105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104, |
| 11491 | 137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35, |
| 11492 | 23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165, |
| 11493 | 19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70, |
| 11494 | 72,115,96,32,106,15,0,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0, |
| 11495 | 192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176, |
| 11496 | 195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20, |
| 11497 | 1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219, |
| 11498 | 36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0, |
| 11499 | 0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1, |
| 11500 | 102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48, |
| 11501 | 20,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179, |
| 11502 | 216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235, |
| 11503 | 81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168, |
| 11504 | 166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149, |
| 11505 | 20,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96, |
| 11506 | 68,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68, |
| 11507 | 159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148, |
| 11508 | 67,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194, |
| 11509 | 173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44, |
| 11510 | 140,35,103,0,255,192,0,0,0,0,0,0,206,25,228,35,208,226,100,150,211,201,29, |
| 11511 | 162,44,140,35,103,0,255,192,0,0,0,0,0,0,206,25,244,35,208,226,100,150,211, |
| 11512 | 201,29,162,44,140,35,103,0,255,192,0,0,0,0,0,0,206,26,4,35,208,226,100,150, |
| 11513 | 211,201,29,162,44,140,35,103,1,0,0,0,0,0,0,0,0,206,26,20,35,208,226,100, |
| 11514 | 150,211,201,29,162,44,140,35,103,1,0,0,0,0,0,0,0,0,206,26,36,35,208,226, |
| 11515 | 100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,52,35,208, |
| 11516 | 226,100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,68,35, |
| 11517 | 208,226,100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,84, |
| 11518 | 35,208,226,100,150,211,201,29,162,44,140,35,103,1,0,128,0,0,0,0,0,0,195, |
| 11519 | 154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150, |
| 11520 | 25,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232, |
| 11521 | 235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7, |
| 11522 | 196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80, |
| 11523 | 200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165, |
| 11524 | 213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10, |
| 11525 | 183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224, |
| 11526 | 221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128, |
| 11527 | 31,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19, |
| 11528 | 18,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153, |
| 11529 | 59,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19, |
| 11530 | 39,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232, |
| 11531 | 73,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27, |
| 11532 | 61,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217, |
| 11533 | 67,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103, |
| 11534 | 167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209, |
| 11535 | 68,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104, |
| 11536 | 193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2, |
| 11537 | 178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76, |
| 11538 | 157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180, |
| 11539 | 81,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196, |
| 11540 | 133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0, |
| 11541 | 22,209,68,201,187,129,4,2,8,3,132,64,60,36,4,0,91,240,168,177,69,118,144, |
| 11542 | 157,91,116,116,32,32,1,53,216,221,218,170,139,3,234,219,165,0,255,152,185, |
| 11543 | 11,251,232,231,188,47,86,227,105,18,1,255,184,170,59,41,92,23,240,110,173, |
| 11544 | 198,209,208,36,3,253,188,183,177,82,110,80,224,93,122,32,32,4,144,253,170, |
| 11545 | 34,22,140,7,236,161,25,232,237,105,64,63,230,160,158,102,127,59,205,11,217, |
| 11546 | 66,51,210,128,127,237,65,60,204,254,119,155,171,197,34,168,48,6,90,194,1,0, |
| 11547 | 39,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,65,6, |
| 11548 | 51,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,80,0, |
| 11549 | 201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,69, |
| 11550 | 234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,165, |
| 11551 | 1,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,107, |
| 11552 | 64,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,132, |
| 11553 | 103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,145, |
| 11554 | 52,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,104, |
| 11555 | 146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,56,18, |
| 11556 | 52,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,47,129, |
| 11557 | 6,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155, |
| 11558 | 163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,36,3,17, |
| 11559 | 46,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,248,75, |
| 11560 | 204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,206,9, |
| 11561 | 113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,178, |
| 11562 | 66,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,38, |
| 11563 | 232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,38, |
| 11564 | 3,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,202, |
| 11565 | 160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,0,0, |
| 11566 | 179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,181, |
| 11567 | 192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,121, |
| 11568 | 35,180,69,145,132,108,224,31,248,0,0,0,0,0,0,25,188,56,132,122,28,76,146, |
| 11569 | 218,121,35,180,69,145,132,108,224,31,248,0,0,0,0,0,0,40,160,45,110,23,30, |
| 11570 | 176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,153, |
| 11571 | 37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,51,120,145,8,244,56, |
| 11572 | 153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,120,161,8,244, |
| 11573 | 56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,120,177,8, |
| 11574 | 244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,120,193, |
| 11575 | 8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,120, |
| 11576 | 209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51, |
| 11577 | 120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,32,0,0,0,0,0,0, |
| 11578 | 32,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,137, |
| 11579 | 112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,34, |
| 11580 | 74,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,8, |
| 11581 | 35,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,117, |
| 11582 | 96,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,32, |
| 11583 | 148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,238,2, |
| 11584 | 3,107,173,218,3,192, |
| 11585 | }; |
| 11586 | #elif defined(DUK_USE_DOUBLE_ME) |
| 11587 | DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = { |
| 11588 | 144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245, |
| 11589 | 124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33, |
| 11590 | 167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228, |
| 11591 | 64,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46, |
| 11592 | 142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240, |
| 11593 | 242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0, |
| 11594 | 1,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132, |
| 11595 | 33,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237, |
| 11596 | 198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181, |
| 11597 | 10,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62, |
| 11598 | 53,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45, |
| 11599 | 84,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53, |
| 11600 | 109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61, |
| 11601 | 11,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232, |
| 11602 | 145,153,136,0,0,31,15,224,0,0,0,25,152,0,0,30,15,224,0,0,0,25,120,144,13, |
| 11603 | 96,155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168, |
| 11604 | 23,194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104, |
| 11605 | 137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156, |
| 11606 | 36,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5, |
| 11607 | 209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85, |
| 11608 | 144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30, |
| 11609 | 122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19, |
| 11610 | 136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137, |
| 11611 | 195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13, |
| 11612 | 17,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154, |
| 11613 | 2,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205, |
| 11614 | 35,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11, |
| 11615 | 174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32, |
| 11616 | 0,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12, |
| 11617 | 73,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199, |
| 11618 | 89,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40, |
| 11619 | 144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26, |
| 11620 | 78,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23, |
| 11621 | 196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249, |
| 11622 | 132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8, |
| 11623 | 162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164, |
| 11624 | 160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224, |
| 11625 | 151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242, |
| 11626 | 113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84, |
| 11627 | 129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144, |
| 11628 | 168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147, |
| 11629 | 153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212, |
| 11630 | 36,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163, |
| 11631 | 203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17, |
| 11632 | 136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189, |
| 11633 | 207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11, |
| 11634 | 37,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103, |
| 11635 | 44,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138, |
| 11636 | 231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1, |
| 11637 | 30,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5, |
| 11638 | 196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56, |
| 11639 | 35,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135, |
| 11640 | 34,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4, |
| 11641 | 120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115, |
| 11642 | 68,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23, |
| 11643 | 228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15, |
| 11644 | 18,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39, |
| 11645 | 249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4, |
| 11646 | 102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4, |
| 11647 | 9,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12, |
| 11648 | 255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26, |
| 11649 | 57,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246, |
| 11650 | 130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84, |
| 11651 | 11,161,32,127,255,247,191,255,255,255,255,137,235,16,221,170,129,116,36,0, |
| 11652 | 0,0,0,0,16,0,0,12,196,0,0,15,135,240,0,0,0,2,61,123,164,137,162,164,218,67, |
| 11653 | 74,134,162,120,128,0,1,224,254,0,0,0,0,71,173,33,129,52,84,155,72,105,80, |
| 11654 | 212,79,16,0,0,60,63,192,0,0,0,3,244,143,146,22,230,192,0,0,176,60,0,0,0,0, |
| 11655 | 33,214,2,251,82,1,73,180,134,204,134,36,96,127,255,159,161,255,255,255,255, |
| 11656 | 144,235,16,221,169,0,164,218,67,102,67,18,48,63,255,207,240,255,255,255, |
| 11657 | 255,196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34, |
| 11658 | 92,42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187, |
| 11659 | 194,80,212,75,146,1,73,196,54,100,49,35,188,38,57,37,56,240,0,0,0,0,0,0,0, |
| 11660 | 0,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238, |
| 11661 | 18,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3, |
| 11662 | 5,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,0,0, |
| 11663 | 248,127,0,0,0,0,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155, |
| 11664 | 185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193, |
| 11665 | 130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41, |
| 11666 | 197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77, |
| 11667 | 12,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139, |
| 11668 | 218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210, |
| 11669 | 98,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16, |
| 11670 | 250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97, |
| 11671 | 40,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10, |
| 11672 | 49,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97, |
| 11673 | 56,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28, |
| 11674 | 173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51, |
| 11675 | 168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89, |
| 11676 | 18,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149, |
| 11677 | 210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62, |
| 11678 | 72,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5, |
| 11679 | 72,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146, |
| 11680 | 186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82, |
| 11681 | 50,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151, |
| 11682 | 74,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103, |
| 11683 | 186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189, |
| 11684 | 162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2, |
| 11685 | 55,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127, |
| 11686 | 48,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94, |
| 11687 | 82,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207, |
| 11688 | 144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21, |
| 11689 | 221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32, |
| 11690 | 105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104, |
| 11691 | 137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35, |
| 11692 | 23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165, |
| 11693 | 19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70, |
| 11694 | 72,115,96,0,15,106,32,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0, |
| 11695 | 192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176, |
| 11696 | 195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20, |
| 11697 | 1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219, |
| 11698 | 36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0, |
| 11699 | 0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1, |
| 11700 | 102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48, |
| 11701 | 20,28,76,156,113,75,34,78,62,0,0,45,3,103,31,0,0,22,65,44,57,137,62,33,179, |
| 11702 | 216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235, |
| 11703 | 81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168, |
| 11704 | 166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149, |
| 11705 | 20,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96, |
| 11706 | 68,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68, |
| 11707 | 159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148, |
| 11708 | 67,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194, |
| 11709 | 173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44, |
| 11710 | 140,35,103,0,0,3,192,252,0,0,0,0,206,25,228,35,208,226,100,150,211,201,29, |
| 11711 | 162,44,140,35,103,0,0,3,192,252,0,0,0,0,206,25,244,35,208,226,100,150,211, |
| 11712 | 201,29,162,44,140,35,103,0,0,3,192,252,0,0,0,0,206,26,4,35,208,226,100,150, |
| 11713 | 211,201,29,162,44,140,35,103,0,0,0,1,0,0,0,0,0,206,26,20,35,208,226,100, |
| 11714 | 150,211,201,29,162,44,140,35,103,0,0,0,1,0,0,0,0,0,206,26,36,35,208,226, |
| 11715 | 100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,52,35,208, |
| 11716 | 226,100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,68,35, |
| 11717 | 208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,84, |
| 11718 | 35,208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,129,0,0,0,0,0,195, |
| 11719 | 154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150, |
| 11720 | 25,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232, |
| 11721 | 235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7, |
| 11722 | 196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80, |
| 11723 | 200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165, |
| 11724 | 213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10, |
| 11725 | 183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224, |
| 11726 | 221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128, |
| 11727 | 31,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19, |
| 11728 | 18,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153, |
| 11729 | 59,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19, |
| 11730 | 39,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232, |
| 11731 | 73,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27, |
| 11732 | 61,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217, |
| 11733 | 67,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103, |
| 11734 | 167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209, |
| 11735 | 68,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104, |
| 11736 | 193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2, |
| 11737 | 178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76, |
| 11738 | 157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180, |
| 11739 | 81,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196, |
| 11740 | 133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0, |
| 11741 | 22,209,68,201,187,129,4,2,8,3,132,64,60,36,0,171,240,84,6,149,113,72,176, |
| 11742 | 157,91,116,116,32,88,181,129,32,11,42,218,221,131,234,219,165,1,8,187,152, |
| 11743 | 255,188,231,235,248,47,86,227,105,18,2,56,175,185,255,244,17,91,40,110,173, |
| 11744 | 198,209,208,36,7,188,189,179,240,238,82,97,80,93,122,32,125,144,132,160,12, |
| 11745 | 22,162,42,7,236,161,25,232,237,105,64,158,160,230,63,205,59,127,102,11,217, |
| 11746 | 66,51,210,129,61,65,236,127,154,118,254,205,171,197,34,168,48,6,90,194,1,0, |
| 11747 | 39,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,65,6, |
| 11748 | 51,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,80,0, |
| 11749 | 201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,69, |
| 11750 | 234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,165, |
| 11751 | 1,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,107, |
| 11752 | 64,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,132, |
| 11753 | 103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,145, |
| 11754 | 52,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,104, |
| 11755 | 146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,56,18, |
| 11756 | 52,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,47,129, |
| 11757 | 6,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155, |
| 11758 | 163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,36,3,17, |
| 11759 | 46,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,248,75, |
| 11760 | 204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,206,9, |
| 11761 | 113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,178, |
| 11762 | 66,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,38, |
| 11763 | 232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,38, |
| 11764 | 3,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,202, |
| 11765 | 160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,0,0, |
| 11766 | 179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,181, |
| 11767 | 192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,121, |
| 11768 | 35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,25,188,56,132,122,28,76,146, |
| 11769 | 218,121,35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,40,160,45,110,23,30, |
| 11770 | 176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,153, |
| 11771 | 37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0,51,120,145,8,244,56, |
| 11772 | 153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,120,161,8,244, |
| 11773 | 56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,120,177,8, |
| 11774 | 244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,120,193, |
| 11775 | 8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,120, |
| 11776 | 209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51, |
| 11777 | 120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,32,64,0,0,0,0, |
| 11778 | 32,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,137, |
| 11779 | 112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,34, |
| 11780 | 74,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,8, |
| 11781 | 35,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,117, |
| 11782 | 96,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,32, |
| 11783 | 148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,238,2, |
| 11784 | 3,107,173,218,3,192, |
| 11785 | }; |
| 11786 | #else |
| 11787 | #error invalid endianness defines |
| 11788 | #endif |
| 11789 | #endif /* DUK_USE_ROM_OBJECTS */ |
| 11790 | |
| 11791 | /* automatic undefs */ |
| 11792 | #undef DUK__REFCINIT |
| 11793 | #line 1 "duk_error_macros.c" |
| 11794 | /* |
| 11795 | * Error and fatal handling. |
| 11796 | */ |
| 11797 | |
| 11798 | /* #include duk_internal.h -> already included */ |
| 11799 | |
| 11800 | #define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */ |
| 11801 | |
| 11802 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 11803 | |
| 11804 | DUK_INTERNAL DUK_COLD void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) { |
| 11805 | va_list ap; |
| 11806 | char msg[DUK__ERRFMT_BUFSIZE]; |
| 11807 | va_start(ap, fmt); |
| 11808 | (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap); |
| 11809 | msg[sizeof(msg) - 1] = (char) 0; |
| 11810 | duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL)); |
| 11811 | va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */ |
| 11812 | } |
| 11813 | |
| 11814 | DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) { |
| 11815 | duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL)); |
| 11816 | } |
| 11817 | |
| 11818 | #else /* DUK_USE_VERBOSE_ERRORS */ |
| 11819 | |
| 11820 | DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) { |
| 11821 | duk_err_create_and_throw(thr, code); |
| 11822 | } |
| 11823 | |
| 11824 | #endif /* DUK_USE_VERBOSE_ERRORS */ |
| 11825 | |
| 11826 | /* |
| 11827 | * Error throwing helpers |
| 11828 | */ |
| 11829 | |
| 11830 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 11831 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 11832 | DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) { |
| 11833 | DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)" , |
| 11834 | expect_name, duk_get_type_name(thr, idx), (long) idx); |
| 11835 | } |
| 11836 | #else |
| 11837 | DUK_INTERNAL DUK_COLD void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) { |
| 11838 | DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)" , |
| 11839 | expect_name, duk_push_string_readable(thr, idx), (long) idx); |
| 11840 | } |
| 11841 | #endif |
| 11842 | DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) { |
| 11843 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR); |
| 11844 | } |
| 11845 | DUK_INTERNAL DUK_COLD void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) { |
| 11846 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED); |
| 11847 | } |
| 11848 | DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { |
| 11849 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message); |
| 11850 | } |
| 11851 | DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) { |
| 11852 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message); |
| 11853 | } |
| 11854 | DUK_INTERNAL DUK_COLD void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) { |
| 11855 | DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld" , (long) (idx)); |
| 11856 | } |
| 11857 | DUK_INTERNAL DUK_COLD void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) { |
| 11858 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK); |
| 11859 | } |
| 11860 | DUK_INTERNAL DUK_COLD void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) { |
| 11861 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS); |
| 11862 | } |
| 11863 | DUK_INTERNAL DUK_COLD void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) { |
| 11864 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE); |
| 11865 | } |
| 11866 | DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) { |
| 11867 | DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT); |
| 11868 | } |
| 11869 | #else |
| 11870 | /* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW() |
| 11871 | * when non-verbose errors are used. |
| 11872 | */ |
| 11873 | |
| 11874 | DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code)); |
| 11875 | DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) { |
| 11876 | DUK_ERROR_RAW(thr, NULL, 0, code, NULL); |
| 11877 | } |
| 11878 | DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) { |
| 11879 | duk__err_shared(thr, DUK_ERR_ERROR); |
| 11880 | } |
| 11881 | DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) { |
| 11882 | duk__err_shared(thr, DUK_ERR_RANGE_ERROR); |
| 11883 | } |
| 11884 | DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) { |
| 11885 | duk__err_shared(thr, DUK_ERR_EVAL_ERROR); |
| 11886 | } |
| 11887 | DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) { |
| 11888 | duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR); |
| 11889 | } |
| 11890 | DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) { |
| 11891 | duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR); |
| 11892 | } |
| 11893 | DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) { |
| 11894 | duk__err_shared(thr, DUK_ERR_TYPE_ERROR); |
| 11895 | } |
| 11896 | DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) { |
| 11897 | duk__err_shared(thr, DUK_ERR_URI_ERROR); |
| 11898 | } |
| 11899 | #endif |
| 11900 | |
| 11901 | /* |
| 11902 | * Default fatal error handler |
| 11903 | */ |
| 11904 | |
| 11905 | DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) { |
| 11906 | DUK_UNREF(udata); |
| 11907 | DUK_UNREF(msg); |
| 11908 | |
| 11909 | msg = msg ? msg : "NULL" ; |
| 11910 | |
| 11911 | #if defined(DUK_USE_FATAL_HANDLER) |
| 11912 | /* duk_config.h provided a custom default fatal handler. */ |
| 11913 | DUK_D(DUK_DPRINT("custom default fatal error handler called: %s" , msg)); |
| 11914 | DUK_USE_FATAL_HANDLER(udata, msg); |
| 11915 | #elif defined(DUK_USE_CPP_EXCEPTIONS) |
| 11916 | /* With C++ use a duk_fatal_exception which user code can catch in |
| 11917 | * a natural way. |
| 11918 | */ |
| 11919 | DUK_D(DUK_DPRINT("built-in default C++ fatal error handler called: %s" , msg)); |
| 11920 | throw duk_fatal_exception(msg); |
| 11921 | #else |
| 11922 | /* Default behavior is to abort() on error. There's no printout |
| 11923 | * which makes this awkward, so it's always recommended to use an |
| 11924 | * explicit fatal error handler. |
| 11925 | * |
| 11926 | * ==================================================================== |
| 11927 | * NOTE: If you are seeing this, you are most likely dealing with an |
| 11928 | * uncaught error. You should provide a fatal error handler in Duktape |
| 11929 | * heap creation, and should consider using a protected call as your |
| 11930 | * first call into an empty Duktape context to properly handle errors. |
| 11931 | * See: |
| 11932 | * - http://duktape.org/guide.html#error-handling |
| 11933 | * - http://wiki.duktape.org/HowtoFatalErrors.html |
| 11934 | * - http://duktape.org/api.html#taglist-protected |
| 11935 | * ==================================================================== |
| 11936 | */ |
| 11937 | DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s" , msg)); |
| 11938 | DUK_ABORT(); |
| 11939 | #endif |
| 11940 | |
| 11941 | DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop" )); |
| 11942 | for (;;) { |
| 11943 | /* Loop forever to ensure we don't return. */ |
| 11944 | } |
| 11945 | } |
| 11946 | |
| 11947 | /* automatic undefs */ |
| 11948 | #undef DUK__ERRFMT_BUFSIZE |
| 11949 | #line 1 "duk_unicode_support.c" |
| 11950 | /* |
| 11951 | * Various Unicode help functions for character classification predicates, |
| 11952 | * case conversion, decoding, etc. |
| 11953 | */ |
| 11954 | |
| 11955 | /* #include duk_internal.h -> already included */ |
| 11956 | |
| 11957 | /* |
| 11958 | * Fast path tables |
| 11959 | */ |
| 11960 | |
| 11961 | #if defined(DUK_USE_IDCHAR_FASTPATH) |
| 11962 | DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = { |
| 11963 | /* 0: not IdentifierStart or IdentifierPart |
| 11964 | * 1: IdentifierStart and IdentifierPart |
| 11965 | * -1: IdentifierPart only |
| 11966 | */ |
| 11967 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */ |
| 11968 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */ |
| 11969 | 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */ |
| 11970 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */ |
| 11971 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */ |
| 11972 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */ |
| 11973 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */ |
| 11974 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */ |
| 11975 | }; |
| 11976 | #endif |
| 11977 | |
| 11978 | /* |
| 11979 | * XUTF-8 and CESU-8 encoding/decoding |
| 11980 | */ |
| 11981 | |
| 11982 | DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) { |
| 11983 | duk_uint_fast32_t x = (duk_uint_fast32_t) cp; |
| 11984 | if (x < 0x80UL) { |
| 11985 | /* 7 bits */ |
| 11986 | return 1; |
| 11987 | } else if (x < 0x800UL) { |
| 11988 | /* 11 bits */ |
| 11989 | return 2; |
| 11990 | } else if (x < 0x10000UL) { |
| 11991 | /* 16 bits */ |
| 11992 | return 3; |
| 11993 | } else if (x < 0x200000UL) { |
| 11994 | /* 21 bits */ |
| 11995 | return 4; |
| 11996 | } else if (x < 0x4000000UL) { |
| 11997 | /* 26 bits */ |
| 11998 | return 5; |
| 11999 | } else if (x < (duk_ucodepoint_t) 0x80000000UL) { |
| 12000 | /* 31 bits */ |
| 12001 | return 6; |
| 12002 | } else { |
| 12003 | /* 36 bits */ |
| 12004 | return 7; |
| 12005 | } |
| 12006 | } |
| 12007 | |
| 12008 | #if defined(DUK_USE_ASSERTIONS) |
| 12009 | DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) { |
| 12010 | duk_uint_fast32_t x = (duk_uint_fast32_t) cp; |
| 12011 | if (x < 0x80UL) { |
| 12012 | /* 7 bits */ |
| 12013 | return 1; |
| 12014 | } else if (x < 0x800UL) { |
| 12015 | /* 11 bits */ |
| 12016 | return 2; |
| 12017 | } else if (x < 0x10000UL) { |
| 12018 | /* 16 bits */ |
| 12019 | return 3; |
| 12020 | } else { |
| 12021 | /* Encoded as surrogate pair, each encoding to 3 bytes for |
| 12022 | * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes |
| 12023 | * too, see duk_unicode_encode_cesu8(). |
| 12024 | */ |
| 12025 | return 3 + 3; |
| 12026 | } |
| 12027 | } |
| 12028 | #endif /* DUK_USE_ASSERTIONS */ |
| 12029 | |
| 12030 | DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = { |
| 12031 | 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe |
| 12032 | }; |
| 12033 | |
| 12034 | /* Encode to extended UTF-8; 'out' must have space for at least |
| 12035 | * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any |
| 12036 | * 32-bit (unsigned) codepoint. |
| 12037 | */ |
| 12038 | DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) { |
| 12039 | duk_uint_fast32_t x = (duk_uint_fast32_t) cp; |
| 12040 | duk_small_int_t len; |
| 12041 | duk_uint8_t marker; |
| 12042 | duk_small_int_t i; |
| 12043 | |
| 12044 | len = duk_unicode_get_xutf8_length(cp); |
| 12045 | DUK_ASSERT(len > 0); |
| 12046 | |
| 12047 | marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */ |
| 12048 | |
| 12049 | i = len; |
| 12050 | DUK_ASSERT(i > 0); |
| 12051 | do { |
| 12052 | i--; |
| 12053 | if (i > 0) { |
| 12054 | out[i] = (duk_uint8_t) (0x80 + (x & 0x3f)); |
| 12055 | x >>= 6; |
| 12056 | } else { |
| 12057 | /* Note: masking of 'x' is not necessary because of |
| 12058 | * range check and shifting -> no bits overlapping |
| 12059 | * the marker should be set. |
| 12060 | */ |
| 12061 | out[0] = (duk_uint8_t) (marker + x); |
| 12062 | } |
| 12063 | } while (i > 0); |
| 12064 | |
| 12065 | return len; |
| 12066 | } |
| 12067 | |
| 12068 | /* Encode to CESU-8; 'out' must have space for at least |
| 12069 | * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF |
| 12070 | * will encode to garbage but won't overwrite the output buffer. |
| 12071 | */ |
| 12072 | DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) { |
| 12073 | duk_uint_fast32_t x = (duk_uint_fast32_t) cp; |
| 12074 | duk_small_int_t len; |
| 12075 | |
| 12076 | if (x < 0x80UL) { |
| 12077 | out[0] = (duk_uint8_t) x; |
| 12078 | len = 1; |
| 12079 | } else if (x < 0x800UL) { |
| 12080 | out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f)); |
| 12081 | out[1] = (duk_uint8_t) (0x80 + (x & 0x3f)); |
| 12082 | len = 2; |
| 12083 | } else if (x < 0x10000UL) { |
| 12084 | /* surrogate pairs get encoded here */ |
| 12085 | out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f)); |
| 12086 | out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f)); |
| 12087 | out[2] = (duk_uint8_t) (0x80 + (x & 0x3f)); |
| 12088 | len = 3; |
| 12089 | } else { |
| 12090 | /* |
| 12091 | * Unicode codepoints above U+FFFF are encoded as surrogate |
| 12092 | * pairs here. This ensures that all CESU-8 codepoints are |
| 12093 | * 16-bit values as expected in ECMAScript. The surrogate |
| 12094 | * pairs always get a 3-byte encoding (each) in CESU-8. |
| 12095 | * See: http://en.wikipedia.org/wiki/Surrogate_pair |
| 12096 | * |
| 12097 | * 20-bit codepoint, 10 bits (A and B) per surrogate pair: |
| 12098 | * |
| 12099 | * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB |
| 12100 | * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff)) |
| 12101 | * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff)) |
| 12102 | * |
| 12103 | * Encoded into CESU-8: |
| 12104 | * |
| 12105 | * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f)) |
| 12106 | * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f)) |
| 12107 | * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f)) |
| 12108 | * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f)) |
| 12109 | * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f)) |
| 12110 | * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f)) |
| 12111 | * |
| 12112 | * Note that 0x10000 must be subtracted first. The code below |
| 12113 | * avoids the sp1, sp2 temporaries which saves around 20 bytes |
| 12114 | * of code. |
| 12115 | */ |
| 12116 | |
| 12117 | x -= 0x10000UL; |
| 12118 | |
| 12119 | out[0] = (duk_uint8_t) (0xed); |
| 12120 | out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f)); |
| 12121 | out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f)); |
| 12122 | out[3] = (duk_uint8_t) (0xed); |
| 12123 | out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f)); |
| 12124 | out[5] = (duk_uint8_t) (0x80 + (x & 0x3f)); |
| 12125 | len = 6; |
| 12126 | } |
| 12127 | |
| 12128 | return len; |
| 12129 | } |
| 12130 | |
| 12131 | /* Decode helper. Return zero on error. */ |
| 12132 | DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp) { |
| 12133 | const duk_uint8_t *p; |
| 12134 | duk_uint32_t res; |
| 12135 | duk_uint_fast8_t ch; |
| 12136 | duk_small_int_t n; |
| 12137 | |
| 12138 | DUK_UNREF(thr); |
| 12139 | |
| 12140 | p = *ptr; |
| 12141 | if (p < ptr_start || p >= ptr_end) { |
| 12142 | goto fail; |
| 12143 | } |
| 12144 | |
| 12145 | /* |
| 12146 | * UTF-8 decoder which accepts longer than standard byte sequences. |
| 12147 | * This allows full 32-bit code points to be used. |
| 12148 | */ |
| 12149 | |
| 12150 | ch = (duk_uint_fast8_t) (*p++); |
| 12151 | if (ch < 0x80) { |
| 12152 | /* 0xxx xxxx [7 bits] */ |
| 12153 | res = (duk_uint32_t) (ch & 0x7f); |
| 12154 | n = 0; |
| 12155 | } else if (ch < 0xc0) { |
| 12156 | /* 10xx xxxx -> invalid */ |
| 12157 | goto fail; |
| 12158 | } else if (ch < 0xe0) { |
| 12159 | /* 110x xxxx 10xx xxxx [11 bits] */ |
| 12160 | res = (duk_uint32_t) (ch & 0x1f); |
| 12161 | n = 1; |
| 12162 | } else if (ch < 0xf0) { |
| 12163 | /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */ |
| 12164 | res = (duk_uint32_t) (ch & 0x0f); |
| 12165 | n = 2; |
| 12166 | } else if (ch < 0xf8) { |
| 12167 | /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */ |
| 12168 | res = (duk_uint32_t) (ch & 0x07); |
| 12169 | n = 3; |
| 12170 | } else if (ch < 0xfc) { |
| 12171 | /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */ |
| 12172 | res = (duk_uint32_t) (ch & 0x03); |
| 12173 | n = 4; |
| 12174 | } else if (ch < 0xfe) { |
| 12175 | /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */ |
| 12176 | res = (duk_uint32_t) (ch & 0x01); |
| 12177 | n = 5; |
| 12178 | } else if (ch < 0xff) { |
| 12179 | /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */ |
| 12180 | res = (duk_uint32_t) (0); |
| 12181 | n = 6; |
| 12182 | } else { |
| 12183 | /* 8-byte format could be: |
| 12184 | * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits] |
| 12185 | * |
| 12186 | * However, this format would not have a zero bit following the |
| 12187 | * leading one bits and would not allow 0xFF to be used as an |
| 12188 | * "invalid xutf-8" marker for internal keys. Further, 8-byte |
| 12189 | * encodings (up to 41 bit code points) are not currently needed. |
| 12190 | */ |
| 12191 | goto fail; |
| 12192 | } |
| 12193 | |
| 12194 | DUK_ASSERT(p >= ptr_start); /* verified at beginning */ |
| 12195 | if (p + n > ptr_end) { |
| 12196 | /* check pointer at end */ |
| 12197 | goto fail; |
| 12198 | } |
| 12199 | |
| 12200 | while (n > 0) { |
| 12201 | DUK_ASSERT(p >= ptr_start && p < ptr_end); |
| 12202 | ch = (duk_uint_fast8_t) (*p++); |
| 12203 | #if 0 |
| 12204 | if (ch & 0xc0 != 0x80) { |
| 12205 | /* not a continuation byte */ |
| 12206 | p--; |
| 12207 | *ptr = p; |
| 12208 | *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; |
| 12209 | return 1; |
| 12210 | } |
| 12211 | #endif |
| 12212 | res = (res << 6) + (duk_uint32_t) (ch & 0x3f); |
| 12213 | n--; |
| 12214 | } |
| 12215 | |
| 12216 | *ptr = p; |
| 12217 | *out_cp = res; |
| 12218 | return 1; |
| 12219 | |
| 12220 | fail: |
| 12221 | return 0; |
| 12222 | } |
| 12223 | |
| 12224 | /* used by e.g. duk_regexp_executor.c, string built-ins */ |
| 12225 | DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end) { |
| 12226 | duk_ucodepoint_t cp; |
| 12227 | |
| 12228 | if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) { |
| 12229 | return cp; |
| 12230 | } |
| 12231 | DUK_ERROR_INTERNAL(thr); |
| 12232 | DUK_WO_NORETURN(return 0;); |
| 12233 | } |
| 12234 | |
| 12235 | /* Compute (extended) utf-8 length without codepoint encoding validation, |
| 12236 | * used for string interning. |
| 12237 | * |
| 12238 | * NOTE: This algorithm is performance critical, more so than string hashing |
| 12239 | * in some cases. It is needed when interning a string and needs to scan |
| 12240 | * every byte of the string with no skipping. Having an ASCII fast path |
| 12241 | * is useful if possible in the algorithm. The current algorithms were |
| 12242 | * chosen from several variants, based on x64 gcc -O2 testing. See: |
| 12243 | * https://github.com/svaarala/duktape/pull/422 |
| 12244 | * |
| 12245 | * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length(). |
| 12246 | */ |
| 12247 | |
| 12248 | #if defined(DUK_USE_PREFER_SIZE) |
| 12249 | /* Small variant; roughly 150 bytes smaller than the fast variant. */ |
| 12250 | DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { |
| 12251 | const duk_uint8_t *p; |
| 12252 | const duk_uint8_t *p_end; |
| 12253 | duk_size_t ncont; |
| 12254 | duk_size_t clen; |
| 12255 | |
| 12256 | p = data; |
| 12257 | p_end = data + blen; |
| 12258 | ncont = 0; |
| 12259 | while (p != p_end) { |
| 12260 | duk_uint8_t x; |
| 12261 | x = *p++; |
| 12262 | if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { |
| 12263 | ncont++; |
| 12264 | } |
| 12265 | } |
| 12266 | |
| 12267 | DUK_ASSERT(ncont <= blen); |
| 12268 | clen = blen - ncont; |
| 12269 | DUK_ASSERT(clen <= blen); |
| 12270 | return clen; |
| 12271 | } |
| 12272 | #else /* DUK_USE_PREFER_SIZE */ |
| 12273 | /* This seems like a good overall approach. Fast path for ASCII in 4 byte |
| 12274 | * blocks. |
| 12275 | */ |
| 12276 | DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) { |
| 12277 | const duk_uint8_t *p; |
| 12278 | const duk_uint8_t *p_end; |
| 12279 | const duk_uint32_t *p32_end; |
| 12280 | const duk_uint32_t *p32; |
| 12281 | duk_size_t ncont; |
| 12282 | duk_size_t clen; |
| 12283 | |
| 12284 | ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */ |
| 12285 | p = data; |
| 12286 | p_end = data + blen; |
| 12287 | if (blen < 16) { |
| 12288 | goto skip_fastpath; |
| 12289 | } |
| 12290 | |
| 12291 | /* Align 'p' to 4; the input data may have arbitrary alignment. |
| 12292 | * End of string check not needed because blen >= 16. |
| 12293 | */ |
| 12294 | while (((duk_size_t) (const void *) p) & 0x03U) { |
| 12295 | duk_uint8_t x; |
| 12296 | x = *p++; |
| 12297 | if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { |
| 12298 | ncont++; |
| 12299 | } |
| 12300 | } |
| 12301 | |
| 12302 | /* Full, aligned 4-byte reads. */ |
| 12303 | p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03))); |
| 12304 | p32 = (const duk_uint32_t *) (const void *) p; |
| 12305 | while (p32 != (const duk_uint32_t *) p32_end) { |
| 12306 | duk_uint32_t x; |
| 12307 | x = *p32++; |
| 12308 | if (DUK_LIKELY((x & 0x80808080UL) == 0)) { |
| 12309 | ; /* ASCII fast path */ |
| 12310 | } else { |
| 12311 | /* Flip highest bit of each byte which changes |
| 12312 | * the bit pattern 10xxxxxx into 00xxxxxx which |
| 12313 | * allows an easy bit mask test. |
| 12314 | */ |
| 12315 | x ^= 0x80808080UL; |
| 12316 | if (DUK_UNLIKELY(!(x & 0xc0000000UL))) { |
| 12317 | ncont++; |
| 12318 | } |
| 12319 | if (DUK_UNLIKELY(!(x & 0x00c00000UL))) { |
| 12320 | ncont++; |
| 12321 | } |
| 12322 | if (DUK_UNLIKELY(!(x & 0x0000c000UL))) { |
| 12323 | ncont++; |
| 12324 | } |
| 12325 | if (DUK_UNLIKELY(!(x & 0x000000c0UL))) { |
| 12326 | ncont++; |
| 12327 | } |
| 12328 | } |
| 12329 | } |
| 12330 | p = (const duk_uint8_t *) p32; |
| 12331 | /* Fall through to handle the rest. */ |
| 12332 | |
| 12333 | skip_fastpath: |
| 12334 | while (p != p_end) { |
| 12335 | duk_uint8_t x; |
| 12336 | x = *p++; |
| 12337 | if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) { |
| 12338 | ncont++; |
| 12339 | } |
| 12340 | } |
| 12341 | |
| 12342 | DUK_ASSERT(ncont <= blen); |
| 12343 | clen = blen - ncont; |
| 12344 | DUK_ASSERT(clen <= blen); |
| 12345 | return clen; |
| 12346 | } |
| 12347 | #endif /* DUK_USE_PREFER_SIZE */ |
| 12348 | |
| 12349 | /* Check whether a string is UTF-8 compatible or not. */ |
| 12350 | DUK_INTERNAL duk_bool_t duk_unicode_is_utf8_compatible(const duk_uint8_t *buf, duk_size_t len) { |
| 12351 | duk_size_t i = 0; |
| 12352 | #if !defined(DUK_USE_PREFER_SIZE) |
| 12353 | duk_size_t len_safe; |
| 12354 | #endif |
| 12355 | |
| 12356 | /* Many practical strings are ASCII only, so use a fast path check |
| 12357 | * to check chunks of bytes at once with minimal branch cost. |
| 12358 | */ |
| 12359 | #if !defined(DUK_USE_PREFER_SIZE) |
| 12360 | len_safe = len & ~0x03UL; |
| 12361 | for (; i < len_safe; i += 4) { |
| 12362 | duk_uint8_t t = buf[i] | buf[i + 1] | buf[i + 2] | buf[i + 3]; |
| 12363 | if (DUK_UNLIKELY((t & 0x80U) != 0U)) { |
| 12364 | /* At least one byte was outside 0x00-0x7f, break |
| 12365 | * out to slow path (and remain there). |
| 12366 | * |
| 12367 | * XXX: We could also deal with the problem character |
| 12368 | * and resume fast path later. |
| 12369 | */ |
| 12370 | break; |
| 12371 | } |
| 12372 | } |
| 12373 | #endif |
| 12374 | |
| 12375 | for (; i < len;) { |
| 12376 | duk_uint8_t t; |
| 12377 | duk_size_t left; |
| 12378 | duk_size_t ncont; |
| 12379 | duk_uint32_t cp; |
| 12380 | duk_uint32_t mincp; |
| 12381 | |
| 12382 | t = buf[i++]; |
| 12383 | if (DUK_LIKELY((t & 0x80U) == 0U)) { |
| 12384 | /* Fast path, ASCII. */ |
| 12385 | continue; |
| 12386 | } |
| 12387 | |
| 12388 | /* Non-ASCII start byte, slow path. |
| 12389 | * |
| 12390 | * 10xx xxxx -> continuation byte |
| 12391 | * 110x xxxx + 1*CONT -> [0x80, 0x7ff] |
| 12392 | * 1110 xxxx + 2*CONT -> [0x800, 0xffff], must reject [0xd800,0xdfff] |
| 12393 | * 1111 0xxx + 3*CONT -> [0x10000, 0x10ffff] |
| 12394 | */ |
| 12395 | left = len - i; |
| 12396 | if (t <= 0xdfU) { /* 1101 1111 = 0xdf */ |
| 12397 | if (t <= 0xbfU) { /* 1011 1111 = 0xbf */ |
| 12398 | return 0; |
| 12399 | } |
| 12400 | ncont = 1; |
| 12401 | mincp = 0x80UL; |
| 12402 | cp = t & 0x1fU; |
| 12403 | } else if (t <= 0xefU) { /* 1110 1111 = 0xef */ |
| 12404 | ncont = 2; |
| 12405 | mincp = 0x800UL; |
| 12406 | cp = t & 0x0fU; |
| 12407 | } else if (t <= 0xf7U) { /* 1111 0111 = 0xf7 */ |
| 12408 | ncont = 3; |
| 12409 | mincp = 0x10000UL; |
| 12410 | cp = t & 0x07U; |
| 12411 | } else { |
| 12412 | return 0; |
| 12413 | } |
| 12414 | if (left < ncont) { |
| 12415 | return 0; |
| 12416 | } |
| 12417 | while (ncont > 0U) { |
| 12418 | t = buf[i++]; |
| 12419 | if ((t & 0xc0U) != 0x80U) { /* 10xx xxxx */ |
| 12420 | return 0; |
| 12421 | } |
| 12422 | cp = (cp << 6) + (t & 0x3fU); |
| 12423 | ncont--; |
| 12424 | } |
| 12425 | if (cp < mincp || cp > 0x10ffffUL || (cp >= 0xd800UL && cp <= 0xdfffUL)) { |
| 12426 | return 0; |
| 12427 | } |
| 12428 | } |
| 12429 | |
| 12430 | return 1; |
| 12431 | } |
| 12432 | |
| 12433 | /* |
| 12434 | * Unicode range matcher |
| 12435 | * |
| 12436 | * Matches a codepoint against a packed bitstream of character ranges. |
| 12437 | * Used for slow path Unicode matching. |
| 12438 | */ |
| 12439 | |
| 12440 | /* Must match tools/extract_chars.py, generate_match_table3(). */ |
| 12441 | DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) { |
| 12442 | duk_uint32_t t; |
| 12443 | |
| 12444 | t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4); |
| 12445 | if (t <= 0x0eU) { |
| 12446 | return t; |
| 12447 | } |
| 12448 | t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8); |
| 12449 | if (t <= 0xfdU) { |
| 12450 | return t + 0x0f; |
| 12451 | } |
| 12452 | if (t == 0xfeU) { |
| 12453 | t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12); |
| 12454 | return t + 0x0fU + 0xfeU; |
| 12455 | } else { |
| 12456 | t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24); |
| 12457 | return t + 0x0fU + 0xfeU + 0x1000UL; |
| 12458 | } |
| 12459 | } |
| 12460 | |
| 12461 | DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) { |
| 12462 | duk_bitdecoder_ctx bd_ctx; |
| 12463 | duk_codepoint_t prev_re; |
| 12464 | |
| 12465 | duk_memzero(&bd_ctx, sizeof(bd_ctx)); |
| 12466 | bd_ctx.data = (const duk_uint8_t *) unitab; |
| 12467 | bd_ctx.length = (duk_size_t) unilen; |
| 12468 | |
| 12469 | prev_re = 0; |
| 12470 | for (;;) { |
| 12471 | duk_codepoint_t r1, r2; |
| 12472 | r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx); |
| 12473 | if (r1 == 0) { |
| 12474 | break; |
| 12475 | } |
| 12476 | r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx); |
| 12477 | |
| 12478 | r1 = prev_re + r1; |
| 12479 | r2 = r1 + r2; |
| 12480 | prev_re = r2; |
| 12481 | |
| 12482 | /* [r1,r2] is the range */ |
| 12483 | |
| 12484 | DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]" , |
| 12485 | (unsigned long) cp, (unsigned long) r1, (unsigned long) r2)); |
| 12486 | if (cp >= r1 && cp <= r2) { |
| 12487 | return 1; |
| 12488 | } |
| 12489 | } |
| 12490 | |
| 12491 | return 0; |
| 12492 | } |
| 12493 | |
| 12494 | /* |
| 12495 | * "WhiteSpace" production check. |
| 12496 | */ |
| 12497 | |
| 12498 | DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) { |
| 12499 | /* |
| 12500 | * E5 Section 7.2 specifies six characters specifically as |
| 12501 | * white space: |
| 12502 | * |
| 12503 | * 0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;; |
| 12504 | * 000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;; |
| 12505 | * 000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;; |
| 12506 | * 0020;SPACE;Zs;0;WS;;;;;N;;;;; |
| 12507 | * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;; |
| 12508 | * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; |
| 12509 | * |
| 12510 | * It also specifies any Unicode category 'Zs' characters as white |
| 12511 | * space. These can be extracted with the "tools/extract_chars.py" script. |
| 12512 | * Current result: |
| 12513 | * |
| 12514 | * RAW OUTPUT: |
| 12515 | * =========== |
| 12516 | * 0020;SPACE;Zs;0;WS;;;;;N;;;;; |
| 12517 | * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;; |
| 12518 | * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; |
| 12519 | * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;; |
| 12520 | * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; |
| 12521 | * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; |
| 12522 | * 2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12523 | * 2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12524 | * 2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12525 | * 2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12526 | * 2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12527 | * 2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;; |
| 12528 | * 2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12529 | * 2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12530 | * 200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12531 | * 202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;; |
| 12532 | * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;; |
| 12533 | * 3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;; |
| 12534 | * |
| 12535 | * RANGES: |
| 12536 | * ======= |
| 12537 | * 0x0020 |
| 12538 | * 0x00a0 |
| 12539 | * 0x1680 |
| 12540 | * 0x180e |
| 12541 | * 0x2000 ... 0x200a |
| 12542 | * 0x202f |
| 12543 | * 0x205f |
| 12544 | * 0x3000 |
| 12545 | * |
| 12546 | * A manual decoder (below) is probably most compact for this. |
| 12547 | */ |
| 12548 | |
| 12549 | duk_uint_fast8_t lo; |
| 12550 | duk_uint_fast32_t hi; |
| 12551 | |
| 12552 | /* cp == -1 (EOF) never matches and causes return value 0 */ |
| 12553 | |
| 12554 | lo = (duk_uint_fast8_t) (cp & 0xff); |
| 12555 | hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */ |
| 12556 | |
| 12557 | if (hi == 0x0000UL) { |
| 12558 | if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU || |
| 12559 | lo == 0x20U || lo == 0xa0U) { |
| 12560 | return 1; |
| 12561 | } |
| 12562 | } else if (hi == 0x0020UL) { |
| 12563 | if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) { |
| 12564 | return 1; |
| 12565 | } |
| 12566 | } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L || |
| 12567 | cp == 0xfeffL) { |
| 12568 | return 1; |
| 12569 | } |
| 12570 | |
| 12571 | return 0; |
| 12572 | } |
| 12573 | |
| 12574 | /* |
| 12575 | * "LineTerminator" production check. |
| 12576 | */ |
| 12577 | |
| 12578 | DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) { |
| 12579 | /* |
| 12580 | * E5 Section 7.3 |
| 12581 | * |
| 12582 | * A LineTerminatorSequence essentially merges <CR> <LF> sequences |
| 12583 | * into a single line terminator. This must be handled by the caller. |
| 12584 | */ |
| 12585 | |
| 12586 | if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L || |
| 12587 | cp == 0x2029L) { |
| 12588 | return 1; |
| 12589 | } |
| 12590 | |
| 12591 | return 0; |
| 12592 | } |
| 12593 | |
| 12594 | /* |
| 12595 | * "IdentifierStart" production check. |
| 12596 | */ |
| 12597 | |
| 12598 | DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) { |
| 12599 | /* |
| 12600 | * E5 Section 7.6: |
| 12601 | * |
| 12602 | * IdentifierStart: |
| 12603 | * UnicodeLetter |
| 12604 | * $ |
| 12605 | * _ |
| 12606 | * \ UnicodeEscapeSequence |
| 12607 | * |
| 12608 | * IdentifierStart production has one multi-character production: |
| 12609 | * |
| 12610 | * \ UnicodeEscapeSequence |
| 12611 | * |
| 12612 | * The '\' character is -not- matched by this function. Rather, the caller |
| 12613 | * should decode the escape and then call this function to check whether the |
| 12614 | * decoded character is acceptable (see discussion in E5 Section 7.6). |
| 12615 | * |
| 12616 | * The "UnicodeLetter" alternative of the production allows letters |
| 12617 | * from various Unicode categories. These can be extracted with the |
| 12618 | * "tools/extract_chars.py" script. |
| 12619 | * |
| 12620 | * Because the result has hundreds of Unicode codepoint ranges, matching |
| 12621 | * for any values >= 0x80 are done using a very slow range-by-range scan |
| 12622 | * and a packed range format. |
| 12623 | * |
| 12624 | * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because |
| 12625 | * it matters the most. The ASCII related ranges of IdentifierStart are: |
| 12626 | * |
| 12627 | * 0x0041 ... 0x005a ['A' ... 'Z'] |
| 12628 | * 0x0061 ... 0x007a ['a' ... 'z'] |
| 12629 | * 0x0024 ['$'] |
| 12630 | * 0x005f ['_'] |
| 12631 | */ |
| 12632 | |
| 12633 | /* ASCII (and EOF) fast path -- quick accept and reject */ |
| 12634 | if (cp <= 0x7fL) { |
| 12635 | #if defined(DUK_USE_IDCHAR_FASTPATH) |
| 12636 | return (cp >= 0) && (duk_is_idchar_tab[cp] > 0); |
| 12637 | #else |
| 12638 | if ((cp >= 'a' && cp <= 'z') || |
| 12639 | (cp >= 'A' && cp <= 'Z') || |
| 12640 | cp == '_' || cp == '$') { |
| 12641 | return 1; |
| 12642 | } |
| 12643 | return 0; |
| 12644 | #endif |
| 12645 | } |
| 12646 | |
| 12647 | /* Non-ASCII slow path (range-by-range linear comparison), very slow */ |
| 12648 | |
| 12649 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 12650 | if (duk__uni_range_match(duk_unicode_ids_noa, |
| 12651 | (duk_size_t) sizeof(duk_unicode_ids_noa), |
| 12652 | (duk_codepoint_t) cp)) { |
| 12653 | return 1; |
| 12654 | } |
| 12655 | return 0; |
| 12656 | #else |
| 12657 | if (cp < 0x10000L) { |
| 12658 | if (duk__uni_range_match(duk_unicode_ids_noabmp, |
| 12659 | sizeof(duk_unicode_ids_noabmp), |
| 12660 | (duk_codepoint_t) cp)) { |
| 12661 | return 1; |
| 12662 | } |
| 12663 | return 0; |
| 12664 | } else { |
| 12665 | /* without explicit non-BMP support, assume non-BMP characters |
| 12666 | * are always accepted as identifier characters. |
| 12667 | */ |
| 12668 | return 1; |
| 12669 | } |
| 12670 | #endif |
| 12671 | } |
| 12672 | |
| 12673 | /* |
| 12674 | * "IdentifierPart" production check. |
| 12675 | */ |
| 12676 | |
| 12677 | DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) { |
| 12678 | /* |
| 12679 | * E5 Section 7.6: |
| 12680 | * |
| 12681 | * IdentifierPart: |
| 12682 | * IdentifierStart |
| 12683 | * UnicodeCombiningMark |
| 12684 | * UnicodeDigit |
| 12685 | * UnicodeConnectorPunctuation |
| 12686 | * <ZWNJ> [U+200C] |
| 12687 | * <ZWJ> [U+200D] |
| 12688 | * |
| 12689 | * IdentifierPart production has one multi-character production |
| 12690 | * as part of its IdentifierStart alternative. The '\' character |
| 12691 | * of an escape sequence is not matched here, see discussion in |
| 12692 | * duk_unicode_is_identifier_start(). |
| 12693 | * |
| 12694 | * To match non-ASCII characters (codepoints >= 0x80), a very slow |
| 12695 | * linear range-by-range scan is used. The codepoint is first compared |
| 12696 | * to the IdentifierStart ranges, and if it doesn't match, then to a |
| 12697 | * set consisting of code points in IdentifierPart but not in |
| 12698 | * IdentifierStart. This is done to keep the unicode range data small, |
| 12699 | * at the expense of speed. |
| 12700 | * |
| 12701 | * The ASCII fast path consists of: |
| 12702 | * |
| 12703 | * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit] |
| 12704 | * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart] |
| 12705 | * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart] |
| 12706 | * 0x0024 ['$', IdentifierStart] |
| 12707 | * 0x005f ['_', IdentifierStart and |
| 12708 | * UnicodeConnectorPunctuation] |
| 12709 | * |
| 12710 | * UnicodeCombiningMark has no code points <= 0x7f. |
| 12711 | * |
| 12712 | * The matching code reuses the "identifier start" tables, and then |
| 12713 | * consults a separate range set for characters in "identifier part" |
| 12714 | * but not in "identifier start". These can be extracted with the |
| 12715 | * "tools/extract_chars.py" script. |
| 12716 | * |
| 12717 | * UnicodeCombiningMark -> categories Mn, Mc |
| 12718 | * UnicodeDigit -> categories Nd |
| 12719 | * UnicodeConnectorPunctuation -> categories Pc |
| 12720 | */ |
| 12721 | |
| 12722 | /* ASCII (and EOF) fast path -- quick accept and reject */ |
| 12723 | if (cp <= 0x7fL) { |
| 12724 | #if defined(DUK_USE_IDCHAR_FASTPATH) |
| 12725 | return (cp >= 0) && (duk_is_idchar_tab[cp] != 0); |
| 12726 | #else |
| 12727 | if ((cp >= 'a' && cp <= 'z') || |
| 12728 | (cp >= 'A' && cp <= 'Z') || |
| 12729 | (cp >= '0' && cp <= '9') || |
| 12730 | cp == '_' || cp == '$') { |
| 12731 | return 1; |
| 12732 | } |
| 12733 | return 0; |
| 12734 | #endif |
| 12735 | } |
| 12736 | |
| 12737 | /* Non-ASCII slow path (range-by-range linear comparison), very slow */ |
| 12738 | |
| 12739 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 12740 | if (duk__uni_range_match(duk_unicode_ids_noa, |
| 12741 | sizeof(duk_unicode_ids_noa), |
| 12742 | (duk_codepoint_t) cp) || |
| 12743 | duk__uni_range_match(duk_unicode_idp_m_ids_noa, |
| 12744 | sizeof(duk_unicode_idp_m_ids_noa), |
| 12745 | (duk_codepoint_t) cp)) { |
| 12746 | return 1; |
| 12747 | } |
| 12748 | return 0; |
| 12749 | #else |
| 12750 | if (cp < 0x10000L) { |
| 12751 | if (duk__uni_range_match(duk_unicode_ids_noabmp, |
| 12752 | sizeof(duk_unicode_ids_noabmp), |
| 12753 | (duk_codepoint_t) cp) || |
| 12754 | duk__uni_range_match(duk_unicode_idp_m_ids_noabmp, |
| 12755 | sizeof(duk_unicode_idp_m_ids_noabmp), |
| 12756 | (duk_codepoint_t) cp)) { |
| 12757 | return 1; |
| 12758 | } |
| 12759 | return 0; |
| 12760 | } else { |
| 12761 | /* without explicit non-BMP support, assume non-BMP characters |
| 12762 | * are always accepted as identifier characters. |
| 12763 | */ |
| 12764 | return 1; |
| 12765 | } |
| 12766 | #endif |
| 12767 | } |
| 12768 | |
| 12769 | /* |
| 12770 | * Unicode letter check. |
| 12771 | */ |
| 12772 | |
| 12773 | DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) { |
| 12774 | /* |
| 12775 | * Unicode letter is now taken to be the categories: |
| 12776 | * |
| 12777 | * Lu, Ll, Lt, Lm, Lo |
| 12778 | * |
| 12779 | * (Not sure if this is exactly correct.) |
| 12780 | * |
| 12781 | * The ASCII fast path consists of: |
| 12782 | * |
| 12783 | * 0x0041 ... 0x005a ['A' ... 'Z'] |
| 12784 | * 0x0061 ... 0x007a ['a' ... 'z'] |
| 12785 | */ |
| 12786 | |
| 12787 | /* ASCII (and EOF) fast path -- quick accept and reject */ |
| 12788 | if (cp <= 0x7fL) { |
| 12789 | if ((cp >= 'a' && cp <= 'z') || |
| 12790 | (cp >= 'A' && cp <= 'Z')) { |
| 12791 | return 1; |
| 12792 | } |
| 12793 | return 0; |
| 12794 | } |
| 12795 | |
| 12796 | /* Non-ASCII slow path (range-by-range linear comparison), very slow */ |
| 12797 | |
| 12798 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 12799 | if (duk__uni_range_match(duk_unicode_ids_noa, |
| 12800 | sizeof(duk_unicode_ids_noa), |
| 12801 | (duk_codepoint_t) cp) && |
| 12802 | !duk__uni_range_match(duk_unicode_ids_m_let_noa, |
| 12803 | sizeof(duk_unicode_ids_m_let_noa), |
| 12804 | (duk_codepoint_t) cp)) { |
| 12805 | return 1; |
| 12806 | } |
| 12807 | return 0; |
| 12808 | #else |
| 12809 | if (cp < 0x10000L) { |
| 12810 | if (duk__uni_range_match(duk_unicode_ids_noabmp, |
| 12811 | sizeof(duk_unicode_ids_noabmp), |
| 12812 | (duk_codepoint_t) cp) && |
| 12813 | !duk__uni_range_match(duk_unicode_ids_m_let_noabmp, |
| 12814 | sizeof(duk_unicode_ids_m_let_noabmp), |
| 12815 | (duk_codepoint_t) cp)) { |
| 12816 | return 1; |
| 12817 | } |
| 12818 | return 0; |
| 12819 | } else { |
| 12820 | /* without explicit non-BMP support, assume non-BMP characters |
| 12821 | * are always accepted as letters. |
| 12822 | */ |
| 12823 | return 1; |
| 12824 | } |
| 12825 | #endif |
| 12826 | } |
| 12827 | |
| 12828 | /* |
| 12829 | * Complex case conversion helper which decodes a bit-packed conversion |
| 12830 | * control stream generated by tools/extract_caseconv.py. The conversion |
| 12831 | * is very slow because it runs through the conversion data in a linear |
| 12832 | * fashion to save space (which is why ASCII characters have a special |
| 12833 | * fast path before arriving here). |
| 12834 | * |
| 12835 | * The particular bit counts etc have been determined experimentally to |
| 12836 | * be small but still sufficient, and must match the Python script |
| 12837 | * (tools/extract_caseconv.py). |
| 12838 | * |
| 12839 | * The return value is the case converted codepoint or -1 if the conversion |
| 12840 | * results in multiple characters (this is useful for regexp Canonicalization |
| 12841 | * operation). If 'buf' is not NULL, the result codepoint(s) are also |
| 12842 | * appended to the hbuffer. |
| 12843 | * |
| 12844 | * Context and locale specific rules must be checked before consulting |
| 12845 | * this function. |
| 12846 | */ |
| 12847 | |
| 12848 | DUK_LOCAL |
| 12849 | duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr, |
| 12850 | duk_bufwriter_ctx *bw, |
| 12851 | duk_codepoint_t cp, |
| 12852 | duk_bitdecoder_ctx *bd_ctx) { |
| 12853 | duk_small_int_t skip = 0; |
| 12854 | duk_small_int_t n; |
| 12855 | duk_small_int_t t; |
| 12856 | duk_small_int_t count; |
| 12857 | duk_codepoint_t tmp_cp; |
| 12858 | duk_codepoint_t start_i; |
| 12859 | duk_codepoint_t start_o; |
| 12860 | |
| 12861 | DUK_ASSERT(bd_ctx != NULL); |
| 12862 | DUK_UNREF(thr); |
| 12863 | |
| 12864 | DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld" , (long) cp)); |
| 12865 | |
| 12866 | /* range conversion with a "skip" */ |
| 12867 | DUK_DDD(DUK_DDDPRINT("checking ranges" )); |
| 12868 | for (;;) { |
| 12869 | skip++; |
| 12870 | n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6); |
| 12871 | if (n == 0x3f) { |
| 12872 | /* end marker */ |
| 12873 | break; |
| 12874 | } |
| 12875 | DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld" , (long) skip, (long) n)); |
| 12876 | |
| 12877 | while (n--) { |
| 12878 | start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); |
| 12879 | start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); |
| 12880 | count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); |
| 12881 | DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld" , |
| 12882 | (long) start_i, (long) start_o, (long) count, (long) skip)); |
| 12883 | |
| 12884 | if (cp >= start_i) { |
| 12885 | tmp_cp = cp - start_i; /* always >= 0 */ |
| 12886 | if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip && |
| 12887 | (tmp_cp % (duk_codepoint_t) skip) == 0) { |
| 12888 | DUK_DDD(DUK_DDDPRINT("range matches input codepoint" )); |
| 12889 | cp = start_o + tmp_cp; |
| 12890 | goto single; |
| 12891 | } |
| 12892 | } |
| 12893 | } |
| 12894 | } |
| 12895 | |
| 12896 | /* 1:1 conversion */ |
| 12897 | n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); |
| 12898 | DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)" , (long) n)); |
| 12899 | while (n--) { |
| 12900 | start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); |
| 12901 | start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); |
| 12902 | DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld" , (long) start_i, (long) start_o)); |
| 12903 | if (cp == start_i) { |
| 12904 | DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint" )); |
| 12905 | cp = start_o; |
| 12906 | goto single; |
| 12907 | } |
| 12908 | } |
| 12909 | |
| 12910 | /* complex, multicharacter conversion */ |
| 12911 | n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7); |
| 12912 | DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)" , (long) n)); |
| 12913 | while (n--) { |
| 12914 | start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); |
| 12915 | t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2); |
| 12916 | DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars" , (long) start_i, (long) t)); |
| 12917 | if (cp == start_i) { |
| 12918 | DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint" )); |
| 12919 | if (bw != NULL) { |
| 12920 | while (t--) { |
| 12921 | tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16); |
| 12922 | DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp); |
| 12923 | } |
| 12924 | } |
| 12925 | return -1; |
| 12926 | } else { |
| 12927 | while (t--) { |
| 12928 | (void) duk_bd_decode(bd_ctx, 16); |
| 12929 | } |
| 12930 | } |
| 12931 | } |
| 12932 | |
| 12933 | /* default: no change */ |
| 12934 | DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input" )); |
| 12935 | /* fall through */ |
| 12936 | |
| 12937 | single: |
| 12938 | if (bw != NULL) { |
| 12939 | DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp); |
| 12940 | } |
| 12941 | return cp; |
| 12942 | } |
| 12943 | |
| 12944 | /* |
| 12945 | * Case conversion helper, with context/local sensitivity. |
| 12946 | * For proper case conversion, one needs to know the character |
| 12947 | * and the preceding and following characters, as well as |
| 12948 | * locale/language. |
| 12949 | */ |
| 12950 | |
| 12951 | /* XXX: add 'language' argument when locale/language sensitive rule |
| 12952 | * support added. |
| 12953 | */ |
| 12954 | DUK_LOCAL |
| 12955 | duk_codepoint_t duk__case_transform_helper(duk_hthread *thr, |
| 12956 | duk_bufwriter_ctx *bw, |
| 12957 | duk_codepoint_t cp, |
| 12958 | duk_codepoint_t prev, |
| 12959 | duk_codepoint_t next, |
| 12960 | duk_bool_t uppercase) { |
| 12961 | duk_bitdecoder_ctx bd_ctx; |
| 12962 | |
| 12963 | /* fast path for ASCII */ |
| 12964 | if (cp < 0x80L) { |
| 12965 | /* XXX: there are language sensitive rules for the ASCII range. |
| 12966 | * If/when language/locale support is implemented, they need to |
| 12967 | * be implemented here for the fast path. There are no context |
| 12968 | * sensitive rules for ASCII range. |
| 12969 | */ |
| 12970 | |
| 12971 | if (uppercase) { |
| 12972 | if (cp >= 'a' && cp <= 'z') { |
| 12973 | cp = cp - 'a' + 'A'; |
| 12974 | } |
| 12975 | } else { |
| 12976 | if (cp >= 'A' && cp <= 'Z') { |
| 12977 | cp = cp - 'A' + 'a'; |
| 12978 | } |
| 12979 | } |
| 12980 | |
| 12981 | if (bw != NULL) { |
| 12982 | DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp); |
| 12983 | } |
| 12984 | return cp; |
| 12985 | } |
| 12986 | |
| 12987 | /* context and locale specific rules which cannot currently be represented |
| 12988 | * in the caseconv bitstream: hardcoded rules in C |
| 12989 | */ |
| 12990 | if (uppercase) { |
| 12991 | /* XXX: turkish / azeri */ |
| 12992 | } else { |
| 12993 | /* |
| 12994 | * Final sigma context specific rule. This is a rather tricky |
| 12995 | * rule and this handling is probably not 100% correct now. |
| 12996 | * The rule is not locale/language specific so it is supported. |
| 12997 | */ |
| 12998 | |
| 12999 | if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */ |
| 13000 | duk_unicode_is_letter(prev) && /* prev exists and is not a letter */ |
| 13001 | !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */ |
| 13002 | /* Capital sigma occurred at "end of word", lowercase to |
| 13003 | * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise |
| 13004 | * fall through and let the normal rules lowercase it to |
| 13005 | * U+03C3 = GREEK SMALL LETTER SIGMA. |
| 13006 | */ |
| 13007 | cp = 0x03c2L; |
| 13008 | goto singlechar; |
| 13009 | } |
| 13010 | |
| 13011 | /* XXX: lithuanian not implemented */ |
| 13012 | /* XXX: lithuanian, explicit dot rules */ |
| 13013 | /* XXX: turkish / azeri, lowercase rules */ |
| 13014 | } |
| 13015 | |
| 13016 | /* 1:1 or special conversions, but not locale/context specific: script generated rules */ |
| 13017 | duk_memzero(&bd_ctx, sizeof(bd_ctx)); |
| 13018 | if (uppercase) { |
| 13019 | bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc; |
| 13020 | bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc); |
| 13021 | } else { |
| 13022 | bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc; |
| 13023 | bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc); |
| 13024 | } |
| 13025 | return duk__slow_case_conversion(thr, bw, cp, &bd_ctx); |
| 13026 | |
| 13027 | singlechar: |
| 13028 | if (bw != NULL) { |
| 13029 | DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp); |
| 13030 | } |
| 13031 | return cp; |
| 13032 | |
| 13033 | /* unused now, not needed until Turkish/Azeri */ |
| 13034 | #if 0 |
| 13035 | nochar: |
| 13036 | return -1; |
| 13037 | #endif |
| 13038 | } |
| 13039 | |
| 13040 | /* |
| 13041 | * Replace valstack top with case converted version. |
| 13042 | */ |
| 13043 | |
| 13044 | DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase) { |
| 13045 | duk_hstring *h_input; |
| 13046 | duk_bufwriter_ctx bw_alloc; |
| 13047 | duk_bufwriter_ctx *bw; |
| 13048 | const duk_uint8_t *p, *p_start, *p_end; |
| 13049 | duk_codepoint_t prev, curr, next; |
| 13050 | |
| 13051 | h_input = duk_require_hstring(thr, -1); /* Accept symbols. */ |
| 13052 | DUK_ASSERT(h_input != NULL); |
| 13053 | |
| 13054 | bw = &bw_alloc; |
| 13055 | DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); |
| 13056 | |
| 13057 | /* [ ... input buffer ] */ |
| 13058 | |
| 13059 | p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); |
| 13060 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); |
| 13061 | p = p_start; |
| 13062 | |
| 13063 | prev = -1; DUK_UNREF(prev); |
| 13064 | curr = -1; |
| 13065 | next = -1; |
| 13066 | for (;;) { |
| 13067 | prev = curr; |
| 13068 | curr = next; |
| 13069 | next = -1; |
| 13070 | if (p < p_end) { |
| 13071 | next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); |
| 13072 | } else { |
| 13073 | /* end of input and last char has been processed */ |
| 13074 | if (curr < 0) { |
| 13075 | break; |
| 13076 | } |
| 13077 | } |
| 13078 | |
| 13079 | /* on first round, skip */ |
| 13080 | if (curr >= 0) { |
| 13081 | /* XXX: could add a fast path to process chunks of input codepoints, |
| 13082 | * but relative benefit would be quite small. |
| 13083 | */ |
| 13084 | |
| 13085 | /* Ensure space for maximum multi-character result; estimate is overkill. */ |
| 13086 | DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH); |
| 13087 | |
| 13088 | duk__case_transform_helper(thr, |
| 13089 | bw, |
| 13090 | (duk_codepoint_t) curr, |
| 13091 | prev, |
| 13092 | next, |
| 13093 | uppercase); |
| 13094 | } |
| 13095 | } |
| 13096 | |
| 13097 | DUK_BW_COMPACT(thr, bw); |
| 13098 | (void) duk_buffer_to_string(thr, -1); /* Safe, output is encoded. */ |
| 13099 | /* invalidates h_buf pointer */ |
| 13100 | duk_remove_m2(thr); |
| 13101 | } |
| 13102 | |
| 13103 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 13104 | |
| 13105 | /* |
| 13106 | * Canonicalize() abstract operation needed for canonicalization of individual |
| 13107 | * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8. |
| 13108 | * Note that codepoints are canonicalized one character at a time, so no context |
| 13109 | * specific rules can apply. Locale specific rules can apply, though. |
| 13110 | */ |
| 13111 | |
| 13112 | DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) { |
| 13113 | #if defined(DUK_USE_REGEXP_CANON_WORKAROUND) |
| 13114 | /* Fast canonicalization lookup at the cost of 128kB footprint. */ |
| 13115 | DUK_ASSERT(cp >= 0); |
| 13116 | DUK_UNREF(thr); |
| 13117 | if (DUK_LIKELY(cp < 0x10000L)) { |
| 13118 | return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp]; |
| 13119 | } |
| 13120 | return cp; |
| 13121 | #else /* DUK_USE_REGEXP_CANON_WORKAROUND */ |
| 13122 | duk_codepoint_t y; |
| 13123 | |
| 13124 | y = duk__case_transform_helper(thr, |
| 13125 | NULL, /* NULL is allowed, no output */ |
| 13126 | cp, /* curr char */ |
| 13127 | -1, /* prev char */ |
| 13128 | -1, /* next char */ |
| 13129 | 1); /* uppercase */ |
| 13130 | |
| 13131 | if ((y < 0) || (cp >= 0x80 && y < 0x80)) { |
| 13132 | /* multiple codepoint conversion or non-ASCII mapped to ASCII |
| 13133 | * --> leave as is. |
| 13134 | */ |
| 13135 | return cp; |
| 13136 | } |
| 13137 | |
| 13138 | return y; |
| 13139 | #endif /* DUK_USE_REGEXP_CANON_WORKAROUND */ |
| 13140 | } |
| 13141 | |
| 13142 | /* |
| 13143 | * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume |
| 13144 | * x < 0 for characters read outside the string. |
| 13145 | */ |
| 13146 | |
| 13147 | DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) { |
| 13148 | /* |
| 13149 | * Note: the description in E5 Section 15.10.2.6 has a typo, it |
| 13150 | * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_]. |
| 13151 | */ |
| 13152 | if ((x >= '0' && x <= '9') || |
| 13153 | (x >= 'a' && x <= 'z') || |
| 13154 | (x >= 'A' && x <= 'Z') || |
| 13155 | (x == '_')) { |
| 13156 | return 1; |
| 13157 | } |
| 13158 | return 0; |
| 13159 | } |
| 13160 | |
| 13161 | /* |
| 13162 | * Regexp range tables |
| 13163 | */ |
| 13164 | |
| 13165 | /* exposed because lexer needs these too */ |
| 13166 | DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = { |
| 13167 | (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL, |
| 13168 | }; |
| 13169 | DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = { |
| 13170 | (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL, |
| 13171 | (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL, |
| 13172 | (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL, |
| 13173 | (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL, |
| 13174 | (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL, |
| 13175 | (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL, |
| 13176 | (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL, |
| 13177 | (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL, |
| 13178 | (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL, |
| 13179 | (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL, |
| 13180 | (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL, |
| 13181 | }; |
| 13182 | DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = { |
| 13183 | (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL, |
| 13184 | (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL, |
| 13185 | (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL, |
| 13186 | (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL, |
| 13187 | }; |
| 13188 | DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = { |
| 13189 | (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL, |
| 13190 | (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL, |
| 13191 | }; |
| 13192 | DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = { |
| 13193 | (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL, |
| 13194 | (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL, |
| 13195 | (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL, |
| 13196 | (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL, |
| 13197 | (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL, |
| 13198 | (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL, |
| 13199 | (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL, |
| 13200 | (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL, |
| 13201 | (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL, |
| 13202 | (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL, |
| 13203 | (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL, |
| 13204 | (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL, |
| 13205 | }; |
| 13206 | DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = { |
| 13207 | (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL, |
| 13208 | (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL, |
| 13209 | (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL, |
| 13210 | (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL, |
| 13211 | (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL, |
| 13212 | }; |
| 13213 | |
| 13214 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 13215 | #line 1 "duk_util_memrw.c" |
| 13216 | /* |
| 13217 | * Macro support functions for reading/writing raw data. |
| 13218 | * |
| 13219 | * These are done using memcpy to ensure they're valid even for unaligned |
| 13220 | * reads/writes on platforms where alignment counts. On x86 at least gcc |
| 13221 | * is able to compile these into a bswap+mov. "Always inline" is used to |
| 13222 | * ensure these macros compile to minimal code. |
| 13223 | */ |
| 13224 | |
| 13225 | /* #include duk_internal.h -> already included */ |
| 13226 | |
| 13227 | union duk__u16_union { |
| 13228 | duk_uint8_t b[2]; |
| 13229 | duk_uint16_t x; |
| 13230 | }; |
| 13231 | typedef union duk__u16_union duk__u16_union; |
| 13232 | |
| 13233 | union duk__u32_union { |
| 13234 | duk_uint8_t b[4]; |
| 13235 | duk_uint32_t x; |
| 13236 | }; |
| 13237 | typedef union duk__u32_union duk__u32_union; |
| 13238 | |
| 13239 | #if defined(DUK_USE_64BIT_OPS) |
| 13240 | union duk__u64_union { |
| 13241 | duk_uint8_t b[8]; |
| 13242 | duk_uint64_t x; |
| 13243 | }; |
| 13244 | typedef union duk__u64_union duk__u64_union; |
| 13245 | #endif |
| 13246 | |
| 13247 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(const duk_uint8_t *p) { |
| 13248 | duk__u16_union u; |
| 13249 | duk_memcpy((void *) u.b, (const void *) p, (size_t) 2); |
| 13250 | u.x = DUK_NTOH16(u.x); |
| 13251 | return u.x; |
| 13252 | } |
| 13253 | |
| 13254 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(const duk_uint8_t *p) { |
| 13255 | duk__u32_union u; |
| 13256 | duk_memcpy((void *) u.b, (const void *) p, (size_t) 4); |
| 13257 | u.x = DUK_NTOH32(u.x); |
| 13258 | return u.x; |
| 13259 | } |
| 13260 | |
| 13261 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_float_t duk_raw_read_float_be(const duk_uint8_t *p) { |
| 13262 | duk_float_union fu; |
| 13263 | duk_memcpy((void *) fu.uc, (const void *) p, (size_t) 4); |
| 13264 | duk_fltunion_big_to_host(&fu); |
| 13265 | return fu.f; |
| 13266 | } |
| 13267 | |
| 13268 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(const duk_uint8_t *p) { |
| 13269 | duk_double_union du; |
| 13270 | duk_memcpy((void *) du.uc, (const void *) p, (size_t) 8); |
| 13271 | duk_dblunion_big_to_host(&du); |
| 13272 | return du.d; |
| 13273 | } |
| 13274 | |
| 13275 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_readinc_u16_be(const duk_uint8_t **p) { |
| 13276 | duk_uint16_t res = duk_raw_read_u16_be(*p); |
| 13277 | *p += 2; |
| 13278 | return res; |
| 13279 | } |
| 13280 | |
| 13281 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_readinc_u32_be(const duk_uint8_t **p) { |
| 13282 | duk_uint32_t res = duk_raw_read_u32_be(*p); |
| 13283 | *p += 4; |
| 13284 | return res; |
| 13285 | } |
| 13286 | |
| 13287 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_float_t duk_raw_readinc_float_be(const duk_uint8_t **p) { |
| 13288 | duk_float_t res = duk_raw_read_float_be(*p); |
| 13289 | *p += 4; |
| 13290 | return res; |
| 13291 | } |
| 13292 | |
| 13293 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_readinc_double_be(const duk_uint8_t **p) { |
| 13294 | duk_double_t res = duk_raw_read_double_be(*p); |
| 13295 | *p += 8; |
| 13296 | return res; |
| 13297 | } |
| 13298 | |
| 13299 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t *p, duk_uint16_t val) { |
| 13300 | duk__u16_union u; |
| 13301 | u.x = DUK_HTON16(val); |
| 13302 | duk_memcpy((void *) p, (const void *) u.b, (size_t) 2); |
| 13303 | } |
| 13304 | |
| 13305 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t *p, duk_uint32_t val) { |
| 13306 | duk__u32_union u; |
| 13307 | u.x = DUK_HTON32(val); |
| 13308 | duk_memcpy((void *) p, (const void *) u.b, (size_t) 4); |
| 13309 | } |
| 13310 | |
| 13311 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_float_be(duk_uint8_t *p, duk_float_t val) { |
| 13312 | duk_float_union fu; |
| 13313 | fu.f = val; |
| 13314 | duk_fltunion_host_to_big(&fu); |
| 13315 | duk_memcpy((void *) p, (const void *) fu.uc, (size_t) 4); |
| 13316 | } |
| 13317 | |
| 13318 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t *p, duk_double_t val) { |
| 13319 | duk_double_union du; |
| 13320 | du.d = val; |
| 13321 | duk_dblunion_host_to_big(&du); |
| 13322 | duk_memcpy((void *) p, (const void *) du.uc, (size_t) 8); |
| 13323 | } |
| 13324 | |
| 13325 | DUK_INTERNAL duk_small_int_t duk_raw_write_xutf8(duk_uint8_t *p, duk_ucodepoint_t val) { |
| 13326 | duk_small_int_t len = duk_unicode_encode_xutf8(val, p); |
| 13327 | return len; |
| 13328 | } |
| 13329 | |
| 13330 | DUK_INTERNAL duk_small_int_t duk_raw_write_cesu8(duk_uint8_t *p, duk_ucodepoint_t val) { |
| 13331 | duk_small_int_t len = duk_unicode_encode_cesu8(val, p); |
| 13332 | return len; |
| 13333 | } |
| 13334 | |
| 13335 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_u16_be(duk_uint8_t **p, duk_uint16_t val) { |
| 13336 | duk_raw_write_u16_be(*p, val); |
| 13337 | *p += 2; |
| 13338 | } |
| 13339 | |
| 13340 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_u32_be(duk_uint8_t **p, duk_uint32_t val) { |
| 13341 | duk_raw_write_u32_be(*p, val); |
| 13342 | *p += 4; |
| 13343 | } |
| 13344 | |
| 13345 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_float_be(duk_uint8_t **p, duk_float_t val) { |
| 13346 | duk_raw_write_float_be(*p, val); |
| 13347 | *p += 4; |
| 13348 | } |
| 13349 | |
| 13350 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_writeinc_double_be(duk_uint8_t **p, duk_double_t val) { |
| 13351 | duk_raw_write_double_be(*p, val); |
| 13352 | *p += 8; |
| 13353 | } |
| 13354 | |
| 13355 | DUK_INTERNAL void duk_raw_writeinc_xutf8(duk_uint8_t **p, duk_ucodepoint_t val) { |
| 13356 | duk_small_int_t len = duk_unicode_encode_xutf8(val, *p); |
| 13357 | *p += len; |
| 13358 | } |
| 13359 | |
| 13360 | DUK_INTERNAL void duk_raw_writeinc_cesu8(duk_uint8_t **p, duk_ucodepoint_t val) { |
| 13361 | duk_small_int_t len = duk_unicode_encode_cesu8(val, *p); |
| 13362 | *p += len; |
| 13363 | } |
| 13364 | #line 1 "duk_util_misc.c" |
| 13365 | /* |
| 13366 | * Misc util stuff. |
| 13367 | */ |
| 13368 | |
| 13369 | /* #include duk_internal.h -> already included */ |
| 13370 | |
| 13371 | /* |
| 13372 | * Lowercase digits for radix values 2 to 36. Also doubles as lowercase |
| 13373 | * hex nybble table. |
| 13374 | */ |
| 13375 | |
| 13376 | DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = { |
| 13377 | DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, |
| 13378 | DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, |
| 13379 | DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B, |
| 13380 | DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F, |
| 13381 | DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J, |
| 13382 | DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N, |
| 13383 | DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R, |
| 13384 | DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V, |
| 13385 | DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z |
| 13386 | }; |
| 13387 | |
| 13388 | DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = { |
| 13389 | DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, |
| 13390 | DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, |
| 13391 | DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B, |
| 13392 | DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F |
| 13393 | }; |
| 13394 | |
| 13395 | /* |
| 13396 | * Table for hex decoding ASCII hex digits |
| 13397 | */ |
| 13398 | |
| 13399 | DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = { |
| 13400 | /* -1 if invalid */ |
| 13401 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ |
| 13402 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ |
| 13403 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ |
| 13404 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */ |
| 13405 | -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */ |
| 13406 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */ |
| 13407 | -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */ |
| 13408 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */ |
| 13409 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */ |
| 13410 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */ |
| 13411 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */ |
| 13412 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */ |
| 13413 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */ |
| 13414 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */ |
| 13415 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */ |
| 13416 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ |
| 13417 | }; |
| 13418 | |
| 13419 | #if defined(DUK_USE_HEX_FASTPATH) |
| 13420 | /* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */ |
| 13421 | DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = { |
| 13422 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */ |
| 13423 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */ |
| 13424 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */ |
| 13425 | 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */ |
| 13426 | -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */ |
| 13427 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */ |
| 13428 | -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */ |
| 13429 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */ |
| 13430 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */ |
| 13431 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */ |
| 13432 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */ |
| 13433 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */ |
| 13434 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */ |
| 13435 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */ |
| 13436 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */ |
| 13437 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */ |
| 13438 | }; |
| 13439 | #endif |
| 13440 | |
| 13441 | /* |
| 13442 | * Table for hex encoding bytes |
| 13443 | */ |
| 13444 | |
| 13445 | #if defined(DUK_USE_HEX_FASTPATH) |
| 13446 | /* Lookup to encode one byte directly into 2 characters: |
| 13447 | * |
| 13448 | * def genhextab(bswap): |
| 13449 | * for i in xrange(256): |
| 13450 | * t = chr(i).encode('hex') |
| 13451 | * if bswap: |
| 13452 | * t = t[1] + t[0] |
| 13453 | * print('0x' + t.encode('hex') + 'U') |
| 13454 | * print('big endian'); genhextab(False) |
| 13455 | * print('little endian'); genhextab(True) |
| 13456 | */ |
| 13457 | DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = { |
| 13458 | #if defined(DUK_USE_INTEGER_BE) |
| 13459 | 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U, |
| 13460 | 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U, |
| 13461 | 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U, |
| 13462 | 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U, |
| 13463 | 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U, |
| 13464 | 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U, |
| 13465 | 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U, |
| 13466 | 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U, |
| 13467 | 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U, |
| 13468 | 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U, |
| 13469 | 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U, |
| 13470 | 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U, |
| 13471 | 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U, |
| 13472 | 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U, |
| 13473 | 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U, |
| 13474 | 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U, |
| 13475 | 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U, |
| 13476 | 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U, |
| 13477 | 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U, |
| 13478 | 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U, |
| 13479 | 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U, |
| 13480 | 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U, |
| 13481 | 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U, |
| 13482 | 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U, |
| 13483 | 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U, |
| 13484 | 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U, |
| 13485 | 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U, |
| 13486 | 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U, |
| 13487 | 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U, |
| 13488 | 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U, |
| 13489 | 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U, |
| 13490 | 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U |
| 13491 | #else /* DUK_USE_INTEGER_BE */ |
| 13492 | 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U, |
| 13493 | 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U, |
| 13494 | 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U, |
| 13495 | 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U, |
| 13496 | 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U, |
| 13497 | 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U, |
| 13498 | 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U, |
| 13499 | 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U, |
| 13500 | 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U, |
| 13501 | 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U, |
| 13502 | 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U, |
| 13503 | 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U, |
| 13504 | 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U, |
| 13505 | 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U, |
| 13506 | 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U, |
| 13507 | 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U, |
| 13508 | 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U, |
| 13509 | 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U, |
| 13510 | 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U, |
| 13511 | 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U, |
| 13512 | 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U, |
| 13513 | 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U, |
| 13514 | 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U, |
| 13515 | 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U, |
| 13516 | 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U, |
| 13517 | 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U, |
| 13518 | 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U, |
| 13519 | 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U, |
| 13520 | 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U, |
| 13521 | 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U, |
| 13522 | 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U, |
| 13523 | 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U |
| 13524 | #endif /* DUK_USE_INTEGER_BE */ |
| 13525 | }; |
| 13526 | #endif /* DUK_USE_HEX_FASTPATH */ |
| 13527 | |
| 13528 | /* |
| 13529 | * Arbitrary byteswap for potentially unaligned values |
| 13530 | * |
| 13531 | * Used to byteswap pointers e.g. in debugger code. |
| 13532 | */ |
| 13533 | |
| 13534 | #if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */ |
| 13535 | DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) { |
| 13536 | duk_uint8_t tmp; |
| 13537 | duk_uint8_t *q = p + len - 1; |
| 13538 | |
| 13539 | while (p - q < 0) { |
| 13540 | tmp = *p; |
| 13541 | *p = *q; |
| 13542 | *q = tmp; |
| 13543 | p++; |
| 13544 | q--; |
| 13545 | } |
| 13546 | } |
| 13547 | #endif |
| 13548 | #line 1 "duk_hobject_class.c" |
| 13549 | /* |
| 13550 | * Hobject ECMAScript [[Class]]. |
| 13551 | */ |
| 13552 | |
| 13553 | /* #include duk_internal.h -> already included */ |
| 13554 | |
| 13555 | #if (DUK_STRIDX_UC_ARGUMENTS > 255) |
| 13556 | #error constant too large |
| 13557 | #endif |
| 13558 | #if (DUK_STRIDX_UC_ARRAY > 255) |
| 13559 | #error constant too large |
| 13560 | #endif |
| 13561 | #if (DUK_STRIDX_UC_BOOLEAN > 255) |
| 13562 | #error constant too large |
| 13563 | #endif |
| 13564 | #if (DUK_STRIDX_UC_DATE > 255) |
| 13565 | #error constant too large |
| 13566 | #endif |
| 13567 | #if (DUK_STRIDX_UC_ERROR > 255) |
| 13568 | #error constant too large |
| 13569 | #endif |
| 13570 | #if (DUK_STRIDX_UC_FUNCTION > 255) |
| 13571 | #error constant too large |
| 13572 | #endif |
| 13573 | #if (DUK_STRIDX_JSON > 255) |
| 13574 | #error constant too large |
| 13575 | #endif |
| 13576 | #if (DUK_STRIDX_MATH > 255) |
| 13577 | #error constant too large |
| 13578 | #endif |
| 13579 | #if (DUK_STRIDX_UC_NUMBER > 255) |
| 13580 | #error constant too large |
| 13581 | #endif |
| 13582 | #if (DUK_STRIDX_UC_OBJECT > 255) |
| 13583 | #error constant too large |
| 13584 | #endif |
| 13585 | #if (DUK_STRIDX_REG_EXP > 255) |
| 13586 | #error constant too large |
| 13587 | #endif |
| 13588 | #if (DUK_STRIDX_UC_STRING > 255) |
| 13589 | #error constant too large |
| 13590 | #endif |
| 13591 | #if (DUK_STRIDX_GLOBAL > 255) |
| 13592 | #error constant too large |
| 13593 | #endif |
| 13594 | #if (DUK_STRIDX_OBJ_ENV > 255) |
| 13595 | #error constant too large |
| 13596 | #endif |
| 13597 | #if (DUK_STRIDX_DEC_ENV > 255) |
| 13598 | #error constant too large |
| 13599 | #endif |
| 13600 | #if (DUK_STRIDX_UC_POINTER > 255) |
| 13601 | #error constant too large |
| 13602 | #endif |
| 13603 | #if (DUK_STRIDX_UC_THREAD > 255) |
| 13604 | #error constant too large |
| 13605 | #endif |
| 13606 | #if (DUK_STRIDX_ARRAY_BUFFER > 255) |
| 13607 | #error constant too large |
| 13608 | #endif |
| 13609 | #if (DUK_STRIDX_DATA_VIEW > 255) |
| 13610 | #error constant too large |
| 13611 | #endif |
| 13612 | #if (DUK_STRIDX_INT8_ARRAY > 255) |
| 13613 | #error constant too large |
| 13614 | #endif |
| 13615 | #if (DUK_STRIDX_UINT8_ARRAY > 255) |
| 13616 | #error constant too large |
| 13617 | #endif |
| 13618 | #if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255) |
| 13619 | #error constant too large |
| 13620 | #endif |
| 13621 | #if (DUK_STRIDX_INT16_ARRAY > 255) |
| 13622 | #error constant too large |
| 13623 | #endif |
| 13624 | #if (DUK_STRIDX_UINT16_ARRAY > 255) |
| 13625 | #error constant too large |
| 13626 | #endif |
| 13627 | #if (DUK_STRIDX_INT32_ARRAY > 255) |
| 13628 | #error constant too large |
| 13629 | #endif |
| 13630 | #if (DUK_STRIDX_UINT32_ARRAY > 255) |
| 13631 | #error constant too large |
| 13632 | #endif |
| 13633 | #if (DUK_STRIDX_FLOAT32_ARRAY > 255) |
| 13634 | #error constant too large |
| 13635 | #endif |
| 13636 | #if (DUK_STRIDX_FLOAT64_ARRAY > 255) |
| 13637 | #error constant too large |
| 13638 | #endif |
| 13639 | #if (DUK_STRIDX_EMPTY_STRING > 255) |
| 13640 | #error constant too large |
| 13641 | #endif |
| 13642 | |
| 13643 | /* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */ |
| 13644 | DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = { |
| 13645 | DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */ |
| 13646 | DUK_STRIDX_UC_OBJECT, |
| 13647 | DUK_STRIDX_UC_ARRAY, |
| 13648 | DUK_STRIDX_UC_FUNCTION, |
| 13649 | DUK_STRIDX_UC_ARGUMENTS, |
| 13650 | DUK_STRIDX_UC_BOOLEAN, |
| 13651 | DUK_STRIDX_UC_DATE, |
| 13652 | DUK_STRIDX_UC_ERROR, |
| 13653 | DUK_STRIDX_JSON, |
| 13654 | DUK_STRIDX_MATH, |
| 13655 | DUK_STRIDX_UC_NUMBER, |
| 13656 | DUK_STRIDX_REG_EXP, |
| 13657 | DUK_STRIDX_UC_STRING, |
| 13658 | DUK_STRIDX_GLOBAL, |
| 13659 | DUK_STRIDX_UC_SYMBOL, |
| 13660 | DUK_STRIDX_OBJ_ENV, |
| 13661 | DUK_STRIDX_DEC_ENV, |
| 13662 | DUK_STRIDX_UC_POINTER, |
| 13663 | DUK_STRIDX_UC_THREAD, |
| 13664 | DUK_STRIDX_ARRAY_BUFFER, |
| 13665 | DUK_STRIDX_DATA_VIEW, |
| 13666 | DUK_STRIDX_INT8_ARRAY, |
| 13667 | DUK_STRIDX_UINT8_ARRAY, |
| 13668 | DUK_STRIDX_UINT8_CLAMPED_ARRAY, |
| 13669 | DUK_STRIDX_INT16_ARRAY, |
| 13670 | DUK_STRIDX_UINT16_ARRAY, |
| 13671 | DUK_STRIDX_INT32_ARRAY, |
| 13672 | DUK_STRIDX_UINT32_ARRAY, |
| 13673 | DUK_STRIDX_FLOAT32_ARRAY, |
| 13674 | DUK_STRIDX_FLOAT64_ARRAY, |
| 13675 | DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ |
| 13676 | DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */ |
| 13677 | }; |
| 13678 | #line 1 "duk_alloc_default.c" |
| 13679 | /* |
| 13680 | * Default allocation functions. |
| 13681 | * |
| 13682 | * Assumes behavior such as malloc allowing zero size, yielding |
| 13683 | * a NULL or a unique pointer which is a no-op for free. |
| 13684 | */ |
| 13685 | |
| 13686 | /* #include duk_internal.h -> already included */ |
| 13687 | |
| 13688 | #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) |
| 13689 | DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) { |
| 13690 | void *res; |
| 13691 | DUK_UNREF(udata); |
| 13692 | res = DUK_ANSI_MALLOC(size); |
| 13693 | DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p" , |
| 13694 | (unsigned long) size, (void *) res)); |
| 13695 | return res; |
| 13696 | } |
| 13697 | |
| 13698 | DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) { |
| 13699 | void *res; |
| 13700 | DUK_UNREF(udata); |
| 13701 | res = DUK_ANSI_REALLOC(ptr, newsize); |
| 13702 | DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p" , |
| 13703 | (void *) ptr, (unsigned long) newsize, (void *) res)); |
| 13704 | return res; |
| 13705 | } |
| 13706 | |
| 13707 | DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) { |
| 13708 | DUK_DDD(DUK_DDDPRINT("default free function: %p" , (void *) ptr)); |
| 13709 | DUK_UNREF(udata); |
| 13710 | DUK_ANSI_FREE(ptr); |
| 13711 | } |
| 13712 | #endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */ |
| 13713 | #line 1 "duk_api_buffer.c" |
| 13714 | /* |
| 13715 | * Buffer |
| 13716 | */ |
| 13717 | |
| 13718 | /* #include duk_internal.h -> already included */ |
| 13719 | |
| 13720 | DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) { |
| 13721 | duk_hbuffer_dynamic *h; |
| 13722 | |
| 13723 | DUK_ASSERT_API_ENTRY(thr); |
| 13724 | |
| 13725 | h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx); |
| 13726 | DUK_ASSERT(h != NULL); |
| 13727 | |
| 13728 | if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { |
| 13729 | DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); |
| 13730 | DUK_WO_NORETURN(return NULL;); |
| 13731 | } |
| 13732 | |
| 13733 | /* Maximum size check is handled by callee. */ |
| 13734 | duk_hbuffer_resize(thr, h, new_size); |
| 13735 | |
| 13736 | return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); |
| 13737 | } |
| 13738 | |
| 13739 | DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { |
| 13740 | duk_hbuffer_dynamic *h; |
| 13741 | void *ptr; |
| 13742 | duk_size_t sz; |
| 13743 | |
| 13744 | DUK_ASSERT_API_ENTRY(thr); |
| 13745 | |
| 13746 | h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx); |
| 13747 | DUK_ASSERT(h != NULL); |
| 13748 | |
| 13749 | if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) { |
| 13750 | DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); |
| 13751 | DUK_WO_NORETURN(return NULL;); |
| 13752 | } |
| 13753 | |
| 13754 | /* Forget the previous allocation, setting size to 0 and alloc to |
| 13755 | * NULL. Caller is responsible for freeing the previous allocation. |
| 13756 | * Getting the allocation and clearing it is done in the same API |
| 13757 | * call to avoid any chance of a realloc. |
| 13758 | */ |
| 13759 | ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h); |
| 13760 | sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h); |
| 13761 | if (out_size) { |
| 13762 | *out_size = sz; |
| 13763 | } |
| 13764 | DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h); |
| 13765 | DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0); |
| 13766 | |
| 13767 | return ptr; |
| 13768 | } |
| 13769 | |
| 13770 | DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) { |
| 13771 | duk_hbuffer_external *h; |
| 13772 | |
| 13773 | DUK_ASSERT_API_ENTRY(thr); |
| 13774 | |
| 13775 | h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx); |
| 13776 | DUK_ASSERT(h != NULL); |
| 13777 | |
| 13778 | if (!DUK_HBUFFER_HAS_EXTERNAL(h)) { |
| 13779 | DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE); |
| 13780 | DUK_WO_NORETURN(return;); |
| 13781 | } |
| 13782 | DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h)); |
| 13783 | |
| 13784 | DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr); |
| 13785 | DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len); |
| 13786 | } |
| 13787 | #line 1 "duk_api_bytecode.c" |
| 13788 | /* |
| 13789 | * Bytecode dump/load |
| 13790 | * |
| 13791 | * The bytecode load primitive is more important performance-wise than the |
| 13792 | * dump primitive. |
| 13793 | * |
| 13794 | * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be |
| 13795 | * memory safe for invalid arguments - caller beware! There's little point |
| 13796 | * in trying to achieve memory safety unless bytecode instructions are also |
| 13797 | * validated which is not easy to do with indirect register references etc. |
| 13798 | */ |
| 13799 | |
| 13800 | /* #include duk_internal.h -> already included */ |
| 13801 | |
| 13802 | #if defined(DUK_USE_BYTECODE_DUMP_SUPPORT) |
| 13803 | |
| 13804 | #define DUK__SER_MARKER 0xbf |
| 13805 | #define DUK__SER_STRING 0x00 |
| 13806 | #define DUK__SER_NUMBER 0x01 |
| 13807 | #define DUK__BYTECODE_INITIAL_ALLOC 256 |
| 13808 | #define DUK__NO_FORMALS 0xffffffffUL |
| 13809 | |
| 13810 | /* |
| 13811 | * Dump/load helpers, xxx_raw() helpers do no buffer checks |
| 13812 | */ |
| 13813 | |
| 13814 | DUK_LOCAL const duk_uint8_t *duk__load_string_raw(duk_hthread *thr, const duk_uint8_t *p) { |
| 13815 | duk_uint32_t len; |
| 13816 | |
| 13817 | len = DUK_RAW_READINC_U32_BE(p); |
| 13818 | duk_push_lstring(thr, (const char *) p, len); |
| 13819 | p += len; |
| 13820 | return p; |
| 13821 | } |
| 13822 | |
| 13823 | DUK_LOCAL const duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, const duk_uint8_t *p) { |
| 13824 | duk_uint32_t len; |
| 13825 | duk_uint8_t *buf; |
| 13826 | |
| 13827 | len = DUK_RAW_READINC_U32_BE(p); |
| 13828 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); |
| 13829 | DUK_ASSERT(buf != NULL); |
| 13830 | duk_memcpy((void *) buf, (const void *) p, (size_t) len); |
| 13831 | p += len; |
| 13832 | return p; |
| 13833 | } |
| 13834 | |
| 13835 | DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) { |
| 13836 | duk_size_t len; |
| 13837 | duk_uint32_t tmp32; |
| 13838 | |
| 13839 | DUK_ASSERT(h != NULL); |
| 13840 | |
| 13841 | len = DUK_HSTRING_GET_BYTELEN(h); |
| 13842 | DUK_ASSERT(len <= 0xffffffffUL); /* string limits */ |
| 13843 | tmp32 = (duk_uint32_t) len; |
| 13844 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 13845 | duk_memcpy((void *) p, |
| 13846 | (const void *) DUK_HSTRING_GET_DATA(h), |
| 13847 | len); |
| 13848 | p += len; |
| 13849 | return p; |
| 13850 | } |
| 13851 | |
| 13852 | DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) { |
| 13853 | duk_size_t len; |
| 13854 | duk_uint32_t tmp32; |
| 13855 | |
| 13856 | DUK_ASSERT(thr != NULL); |
| 13857 | DUK_ASSERT(h != NULL); |
| 13858 | DUK_UNREF(thr); |
| 13859 | |
| 13860 | len = DUK_HBUFFER_GET_SIZE(h); |
| 13861 | DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */ |
| 13862 | tmp32 = (duk_uint32_t) len; |
| 13863 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 13864 | /* When len == 0, buffer data pointer may be NULL. */ |
| 13865 | duk_memcpy_unsafe((void *) p, |
| 13866 | (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h), |
| 13867 | len); |
| 13868 | p += len; |
| 13869 | return p; |
| 13870 | } |
| 13871 | |
| 13872 | DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { |
| 13873 | duk_hstring *h_str; |
| 13874 | duk_tval *tv; |
| 13875 | |
| 13876 | tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx); |
| 13877 | if (tv != NULL && DUK_TVAL_IS_STRING(tv)) { |
| 13878 | h_str = DUK_TVAL_GET_STRING(tv); |
| 13879 | DUK_ASSERT(h_str != NULL); |
| 13880 | } else { |
| 13881 | h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); |
| 13882 | DUK_ASSERT(h_str != NULL); |
| 13883 | } |
| 13884 | DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ |
| 13885 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p); |
| 13886 | p = duk__dump_hstring_raw(p, h_str); |
| 13887 | return p; |
| 13888 | } |
| 13889 | |
| 13890 | DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) { |
| 13891 | duk_tval *tv; |
| 13892 | |
| 13893 | tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx); |
| 13894 | if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) { |
| 13895 | duk_hbuffer *h_buf; |
| 13896 | h_buf = DUK_TVAL_GET_BUFFER(tv); |
| 13897 | DUK_ASSERT(h_buf != NULL); |
| 13898 | DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ |
| 13899 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p); |
| 13900 | p = duk__dump_hbuffer_raw(thr, p, h_buf); |
| 13901 | } else { |
| 13902 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); |
| 13903 | DUK_RAW_WRITEINC_U32_BE(p, 0); |
| 13904 | } |
| 13905 | return p; |
| 13906 | } |
| 13907 | |
| 13908 | DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx, duk_uint32_t def_value) { |
| 13909 | duk_tval *tv; |
| 13910 | duk_uint32_t val; |
| 13911 | |
| 13912 | tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx); |
| 13913 | if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) { |
| 13914 | val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv); |
| 13915 | } else { |
| 13916 | val = def_value; |
| 13917 | } |
| 13918 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); |
| 13919 | DUK_RAW_WRITEINC_U32_BE(p, val); |
| 13920 | return p; |
| 13921 | } |
| 13922 | |
| 13923 | DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { |
| 13924 | duk_hobject *h; |
| 13925 | |
| 13926 | h = duk_hobject_get_varmap(thr, (duk_hobject *) func); |
| 13927 | if (h != NULL) { |
| 13928 | duk_uint_fast32_t i; |
| 13929 | |
| 13930 | /* We know _Varmap only has own properties so walk property |
| 13931 | * table directly. We also know _Varmap is dense and all |
| 13932 | * values are numbers; assert for these. GC and finalizers |
| 13933 | * shouldn't affect _Varmap so side effects should be fine. |
| 13934 | */ |
| 13935 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { |
| 13936 | duk_hstring *key; |
| 13937 | duk_tval *tv_val; |
| 13938 | duk_uint32_t val; |
| 13939 | |
| 13940 | key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i); |
| 13941 | DUK_ASSERT(key != NULL); /* _Varmap is dense */ |
| 13942 | DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)); |
| 13943 | tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i); |
| 13944 | DUK_ASSERT(tv_val != NULL); |
| 13945 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */ |
| 13946 | #if defined(DUK_USE_FASTINT) |
| 13947 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val)); |
| 13948 | DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */ |
| 13949 | val = DUK_TVAL_GET_FASTINT_U32(tv_val); |
| 13950 | #else |
| 13951 | val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val); |
| 13952 | #endif |
| 13953 | |
| 13954 | DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ |
| 13955 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p); |
| 13956 | p = duk__dump_hstring_raw(p, key); |
| 13957 | DUK_RAW_WRITEINC_U32_BE(p, val); |
| 13958 | } |
| 13959 | } |
| 13960 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); |
| 13961 | DUK_RAW_WRITEINC_U32_BE(p, 0); /* end of _Varmap */ |
| 13962 | return p; |
| 13963 | } |
| 13964 | |
| 13965 | DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { |
| 13966 | duk_harray *h; |
| 13967 | |
| 13968 | h = duk_hobject_get_formals(thr, (duk_hobject *) func); |
| 13969 | if (h != NULL) { |
| 13970 | duk_uint32_t i; |
| 13971 | |
| 13972 | /* Here we rely on _Formals being a dense array containing |
| 13973 | * strings. This should be the case unless _Formals has been |
| 13974 | * tweaked by the application (which we don't support right |
| 13975 | * now). |
| 13976 | */ |
| 13977 | |
| 13978 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); |
| 13979 | DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */ |
| 13980 | DUK_RAW_WRITEINC_U32_BE(p, h->length); |
| 13981 | |
| 13982 | for (i = 0; i < h->length; i++) { |
| 13983 | duk_tval *tv_val; |
| 13984 | duk_hstring *varname; |
| 13985 | |
| 13986 | tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i); |
| 13987 | DUK_ASSERT(tv_val != NULL); |
| 13988 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val)); |
| 13989 | |
| 13990 | varname = DUK_TVAL_GET_STRING(tv_val); |
| 13991 | DUK_ASSERT(varname != NULL); |
| 13992 | DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); |
| 13993 | |
| 13994 | DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ |
| 13995 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p); |
| 13996 | p = duk__dump_hstring_raw(p, varname); |
| 13997 | } |
| 13998 | } else { |
| 13999 | DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals" )); |
| 14000 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p); |
| 14001 | DUK_RAW_WRITEINC_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */ |
| 14002 | } |
| 14003 | return p; |
| 14004 | } |
| 14005 | |
| 14006 | static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) { |
| 14007 | duk_tval *tv, *tv_end; |
| 14008 | duk_instr_t *ins, *ins_end; |
| 14009 | duk_hobject **fn, **fn_end; |
| 14010 | duk_hstring *h_str; |
| 14011 | duk_uint32_t count_instr; |
| 14012 | duk_uint32_t tmp32; |
| 14013 | duk_uint16_t tmp16; |
| 14014 | duk_double_t d; |
| 14015 | |
| 14016 | DUK_DD(DUK_DDPRINT("dumping function %p to %p: " |
| 14017 | "consts=[%p,%p[ (%ld bytes, %ld items), " |
| 14018 | "funcs=[%p,%p[ (%ld bytes, %ld items), " |
| 14019 | "code=[%p,%p[ (%ld bytes, %ld items)" , |
| 14020 | (void *) func, |
| 14021 | (void *) p, |
| 14022 | (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func), |
| 14023 | (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func), |
| 14024 | (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func), |
| 14025 | (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func), |
| 14026 | (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func), |
| 14027 | (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func), |
| 14028 | (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func), |
| 14029 | (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func), |
| 14030 | (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func), |
| 14031 | (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func), |
| 14032 | (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func), |
| 14033 | (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func))); |
| 14034 | |
| 14035 | DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */ |
| 14036 | count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func); |
| 14037 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p); |
| 14038 | |
| 14039 | /* Fixed header info. */ |
| 14040 | tmp32 = count_instr; |
| 14041 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 14042 | tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func); |
| 14043 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 14044 | tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func); |
| 14045 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 14046 | tmp16 = func->nregs; |
| 14047 | DUK_RAW_WRITEINC_U16_BE(p, tmp16); |
| 14048 | tmp16 = func->nargs; |
| 14049 | DUK_RAW_WRITEINC_U16_BE(p, tmp16); |
| 14050 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 14051 | tmp32 = func->start_line; |
| 14052 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 14053 | tmp32 = func->end_line; |
| 14054 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 14055 | #else |
| 14056 | DUK_RAW_WRITEINC_U32_BE(p, 0); |
| 14057 | DUK_RAW_WRITEINC_U32_BE(p, 0); |
| 14058 | #endif |
| 14059 | tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */ |
| 14060 | tmp32 &= ~(DUK_HOBJECT_FLAG_HAVE_FINALIZER); /* finalizer flag is lost */ |
| 14061 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 14062 | |
| 14063 | /* Bytecode instructions: endian conversion needed unless |
| 14064 | * platform is big endian. |
| 14065 | */ |
| 14066 | ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func); |
| 14067 | ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func); |
| 14068 | DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr); |
| 14069 | #if defined(DUK_USE_INTEGER_BE) |
| 14070 | duk_memcpy_unsafe((void *) p, (const void *) ins, (size_t) (ins_end - ins)); |
| 14071 | p += (size_t) (ins_end - ins); |
| 14072 | #else |
| 14073 | while (ins != ins_end) { |
| 14074 | tmp32 = (duk_uint32_t) (*ins); |
| 14075 | DUK_RAW_WRITEINC_U32_BE(p, tmp32); |
| 14076 | ins++; |
| 14077 | } |
| 14078 | #endif |
| 14079 | |
| 14080 | /* Constants: variable size encoding. */ |
| 14081 | tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func); |
| 14082 | tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func); |
| 14083 | while (tv != tv_end) { |
| 14084 | /* constants are strings or numbers now */ |
| 14085 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv) || |
| 14086 | DUK_TVAL_IS_NUMBER(tv)); |
| 14087 | |
| 14088 | if (DUK_TVAL_IS_STRING(tv)) { |
| 14089 | h_str = DUK_TVAL_GET_STRING(tv); |
| 14090 | DUK_ASSERT(h_str != NULL); |
| 14091 | DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ |
| 14092 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p); |
| 14093 | *p++ = DUK__SER_STRING; |
| 14094 | p = duk__dump_hstring_raw(p, h_str); |
| 14095 | } else { |
| 14096 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 14097 | p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p); |
| 14098 | *p++ = DUK__SER_NUMBER; |
| 14099 | d = DUK_TVAL_GET_NUMBER(tv); |
| 14100 | DUK_RAW_WRITEINC_DOUBLE_BE(p, d); |
| 14101 | } |
| 14102 | tv++; |
| 14103 | } |
| 14104 | |
| 14105 | /* Inner functions recursively. */ |
| 14106 | fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func); |
| 14107 | fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func); |
| 14108 | while (fn != fn_end) { |
| 14109 | /* XXX: This causes recursion up to inner function depth |
| 14110 | * which is normally not an issue, e.g. mark-and-sweep uses |
| 14111 | * a recursion limiter to avoid C stack issues. Avoiding |
| 14112 | * this would mean some sort of a work list or just refusing |
| 14113 | * to serialize deep functions. |
| 14114 | */ |
| 14115 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn)); |
| 14116 | p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p); |
| 14117 | fn++; |
| 14118 | } |
| 14119 | |
| 14120 | /* Lexenv and varenv are not dumped. */ |
| 14121 | |
| 14122 | /* Object extra properties. |
| 14123 | * |
| 14124 | * There are some difference between function templates and functions. |
| 14125 | * For example, function templates don't have .length and nargs is |
| 14126 | * normally used to instantiate the functions. |
| 14127 | */ |
| 14128 | |
| 14129 | p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs); |
| 14130 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 14131 | p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME); |
| 14132 | #endif |
| 14133 | #if defined(DUK_USE_FUNC_FILENAME_PROPERTY) |
| 14134 | p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME); |
| 14135 | #endif |
| 14136 | #if defined(DUK_USE_PC2LINE) |
| 14137 | p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE); |
| 14138 | #endif |
| 14139 | p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func); |
| 14140 | p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func); |
| 14141 | |
| 14142 | DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p" , (void *) func, (void *) p)); |
| 14143 | |
| 14144 | return p; |
| 14145 | } |
| 14146 | |
| 14147 | /* Load a function from bytecode. The function object returned here must |
| 14148 | * match what is created by duk_js_push_closure() with respect to its flags, |
| 14149 | * properties, etc. |
| 14150 | * |
| 14151 | * NOTE: there are intentionally no input buffer length / bound checks. |
| 14152 | * Adding them would be easy but wouldn't ensure memory safety as untrusted |
| 14153 | * or broken bytecode is unsafe during execution unless the opcodes themselves |
| 14154 | * are validated (which is quite complex, especially for indirect opcodes). |
| 14155 | */ |
| 14156 | |
| 14157 | #define DUK__ASSERT_LEFT(n) do { \ |
| 14158 | DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \ |
| 14159 | } while (0) |
| 14160 | |
| 14161 | static const duk_uint8_t *duk__load_func(duk_hthread *thr, const duk_uint8_t *p, const duk_uint8_t *p_end) { |
| 14162 | duk_hcompfunc *h_fun; |
| 14163 | duk_hbuffer *h_data; |
| 14164 | duk_size_t data_size; |
| 14165 | duk_uint32_t count_instr, count_const, count_funcs; |
| 14166 | duk_uint32_t n; |
| 14167 | duk_uint32_t tmp32; |
| 14168 | duk_small_uint_t const_type; |
| 14169 | duk_uint8_t *fun_data; |
| 14170 | duk_uint8_t *q; |
| 14171 | duk_idx_t idx_base; |
| 14172 | duk_tval *tv1; |
| 14173 | duk_uarridx_t arr_idx; |
| 14174 | duk_uarridx_t arr_limit; |
| 14175 | duk_hobject *func_env; |
| 14176 | duk_bool_t need_pop; |
| 14177 | |
| 14178 | /* XXX: There's some overlap with duk_js_closure() here, but |
| 14179 | * seems difficult to share code. Ensure that the final function |
| 14180 | * looks the same as created by duk_js_closure(). |
| 14181 | */ |
| 14182 | |
| 14183 | DUK_ASSERT(thr != NULL); |
| 14184 | |
| 14185 | DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p" , (const void *) p, (const void *) p_end)); |
| 14186 | |
| 14187 | DUK__ASSERT_LEFT(3 * 4); |
| 14188 | count_instr = DUK_RAW_READINC_U32_BE(p); |
| 14189 | count_const = DUK_RAW_READINC_U32_BE(p); |
| 14190 | count_funcs = DUK_RAW_READINC_U32_BE(p); |
| 14191 | |
| 14192 | data_size = sizeof(duk_tval) * count_const + |
| 14193 | sizeof(duk_hobject *) * count_funcs + |
| 14194 | sizeof(duk_instr_t) * count_instr; |
| 14195 | |
| 14196 | DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld" , |
| 14197 | (long) count_instr, (long) count_const, |
| 14198 | (long) count_const, (long) data_size)); |
| 14199 | |
| 14200 | /* Value stack is used to ensure reachability of constants and |
| 14201 | * inner functions being loaded. Require enough space to handle |
| 14202 | * large functions correctly. |
| 14203 | */ |
| 14204 | duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs)); |
| 14205 | idx_base = duk_get_top(thr); |
| 14206 | |
| 14207 | /* Push function object, init flags etc. This must match |
| 14208 | * duk_js_push_closure() quite carefully. |
| 14209 | */ |
| 14210 | h_fun = duk_push_hcompfunc(thr); |
| 14211 | DUK_ASSERT(h_fun != NULL); |
| 14212 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun)); |
| 14213 | DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL); |
| 14214 | DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL); |
| 14215 | DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL); |
| 14216 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 14217 | |
| 14218 | h_fun->nregs = DUK_RAW_READINC_U16_BE(p); |
| 14219 | h_fun->nargs = DUK_RAW_READINC_U16_BE(p); |
| 14220 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 14221 | h_fun->start_line = DUK_RAW_READINC_U32_BE(p); |
| 14222 | h_fun->end_line = DUK_RAW_READINC_U32_BE(p); |
| 14223 | #else |
| 14224 | p += 8; /* skip line info */ |
| 14225 | #endif |
| 14226 | |
| 14227 | /* duk_hcompfunc flags; quite version specific */ |
| 14228 | tmp32 = DUK_RAW_READINC_U32_BE(p); |
| 14229 | DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */ |
| 14230 | |
| 14231 | /* standard prototype (no need to set here, already set) */ |
| 14232 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 14233 | #if 0 |
| 14234 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 14235 | #endif |
| 14236 | |
| 14237 | /* assert just a few critical flags */ |
| 14238 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT); |
| 14239 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj)); |
| 14240 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj)); |
| 14241 | DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj)); |
| 14242 | DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&h_fun->obj)); |
| 14243 | DUK_ASSERT(!DUK_HOBJECT_IS_PROXY(&h_fun->obj)); |
| 14244 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj)); |
| 14245 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj)); |
| 14246 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj)); |
| 14247 | |
| 14248 | /* Create function 'data' buffer but don't attach it yet. */ |
| 14249 | fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size); |
| 14250 | DUK_ASSERT(fun_data != NULL); |
| 14251 | |
| 14252 | /* Load bytecode instructions. */ |
| 14253 | DUK_ASSERT(sizeof(duk_instr_t) == 4); |
| 14254 | DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t)); |
| 14255 | #if defined(DUK_USE_INTEGER_BE) |
| 14256 | q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; |
| 14257 | duk_memcpy((void *) q, |
| 14258 | (const void *) p, |
| 14259 | sizeof(duk_instr_t) * count_instr); |
| 14260 | p += sizeof(duk_instr_t) * count_instr; |
| 14261 | #else |
| 14262 | q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs; |
| 14263 | for (n = count_instr; n > 0; n--) { |
| 14264 | *((duk_instr_t *) (void *) q) = DUK_RAW_READINC_U32_BE(p); |
| 14265 | q += sizeof(duk_instr_t); |
| 14266 | } |
| 14267 | #endif |
| 14268 | |
| 14269 | /* Load constants onto value stack but don't yet copy to buffer. */ |
| 14270 | for (n = count_const; n > 0; n--) { |
| 14271 | DUK__ASSERT_LEFT(1); |
| 14272 | const_type = DUK_RAW_READINC_U8(p); |
| 14273 | switch (const_type) { |
| 14274 | case DUK__SER_STRING: { |
| 14275 | p = duk__load_string_raw(thr, p); |
| 14276 | break; |
| 14277 | } |
| 14278 | case DUK__SER_NUMBER: { |
| 14279 | /* Important to do a fastint check so that constants are |
| 14280 | * properly read back as fastints. |
| 14281 | */ |
| 14282 | duk_tval tv_tmp; |
| 14283 | duk_double_t val; |
| 14284 | DUK__ASSERT_LEFT(8); |
| 14285 | val = DUK_RAW_READINC_DOUBLE_BE(p); |
| 14286 | DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val); |
| 14287 | duk_push_tval(thr, &tv_tmp); |
| 14288 | break; |
| 14289 | } |
| 14290 | default: { |
| 14291 | goto format_error; |
| 14292 | } |
| 14293 | } |
| 14294 | } |
| 14295 | |
| 14296 | /* Load inner functions to value stack, but don't yet copy to buffer. */ |
| 14297 | for (n = count_funcs; n > 0; n--) { |
| 14298 | p = duk__load_func(thr, p, p_end); |
| 14299 | if (p == NULL) { |
| 14300 | goto format_error; |
| 14301 | } |
| 14302 | } |
| 14303 | |
| 14304 | /* With constants and inner functions on value stack, we can now |
| 14305 | * atomically finish the function 'data' buffer, bump refcounts, |
| 14306 | * etc. |
| 14307 | * |
| 14308 | * Here we take advantage of the value stack being just a duk_tval |
| 14309 | * array: we can just memcpy() the constants as long as we incref |
| 14310 | * them afterwards. |
| 14311 | */ |
| 14312 | |
| 14313 | h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1); |
| 14314 | DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data)); |
| 14315 | DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data); |
| 14316 | DUK_HBUFFER_INCREF(thr, h_data); |
| 14317 | |
| 14318 | tv1 = duk_get_tval(thr, idx_base + 2); /* may be NULL if no constants or inner funcs */ |
| 14319 | DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL); |
| 14320 | |
| 14321 | q = fun_data; |
| 14322 | duk_memcpy_unsafe((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const); |
| 14323 | for (n = count_const; n > 0; n--) { |
| 14324 | DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */ |
| 14325 | q += sizeof(duk_tval); |
| 14326 | } |
| 14327 | tv1 += count_const; |
| 14328 | |
| 14329 | DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q); |
| 14330 | for (n = count_funcs; n > 0; n--) { |
| 14331 | duk_hobject *h_obj; |
| 14332 | |
| 14333 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1)); |
| 14334 | h_obj = DUK_TVAL_GET_OBJECT(tv1); |
| 14335 | DUK_ASSERT(h_obj != NULL); |
| 14336 | tv1++; |
| 14337 | DUK_HOBJECT_INCREF(thr, h_obj); |
| 14338 | |
| 14339 | *((duk_hobject **) (void *) q) = h_obj; |
| 14340 | q += sizeof(duk_hobject *); |
| 14341 | } |
| 14342 | |
| 14343 | DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q); |
| 14344 | |
| 14345 | /* The function object is now reachable and refcounts are fine, |
| 14346 | * so we can pop off all the temporaries. |
| 14347 | */ |
| 14348 | DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT" , duk_get_tval(thr, idx_base))); |
| 14349 | duk_set_top(thr, idx_base + 1); |
| 14350 | |
| 14351 | /* Setup function properties. */ |
| 14352 | tmp32 = DUK_RAW_READINC_U32_BE(p); |
| 14353 | duk_push_u32(thr, tmp32); |
| 14354 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); |
| 14355 | |
| 14356 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 14357 | p = duk__load_string_raw(thr, p); /* -> [ func funcname ] */ |
| 14358 | func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 14359 | DUK_ASSERT(func_env != NULL); |
| 14360 | need_pop = 0; |
| 14361 | if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) { |
| 14362 | /* Original function instance/template had NAMEBINDING. |
| 14363 | * Must create a lexical environment on loading to allow |
| 14364 | * recursive functions like 'function foo() { foo(); }'. |
| 14365 | */ |
| 14366 | duk_hdecenv *new_env; |
| 14367 | |
| 14368 | new_env = duk_hdecenv_alloc(thr, |
| 14369 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 14370 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); |
| 14371 | DUK_ASSERT(new_env != NULL); |
| 14372 | DUK_ASSERT(new_env->thread == NULL); /* Closed. */ |
| 14373 | DUK_ASSERT(new_env->varmap == NULL); |
| 14374 | DUK_ASSERT(new_env->regbase_byteoff == 0); |
| 14375 | DUK_HDECENV_ASSERT_VALID(new_env); |
| 14376 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); |
| 14377 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env); |
| 14378 | DUK_HOBJECT_INCREF(thr, func_env); |
| 14379 | |
| 14380 | func_env = (duk_hobject *) new_env; |
| 14381 | |
| 14382 | duk_push_hobject(thr, (duk_hobject *) new_env); |
| 14383 | |
| 14384 | duk_dup_m2(thr); /* -> [ func funcname env funcname ] */ |
| 14385 | duk_dup(thr, idx_base); /* -> [ func funcname env funcname func ] */ |
| 14386 | duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */ |
| 14387 | |
| 14388 | need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */ |
| 14389 | } |
| 14390 | DUK_ASSERT(func_env != NULL); |
| 14391 | DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env); |
| 14392 | DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env); |
| 14393 | DUK_HOBJECT_INCREF(thr, func_env); |
| 14394 | DUK_HOBJECT_INCREF(thr, func_env); |
| 14395 | if (need_pop) { |
| 14396 | duk_pop(thr); |
| 14397 | } |
| 14398 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); |
| 14399 | #endif /* DUK_USE_FUNC_NAME_PROPERTY */ |
| 14400 | |
| 14401 | #if defined(DUK_USE_FUNC_FILENAME_PROPERTY) |
| 14402 | p = duk__load_string_raw(thr, p); |
| 14403 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C); |
| 14404 | #endif /* DUK_USE_FUNC_FILENAME_PROPERTY */ |
| 14405 | |
| 14406 | if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) { |
| 14407 | /* Restore empty external .prototype only for constructable |
| 14408 | * functions. The prototype object should inherit from |
| 14409 | * Object.prototype. |
| 14410 | */ |
| 14411 | duk_push_object(thr); |
| 14412 | DUK_ASSERT(!duk_is_bare_object(thr, -1)); |
| 14413 | duk_dup_m2(thr); |
| 14414 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */ |
| 14415 | duk_compact_m1(thr); |
| 14416 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); |
| 14417 | } |
| 14418 | |
| 14419 | #if defined(DUK_USE_PC2LINE) |
| 14420 | p = duk__load_buffer_raw(thr, p); |
| 14421 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC); |
| 14422 | #endif /* DUK_USE_PC2LINE */ |
| 14423 | |
| 14424 | duk_push_bare_object(thr); /* _Varmap */ |
| 14425 | for (;;) { |
| 14426 | /* XXX: awkward */ |
| 14427 | p = duk__load_string_raw(thr, p); |
| 14428 | if (duk_get_length(thr, -1) == 0) { |
| 14429 | duk_pop(thr); |
| 14430 | break; |
| 14431 | } |
| 14432 | tmp32 = DUK_RAW_READINC_U32_BE(p); |
| 14433 | duk_push_u32(thr, tmp32); |
| 14434 | duk_put_prop(thr, -3); |
| 14435 | } |
| 14436 | duk_compact_m1(thr); |
| 14437 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); |
| 14438 | |
| 14439 | /* _Formals may have been missing in the original function, which is |
| 14440 | * handled using a marker length. |
| 14441 | */ |
| 14442 | arr_limit = DUK_RAW_READINC_U32_BE(p); |
| 14443 | if (arr_limit != DUK__NO_FORMALS) { |
| 14444 | duk_push_bare_array(thr); /* _Formals */ |
| 14445 | for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) { |
| 14446 | p = duk__load_string_raw(thr, p); |
| 14447 | duk_put_prop_index(thr, -2, arr_idx); |
| 14448 | } |
| 14449 | duk_compact_m1(thr); |
| 14450 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); |
| 14451 | } else { |
| 14452 | DUK_DD(DUK_DDPRINT("no _Formals in dumped function" )); |
| 14453 | } |
| 14454 | |
| 14455 | /* Return with final function pushed on stack top. */ |
| 14456 | DUK_DD(DUK_DDPRINT("final loaded function: %!iT" , duk_get_tval(thr, -1))); |
| 14457 | DUK_ASSERT_TOP(thr, idx_base + 1); |
| 14458 | return p; |
| 14459 | |
| 14460 | format_error: |
| 14461 | return NULL; |
| 14462 | } |
| 14463 | |
| 14464 | DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) { |
| 14465 | duk_hcompfunc *func; |
| 14466 | duk_bufwriter_ctx bw_ctx_alloc; |
| 14467 | duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc; |
| 14468 | duk_uint8_t *p; |
| 14469 | |
| 14470 | DUK_ASSERT_API_ENTRY(thr); |
| 14471 | |
| 14472 | /* Bound functions don't have all properties so we'd either need to |
| 14473 | * lookup the non-bound target function or reject bound functions. |
| 14474 | * For now, bound functions are rejected with TypeError. |
| 14475 | */ |
| 14476 | func = duk_require_hcompfunc(thr, -1); |
| 14477 | DUK_ASSERT(func != NULL); |
| 14478 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj)); |
| 14479 | |
| 14480 | /* Estimating the result size beforehand would be costly, so |
| 14481 | * start with a reasonable size and extend as needed. |
| 14482 | */ |
| 14483 | DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC); |
| 14484 | p = DUK_BW_GET_PTR(thr, bw_ctx); |
| 14485 | *p++ = DUK__SER_MARKER; |
| 14486 | p = duk__dump_func(thr, func, bw_ctx, p); |
| 14487 | DUK_BW_SET_PTR(thr, bw_ctx, p); |
| 14488 | DUK_BW_COMPACT(thr, bw_ctx); |
| 14489 | |
| 14490 | DUK_DD(DUK_DDPRINT("serialized result: %!T" , duk_get_tval(thr, -1))); |
| 14491 | |
| 14492 | duk_remove_m2(thr); /* [ ... func buf ] -> [ ... buf ] */ |
| 14493 | } |
| 14494 | |
| 14495 | DUK_EXTERNAL void duk_load_function(duk_hthread *thr) { |
| 14496 | const duk_uint8_t *p_buf, *p, *p_end; |
| 14497 | duk_size_t sz; |
| 14498 | |
| 14499 | DUK_ASSERT_API_ENTRY(thr); |
| 14500 | |
| 14501 | p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz); |
| 14502 | DUK_ASSERT(p_buf != NULL); |
| 14503 | |
| 14504 | /* The caller is responsible for being sure that bytecode being loaded |
| 14505 | * is valid and trusted. Invalid bytecode can cause memory unsafe |
| 14506 | * behavior directly during loading or later during bytecode execution |
| 14507 | * (instruction validation would be quite complex to implement). |
| 14508 | * |
| 14509 | * This signature check is the only sanity check for detecting |
| 14510 | * accidental invalid inputs. The initial byte ensures no ordinary |
| 14511 | * string or Symbol will be accepted by accident. |
| 14512 | */ |
| 14513 | p = p_buf; |
| 14514 | p_end = p_buf + sz; |
| 14515 | if (sz < 1 || p[0] != DUK__SER_MARKER) { |
| 14516 | goto format_error; |
| 14517 | } |
| 14518 | p++; |
| 14519 | |
| 14520 | p = duk__load_func(thr, p, p_end); |
| 14521 | if (p == NULL) { |
| 14522 | goto format_error; |
| 14523 | } |
| 14524 | |
| 14525 | duk_remove_m2(thr); /* [ ... buf func ] -> [ ... func ] */ |
| 14526 | return; |
| 14527 | |
| 14528 | format_error: |
| 14529 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE); |
| 14530 | DUK_WO_NORETURN(return;); |
| 14531 | } |
| 14532 | |
| 14533 | #else /* DUK_USE_BYTECODE_DUMP_SUPPORT */ |
| 14534 | |
| 14535 | DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) { |
| 14536 | DUK_ASSERT_API_ENTRY(thr); |
| 14537 | DUK_ERROR_UNSUPPORTED(thr); |
| 14538 | DUK_WO_NORETURN(return;); |
| 14539 | } |
| 14540 | |
| 14541 | DUK_EXTERNAL void duk_load_function(duk_hthread *thr) { |
| 14542 | DUK_ASSERT_API_ENTRY(thr); |
| 14543 | DUK_ERROR_UNSUPPORTED(thr); |
| 14544 | DUK_WO_NORETURN(return;); |
| 14545 | } |
| 14546 | |
| 14547 | #endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */ |
| 14548 | |
| 14549 | /* automatic undefs */ |
| 14550 | #undef DUK__ASSERT_LEFT |
| 14551 | #undef DUK__BYTECODE_INITIAL_ALLOC |
| 14552 | #undef DUK__NO_FORMALS |
| 14553 | #undef DUK__SER_MARKER |
| 14554 | #undef DUK__SER_NUMBER |
| 14555 | #undef DUK__SER_STRING |
| 14556 | #line 1 "duk_api_call.c" |
| 14557 | /* |
| 14558 | * Calls. |
| 14559 | * |
| 14560 | * Protected variants should avoid ever throwing an error. Must be careful |
| 14561 | * to catch errors related to value stack manipulation and property lookup, |
| 14562 | * not just the call itself. |
| 14563 | * |
| 14564 | * The only exception is when arguments are insane, e.g. nargs/nrets are out |
| 14565 | * of bounds; in such cases an error is thrown for two reasons. First, we |
| 14566 | * can't always respect the value stack input/output guarantees in such cases |
| 14567 | * so the caller would end up with the value stack in an unexpected state. |
| 14568 | * Second, an attempt to create an error might itself fail (although this |
| 14569 | * could be avoided by pushing a preallocated object/string or a primitive |
| 14570 | * value). |
| 14571 | */ |
| 14572 | |
| 14573 | /* #include duk_internal.h -> already included */ |
| 14574 | |
| 14575 | /* |
| 14576 | * Helpers |
| 14577 | */ |
| 14578 | |
| 14579 | struct duk__pcall_prop_args { |
| 14580 | duk_idx_t obj_idx; |
| 14581 | duk_idx_t nargs; |
| 14582 | duk_small_uint_t call_flags; |
| 14583 | }; |
| 14584 | typedef struct duk__pcall_prop_args duk__pcall_prop_args; |
| 14585 | |
| 14586 | struct duk__pcall_method_args { |
| 14587 | duk_idx_t nargs; |
| 14588 | duk_small_uint_t call_flags; |
| 14589 | }; |
| 14590 | typedef struct duk__pcall_method_args duk__pcall_method_args; |
| 14591 | |
| 14592 | struct duk__pcall_args { |
| 14593 | duk_idx_t nargs; |
| 14594 | duk_small_uint_t call_flags; |
| 14595 | }; |
| 14596 | typedef struct duk__pcall_args duk__pcall_args; |
| 14597 | |
| 14598 | /* Compute and validate idx_func for a certain 'nargs' and 'other' |
| 14599 | * parameter count (1 or 2, depending on whether 'this' binding is |
| 14600 | * present). |
| 14601 | */ |
| 14602 | DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) { |
| 14603 | duk_idx_t idx_func; |
| 14604 | |
| 14605 | /* XXX: byte arithmetic? */ |
| 14606 | |
| 14607 | DUK_ASSERT(other >= 0); |
| 14608 | |
| 14609 | idx_func = duk_get_top(thr) - nargs - other; |
| 14610 | if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */ |
| 14611 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 14612 | DUK_WO_NORETURN(return 0;); |
| 14613 | } |
| 14614 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 14615 | return idx_func; |
| 14616 | } |
| 14617 | |
| 14618 | /* Compute idx_func, assume index will be valid. This is a valid assumption |
| 14619 | * for protected calls: nargs < 0 is checked explicitly and duk_safe_call() |
| 14620 | * validates the argument count. |
| 14621 | */ |
| 14622 | DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) { |
| 14623 | duk_idx_t idx_func; |
| 14624 | |
| 14625 | /* XXX: byte arithmetic? */ |
| 14626 | |
| 14627 | DUK_ASSERT(nargs >= 0); |
| 14628 | DUK_ASSERT(other >= 0); |
| 14629 | |
| 14630 | idx_func = duk_get_top(thr) - nargs - other; |
| 14631 | DUK_ASSERT(idx_func >= 0); |
| 14632 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 14633 | return idx_func; |
| 14634 | } |
| 14635 | |
| 14636 | /* Prepare value stack for a method call through an object property. |
| 14637 | * May currently throw an error e.g. when getting the property. |
| 14638 | */ |
| 14639 | DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) { |
| 14640 | DUK_CTX_ASSERT_VALID(thr); |
| 14641 | DUK_ASSERT(nargs >= 0); |
| 14642 | |
| 14643 | DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld" , |
| 14644 | (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr))); |
| 14645 | |
| 14646 | /* [... key arg1 ... argN] */ |
| 14647 | |
| 14648 | /* duplicate key */ |
| 14649 | duk_dup(thr, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */ |
| 14650 | (void) duk_get_prop(thr, normalized_obj_idx); |
| 14651 | |
| 14652 | DUK_DDD(DUK_DDDPRINT("func: %!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 14653 | |
| 14654 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 14655 | if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) { |
| 14656 | duk_tval *tv_base; |
| 14657 | duk_tval *tv_key; |
| 14658 | |
| 14659 | /* tv_targ is passed on stack top (at index -1). */ |
| 14660 | tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx); |
| 14661 | tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2); |
| 14662 | DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top); |
| 14663 | DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top); |
| 14664 | |
| 14665 | duk_call_setup_propcall_error(thr, tv_base, tv_key); |
| 14666 | } |
| 14667 | #endif |
| 14668 | |
| 14669 | /* [... key arg1 ... argN func] */ |
| 14670 | |
| 14671 | duk_replace(thr, -nargs - 2); |
| 14672 | |
| 14673 | /* [... func arg1 ... argN] */ |
| 14674 | |
| 14675 | duk_dup(thr, normalized_obj_idx); |
| 14676 | duk_insert(thr, -nargs - 1); |
| 14677 | |
| 14678 | /* [... func this arg1 ... argN] */ |
| 14679 | } |
| 14680 | |
| 14681 | DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) { |
| 14682 | duk_small_uint_t call_flags; |
| 14683 | duk_idx_t idx_func; |
| 14684 | |
| 14685 | DUK_ASSERT_API_ENTRY(thr); |
| 14686 | |
| 14687 | idx_func = duk__call_get_idx_func(thr, nargs, 1); |
| 14688 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 14689 | |
| 14690 | duk_insert_undefined(thr, idx_func + 1); |
| 14691 | |
| 14692 | call_flags = 0; /* not protected, respect reclimit, not constructor */ |
| 14693 | duk_handle_call_unprotected(thr, idx_func, call_flags); |
| 14694 | } |
| 14695 | |
| 14696 | DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) { |
| 14697 | duk_small_uint_t call_flags; |
| 14698 | duk_idx_t idx_func; |
| 14699 | |
| 14700 | DUK_ASSERT_API_ENTRY(thr); |
| 14701 | |
| 14702 | idx_func = duk__call_get_idx_func(thr, nargs, 2); |
| 14703 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 14704 | |
| 14705 | call_flags = 0; /* not protected, respect reclimit, not constructor */ |
| 14706 | duk_handle_call_unprotected(thr, idx_func, call_flags); |
| 14707 | } |
| 14708 | |
| 14709 | DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) { |
| 14710 | /* |
| 14711 | * XXX: if duk_handle_call() took values through indices, this could be |
| 14712 | * made much more sensible. However, duk_handle_call() needs to fudge |
| 14713 | * the 'this' and 'func' values to handle bound functions, which is now |
| 14714 | * done "in-place", so this is not a trivial change. |
| 14715 | */ |
| 14716 | |
| 14717 | DUK_ASSERT_API_ENTRY(thr); |
| 14718 | |
| 14719 | obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */ |
| 14720 | if (DUK_UNLIKELY(nargs < 0)) { |
| 14721 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 14722 | DUK_WO_NORETURN(return;); |
| 14723 | } |
| 14724 | |
| 14725 | duk__call_prop_prep_stack(thr, obj_idx, nargs); |
| 14726 | |
| 14727 | duk_call_method(thr, nargs); |
| 14728 | } |
| 14729 | |
| 14730 | DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) { |
| 14731 | duk__pcall_args *args; |
| 14732 | duk_idx_t idx_func; |
| 14733 | duk_int_t ret; |
| 14734 | |
| 14735 | DUK_CTX_ASSERT_VALID(thr); |
| 14736 | DUK_ASSERT(udata != NULL); |
| 14737 | |
| 14738 | args = (duk__pcall_args *) udata; |
| 14739 | idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1); |
| 14740 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 14741 | |
| 14742 | duk_insert_undefined(thr, idx_func + 1); |
| 14743 | |
| 14744 | ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags); |
| 14745 | DUK_ASSERT(ret == 0); |
| 14746 | DUK_UNREF(ret); |
| 14747 | |
| 14748 | return 1; |
| 14749 | } |
| 14750 | |
| 14751 | DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) { |
| 14752 | duk__pcall_args args; |
| 14753 | |
| 14754 | DUK_ASSERT_API_ENTRY(thr); |
| 14755 | |
| 14756 | args.nargs = nargs; |
| 14757 | if (DUK_UNLIKELY(nargs < 0)) { |
| 14758 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 14759 | DUK_WO_NORETURN(return DUK_EXEC_ERROR;); |
| 14760 | } |
| 14761 | args.call_flags = 0; |
| 14762 | |
| 14763 | return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); |
| 14764 | } |
| 14765 | |
| 14766 | DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) { |
| 14767 | duk__pcall_method_args *args; |
| 14768 | duk_idx_t idx_func; |
| 14769 | duk_int_t ret; |
| 14770 | |
| 14771 | DUK_CTX_ASSERT_VALID(thr); |
| 14772 | DUK_ASSERT(udata != NULL); |
| 14773 | |
| 14774 | args = (duk__pcall_method_args *) udata; |
| 14775 | |
| 14776 | idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2); |
| 14777 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 14778 | |
| 14779 | ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags); |
| 14780 | DUK_ASSERT(ret == 0); |
| 14781 | DUK_UNREF(ret); |
| 14782 | |
| 14783 | return 1; |
| 14784 | } |
| 14785 | |
| 14786 | DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) { |
| 14787 | duk__pcall_method_args args; |
| 14788 | |
| 14789 | DUK_ASSERT_API_ENTRY(thr); |
| 14790 | |
| 14791 | args.nargs = nargs; |
| 14792 | if (DUK_UNLIKELY(nargs < 0)) { |
| 14793 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 14794 | DUK_WO_NORETURN(return DUK_EXEC_ERROR;); |
| 14795 | } |
| 14796 | args.call_flags = call_flags; |
| 14797 | |
| 14798 | return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/); |
| 14799 | } |
| 14800 | |
| 14801 | DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) { |
| 14802 | DUK_ASSERT_API_ENTRY(thr); |
| 14803 | |
| 14804 | return duk_pcall_method_flags(thr, nargs, 0); |
| 14805 | } |
| 14806 | |
| 14807 | DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) { |
| 14808 | duk__pcall_prop_args *args; |
| 14809 | duk_idx_t obj_idx; |
| 14810 | duk_int_t ret; |
| 14811 | |
| 14812 | DUK_CTX_ASSERT_VALID(thr); |
| 14813 | DUK_ASSERT(udata != NULL); |
| 14814 | |
| 14815 | args = (duk__pcall_prop_args *) udata; |
| 14816 | |
| 14817 | obj_idx = duk_require_normalize_index(thr, args->obj_idx); /* make absolute */ |
| 14818 | duk__call_prop_prep_stack(thr, obj_idx, args->nargs); |
| 14819 | |
| 14820 | ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags); |
| 14821 | DUK_ASSERT(ret == 0); |
| 14822 | DUK_UNREF(ret); |
| 14823 | return 1; |
| 14824 | } |
| 14825 | |
| 14826 | DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) { |
| 14827 | duk__pcall_prop_args args; |
| 14828 | |
| 14829 | DUK_ASSERT_API_ENTRY(thr); |
| 14830 | |
| 14831 | args.obj_idx = obj_idx; |
| 14832 | args.nargs = nargs; |
| 14833 | if (DUK_UNLIKELY(nargs < 0)) { |
| 14834 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 14835 | DUK_WO_NORETURN(return DUK_EXEC_ERROR;); |
| 14836 | } |
| 14837 | args.call_flags = 0; |
| 14838 | |
| 14839 | return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); |
| 14840 | } |
| 14841 | |
| 14842 | DUK_EXTERNAL duk_int_t duk_safe_call(duk_hthread *thr, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) { |
| 14843 | duk_int_t rc; |
| 14844 | |
| 14845 | DUK_ASSERT_API_ENTRY(thr); |
| 14846 | |
| 14847 | /* nargs condition; fail if: top - bottom < nargs |
| 14848 | * <=> top < bottom + nargs |
| 14849 | * nrets condition; fail if: end - (top - nargs) < nrets |
| 14850 | * <=> end - top + nargs < nrets |
| 14851 | * <=> end + nargs < top + nrets |
| 14852 | */ |
| 14853 | /* XXX: check for any reserve? */ |
| 14854 | |
| 14855 | if (DUK_UNLIKELY((nargs | nrets) < 0 || /* nargs < 0 || nrets < 0; OR sign bits */ |
| 14856 | thr->valstack_top < thr->valstack_bottom + nargs || /* nargs too large compared to top */ |
| 14857 | thr->valstack_end + nargs < thr->valstack_top + nrets)) { /* nrets too large compared to reserve */ |
| 14858 | DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: " |
| 14859 | "nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), " |
| 14860 | "end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)" , |
| 14861 | (long) nargs, |
| 14862 | (long) nrets, |
| 14863 | (long) (thr->valstack_top - thr->valstack), |
| 14864 | (long) (thr->valstack_bottom - thr->valstack), |
| 14865 | (long) nargs, |
| 14866 | (long) (thr->valstack_end - thr->valstack), |
| 14867 | (long) nargs, |
| 14868 | (long) (thr->valstack_top - thr->valstack), |
| 14869 | (long) nrets)); |
| 14870 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 14871 | DUK_WO_NORETURN(return DUK_EXEC_ERROR;); |
| 14872 | } |
| 14873 | |
| 14874 | rc = duk_handle_safe_call(thr, /* thread */ |
| 14875 | func, /* func */ |
| 14876 | udata, /* udata */ |
| 14877 | nargs, /* num_stack_args */ |
| 14878 | nrets); /* num_stack_res */ |
| 14879 | |
| 14880 | return rc; |
| 14881 | } |
| 14882 | |
| 14883 | DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) { |
| 14884 | duk_idx_t idx_func; |
| 14885 | |
| 14886 | DUK_ASSERT_API_ENTRY(thr); |
| 14887 | |
| 14888 | idx_func = duk__call_get_idx_func(thr, nargs, 1); |
| 14889 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 14890 | |
| 14891 | duk_push_object(thr); /* default instance; internal proto updated by call handling */ |
| 14892 | duk_insert(thr, idx_func + 1); |
| 14893 | |
| 14894 | duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT); |
| 14895 | } |
| 14896 | |
| 14897 | DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) { |
| 14898 | duk_idx_t nargs; |
| 14899 | |
| 14900 | DUK_ASSERT(udata != NULL); |
| 14901 | nargs = *((duk_idx_t *) udata); |
| 14902 | |
| 14903 | duk_new(thr, nargs); |
| 14904 | return 1; |
| 14905 | } |
| 14906 | |
| 14907 | DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) { |
| 14908 | duk_int_t rc; |
| 14909 | |
| 14910 | DUK_ASSERT_API_ENTRY(thr); |
| 14911 | |
| 14912 | /* For now, just use duk_safe_call() to wrap duk_new(). We can't |
| 14913 | * simply use a protected duk_handle_call() because pushing the |
| 14914 | * default instance might throw. |
| 14915 | */ |
| 14916 | |
| 14917 | if (DUK_UNLIKELY(nargs < 0)) { |
| 14918 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 14919 | DUK_WO_NORETURN(return DUK_EXEC_ERROR;); |
| 14920 | } |
| 14921 | |
| 14922 | rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); |
| 14923 | return rc; |
| 14924 | } |
| 14925 | |
| 14926 | DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) { |
| 14927 | duk_activation *act; |
| 14928 | |
| 14929 | DUK_ASSERT_API_ENTRY(thr); |
| 14930 | |
| 14931 | act = thr->callstack_curr; |
| 14932 | if (act != NULL) { |
| 14933 | return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); |
| 14934 | } |
| 14935 | return 0; |
| 14936 | } |
| 14937 | |
| 14938 | DUK_EXTERNAL void duk_require_constructor_call(duk_hthread *thr) { |
| 14939 | DUK_ASSERT_API_ENTRY(thr); |
| 14940 | |
| 14941 | if (!duk_is_constructor_call(thr)) { |
| 14942 | DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY); |
| 14943 | DUK_WO_NORETURN(return;); |
| 14944 | } |
| 14945 | } |
| 14946 | |
| 14947 | DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) { |
| 14948 | duk_activation *act; |
| 14949 | |
| 14950 | /* For user code this could just return 1 (strict) always |
| 14951 | * because all Duktape/C functions are considered strict, |
| 14952 | * and strict is also the default when nothing is running. |
| 14953 | * However, Duktape may call this function internally when |
| 14954 | * the current activation is an ECMAScript function, so |
| 14955 | * this cannot be replaced by a 'return 1' without fixing |
| 14956 | * the internal call sites. |
| 14957 | */ |
| 14958 | |
| 14959 | DUK_ASSERT_API_ENTRY(thr); |
| 14960 | |
| 14961 | act = thr->callstack_curr; |
| 14962 | if (act != NULL) { |
| 14963 | return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0); |
| 14964 | } else { |
| 14965 | /* Strict by default. */ |
| 14966 | return 1; |
| 14967 | } |
| 14968 | } |
| 14969 | |
| 14970 | /* |
| 14971 | * Duktape/C function magic |
| 14972 | */ |
| 14973 | |
| 14974 | DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) { |
| 14975 | duk_activation *act; |
| 14976 | duk_hobject *func; |
| 14977 | |
| 14978 | DUK_ASSERT_API_ENTRY(thr); |
| 14979 | |
| 14980 | act = thr->callstack_curr; |
| 14981 | if (act) { |
| 14982 | func = DUK_ACT_GET_FUNC(act); |
| 14983 | if (!func) { |
| 14984 | duk_tval *tv = &act->tv_func; |
| 14985 | duk_small_uint_t lf_flags; |
| 14986 | lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); |
| 14987 | return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); |
| 14988 | } |
| 14989 | DUK_ASSERT(func != NULL); |
| 14990 | |
| 14991 | if (DUK_HOBJECT_IS_NATFUNC(func)) { |
| 14992 | duk_hnatfunc *nf = (duk_hnatfunc *) func; |
| 14993 | return (duk_int_t) nf->magic; |
| 14994 | } |
| 14995 | } |
| 14996 | return 0; |
| 14997 | } |
| 14998 | |
| 14999 | DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) { |
| 15000 | duk_tval *tv; |
| 15001 | duk_hobject *h; |
| 15002 | |
| 15003 | DUK_ASSERT_API_ENTRY(thr); |
| 15004 | |
| 15005 | tv = duk_require_tval(thr, idx); |
| 15006 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 15007 | h = DUK_TVAL_GET_OBJECT(tv); |
| 15008 | DUK_ASSERT(h != NULL); |
| 15009 | if (!DUK_HOBJECT_HAS_NATFUNC(h)) { |
| 15010 | goto type_error; |
| 15011 | } |
| 15012 | return (duk_int_t) ((duk_hnatfunc *) h)->magic; |
| 15013 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { |
| 15014 | duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); |
| 15015 | return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); |
| 15016 | } |
| 15017 | |
| 15018 | /* fall through */ |
| 15019 | type_error: |
| 15020 | DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); |
| 15021 | DUK_WO_NORETURN(return 0;); |
| 15022 | } |
| 15023 | |
| 15024 | DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) { |
| 15025 | duk_hnatfunc *nf; |
| 15026 | |
| 15027 | DUK_ASSERT_API_ENTRY(thr); |
| 15028 | |
| 15029 | nf = duk_require_hnatfunc(thr, idx); |
| 15030 | DUK_ASSERT(nf != NULL); |
| 15031 | nf->magic = (duk_int16_t) magic; |
| 15032 | } |
| 15033 | |
| 15034 | /* |
| 15035 | * Misc helpers |
| 15036 | */ |
| 15037 | |
| 15038 | /* Resolve a bound function on value stack top to a non-bound target |
| 15039 | * (leave other values as is). |
| 15040 | */ |
| 15041 | DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) { |
| 15042 | duk_tval *tv; |
| 15043 | |
| 15044 | DUK_HTHREAD_ASSERT_VALID(thr); |
| 15045 | |
| 15046 | tv = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 15047 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 15048 | duk_hobject *h; |
| 15049 | |
| 15050 | h = DUK_TVAL_GET_OBJECT(tv); |
| 15051 | DUK_ASSERT(h != NULL); |
| 15052 | if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) { |
| 15053 | duk_push_tval(thr, &((duk_hboundfunc *) (void *) h)->target); |
| 15054 | duk_replace(thr, -2); |
| 15055 | #if 0 |
| 15056 | DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target); |
| 15057 | DUK_TVAL_INCREF(thr, tv); |
| 15058 | DUK_HOBJECT_DECREF_NORZ(thr, h); |
| 15059 | #endif |
| 15060 | /* Rely on Function.prototype.bind() on never creating a bound |
| 15061 | * function whose target is not proper. This is now safe |
| 15062 | * because the target is not even an internal property but a |
| 15063 | * struct member. |
| 15064 | */ |
| 15065 | DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1)); |
| 15066 | } |
| 15067 | } |
| 15068 | |
| 15069 | /* Lightfuncs cannot be bound but are always callable and |
| 15070 | * constructable. |
| 15071 | */ |
| 15072 | } |
| 15073 | #line 1 "duk_api_codec.c" |
| 15074 | /* |
| 15075 | * Encoding and decoding basic formats: hex, base64. |
| 15076 | * |
| 15077 | * These are in-place operations which may allow an optimized implementation. |
| 15078 | * |
| 15079 | * Base-64: https://tools.ietf.org/html/rfc4648#section-4 |
| 15080 | */ |
| 15081 | |
| 15082 | /* #include duk_internal.h -> already included */ |
| 15083 | |
| 15084 | /* |
| 15085 | * Misc helpers |
| 15086 | */ |
| 15087 | |
| 15088 | /* Shared handling for encode/decode argument. Fast path handling for |
| 15089 | * buffer and string values because they're the most common. In particular, |
| 15090 | * avoid creating a temporary string or buffer when possible. Return value |
| 15091 | * is guaranteed to be non-NULL, even for zero length input. |
| 15092 | */ |
| 15093 | DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { |
| 15094 | const void *def_ptr = (const void *) out_len; /* Any non-NULL pointer will do. */ |
| 15095 | const void *ptr; |
| 15096 | duk_bool_t isbuffer; |
| 15097 | |
| 15098 | DUK_ASSERT(out_len != NULL); |
| 15099 | DUK_ASSERT(def_ptr != NULL); |
| 15100 | DUK_ASSERT(duk_is_valid_index(thr, idx)); /* checked by caller */ |
| 15101 | |
| 15102 | ptr = (const void *) duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer); |
| 15103 | if (isbuffer) { |
| 15104 | DUK_ASSERT(ptr != NULL || *out_len == 0U); |
| 15105 | if (DUK_UNLIKELY(ptr == NULL)) { |
| 15106 | ptr = def_ptr; |
| 15107 | } |
| 15108 | DUK_ASSERT(ptr != NULL); |
| 15109 | } else { |
| 15110 | /* For strings a non-NULL pointer is always guaranteed because |
| 15111 | * at least a NUL will be present. |
| 15112 | */ |
| 15113 | ptr = (const void *) duk_to_lstring(thr, idx, out_len); |
| 15114 | DUK_ASSERT(ptr != NULL); |
| 15115 | } |
| 15116 | DUK_ASSERT(ptr != NULL); |
| 15117 | return (const duk_uint8_t *) ptr; |
| 15118 | } |
| 15119 | |
| 15120 | /* |
| 15121 | * Base64 |
| 15122 | */ |
| 15123 | |
| 15124 | #if defined(DUK_USE_BASE64_SUPPORT) |
| 15125 | /* Bytes emitted for number of padding characters in range [0,4]. */ |
| 15126 | DUK_LOCAL const duk_int8_t duk__base64_decode_nequal_step[5] = { |
| 15127 | 3, /* #### -> 24 bits, emit 3 bytes */ |
| 15128 | 2, /* ###= -> 18 bits, emit 2 bytes */ |
| 15129 | 1, /* ##== -> 12 bits, emit 1 byte */ |
| 15130 | -1, /* #=== -> 6 bits, error */ |
| 15131 | 0, /* ==== -> 0 bits, emit 0 bytes */ |
| 15132 | }; |
| 15133 | |
| 15134 | #if defined(DUK_USE_BASE64_FASTPATH) |
| 15135 | DUK_LOCAL const duk_uint8_t duk__base64_enctab_fast[64] = { |
| 15136 | 0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U, /* A...P */ |
| 15137 | 0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, 0x59U, 0x5aU, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, /* Q...f */ |
| 15138 | 0x67U, 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU, 0x6fU, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U, /* g...v */ |
| 15139 | 0x77U, 0x78U, 0x79U, 0x7aU, 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x2bU, 0x2fU /* w.../ */ |
| 15140 | }; |
| 15141 | #endif /* DUK_USE_BASE64_FASTPATH */ |
| 15142 | |
| 15143 | #if defined(DUK_USE_BASE64_FASTPATH) |
| 15144 | /* Decode table for one byte of input: |
| 15145 | * -1 = allowed whitespace |
| 15146 | * -2 = padding |
| 15147 | * -3 = error |
| 15148 | * 0...63 decoded bytes |
| 15149 | */ |
| 15150 | DUK_LOCAL const duk_int8_t duk__base64_dectab_fast[256] = { |
| 15151 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3, /* 0x00...0x0f */ |
| 15152 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x10...0x1f */ |
| 15153 | -1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 62, -3, -3, -3, 63, /* 0x20...0x2f */ |
| 15154 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -3, -3, -3, -2, -3, -3, /* 0x30...0x3f */ |
| 15155 | -3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */ |
| 15156 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -3, -3, -3, -3, -3, /* 0x50...0x5f */ |
| 15157 | -3, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */ |
| 15158 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -3, -3, -3, -3, -3, /* 0x70...0x7f */ |
| 15159 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x80...0x8f */ |
| 15160 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x90...0x9f */ |
| 15161 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xa0...0xaf */ |
| 15162 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xb0...0xbf */ |
| 15163 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xc0...0xcf */ |
| 15164 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xd0...0xdf */ |
| 15165 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xe0...0xef */ |
| 15166 | -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3 /* 0xf0...0xff */ |
| 15167 | }; |
| 15168 | #endif /* DUK_USE_BASE64_FASTPATH */ |
| 15169 | |
| 15170 | #if defined(DUK_USE_BASE64_FASTPATH) |
| 15171 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_3(const duk_uint8_t *src, duk_uint8_t *dst) { |
| 15172 | duk_uint_t t; |
| 15173 | |
| 15174 | t = (duk_uint_t) src[0]; |
| 15175 | t = (t << 8) + (duk_uint_t) src[1]; |
| 15176 | t = (t << 8) + (duk_uint_t) src[2]; |
| 15177 | |
| 15178 | dst[0] = duk__base64_enctab_fast[t >> 18]; |
| 15179 | dst[1] = duk__base64_enctab_fast[(t >> 12) & 0x3fU]; |
| 15180 | dst[2] = duk__base64_enctab_fast[(t >> 6) & 0x3fU]; |
| 15181 | dst[3] = duk__base64_enctab_fast[t & 0x3fU]; |
| 15182 | |
| 15183 | #if 0 |
| 15184 | /* Tested: not faster on x64, most likely due to aliasing between |
| 15185 | * output and input index computation. |
| 15186 | */ |
| 15187 | /* aaaaaabb bbbbcccc ccdddddd */ |
| 15188 | dst[0] = duk__base64_enctab_fast[(src[0] >> 2) & 0x3fU]; |
| 15189 | dst[1] = duk__base64_enctab_fast[((src[0] << 4) & 0x30U) | ((src[1] >> 4) & 0x0fU)]; |
| 15190 | dst[2] = duk__base64_enctab_fast[((src[1] << 2) & 0x3fU) | ((src[2] >> 6) & 0x03U)]; |
| 15191 | dst[3] = duk__base64_enctab_fast[src[2] & 0x3fU]; |
| 15192 | #endif |
| 15193 | } |
| 15194 | |
| 15195 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_2(const duk_uint8_t *src, duk_uint8_t *dst) { |
| 15196 | duk_uint_t t; |
| 15197 | |
| 15198 | t = (duk_uint_t) src[0]; |
| 15199 | t = (t << 8) + (duk_uint_t) src[1]; |
| 15200 | dst[0] = duk__base64_enctab_fast[t >> 10]; /* XXXXXX-- -------- */ |
| 15201 | dst[1] = duk__base64_enctab_fast[(t >> 4) & 0x3fU]; /* ------XX XXXX---- */ |
| 15202 | dst[2] = duk__base64_enctab_fast[(t << 2) & 0x3fU]; /* -------- ----XXXX */ |
| 15203 | dst[3] = DUK_ASC_EQUALS; |
| 15204 | } |
| 15205 | |
| 15206 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_1(const duk_uint8_t *src, duk_uint8_t *dst) { |
| 15207 | duk_uint_t t; |
| 15208 | |
| 15209 | t = (duk_uint_t) src[0]; |
| 15210 | dst[0] = duk__base64_enctab_fast[t >> 2]; /* XXXXXX-- */ |
| 15211 | dst[1] = duk__base64_enctab_fast[(t << 4) & 0x3fU]; /* ------XX */ |
| 15212 | dst[2] = DUK_ASC_EQUALS; |
| 15213 | dst[3] = DUK_ASC_EQUALS; |
| 15214 | } |
| 15215 | |
| 15216 | DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { |
| 15217 | duk_size_t n; |
| 15218 | const duk_uint8_t *p; |
| 15219 | duk_uint8_t *q; |
| 15220 | |
| 15221 | n = srclen; |
| 15222 | p = src; |
| 15223 | q = dst; |
| 15224 | |
| 15225 | if (n >= 16U) { |
| 15226 | /* Fast path, unrolled by 4, allows interleaving. Process |
| 15227 | * 12-byte input chunks which encode to 16-char output chunks. |
| 15228 | * Only enter when at least one block is emitted (avoids div+mul |
| 15229 | * for short inputs too). |
| 15230 | */ |
| 15231 | const duk_uint8_t *p_end_fast; |
| 15232 | |
| 15233 | p_end_fast = p + ((n / 12U) * 12U); |
| 15234 | DUK_ASSERT(p_end_fast >= p + 12); |
| 15235 | do { |
| 15236 | duk__base64_encode_fast_3(p, q); |
| 15237 | duk__base64_encode_fast_3(p + 3, q + 4); |
| 15238 | duk__base64_encode_fast_3(p + 6, q + 8); |
| 15239 | duk__base64_encode_fast_3(p + 9, q + 12); |
| 15240 | p += 12; |
| 15241 | q += 16; |
| 15242 | } while (DUK_LIKELY(p != p_end_fast)); |
| 15243 | |
| 15244 | DUK_ASSERT(src + srclen >= p); |
| 15245 | n = (duk_size_t) (src + srclen - p); |
| 15246 | DUK_ASSERT(n < 12U); |
| 15247 | } |
| 15248 | |
| 15249 | /* Remainder. */ |
| 15250 | while (n >= 3U) { |
| 15251 | duk__base64_encode_fast_3(p, q); |
| 15252 | p += 3; |
| 15253 | q += 4; |
| 15254 | n -= 3U; |
| 15255 | } |
| 15256 | DUK_ASSERT(n == 0U || n == 1U || n == 2U); |
| 15257 | if (n == 1U) { |
| 15258 | duk__base64_encode_fast_1(p, q); |
| 15259 | #if 0 /* Unnecessary. */ |
| 15260 | p += 1; |
| 15261 | q += 4; |
| 15262 | n -= 1U; |
| 15263 | #endif |
| 15264 | } else if (n == 2U) { |
| 15265 | duk__base64_encode_fast_2(p, q); |
| 15266 | #if 0 /* Unnecessary. */ |
| 15267 | p += 2; |
| 15268 | q += 4; |
| 15269 | n -= 2U; |
| 15270 | #endif |
| 15271 | } else { |
| 15272 | DUK_ASSERT(n == 0U); /* nothing to do */ |
| 15273 | ; |
| 15274 | } |
| 15275 | } |
| 15276 | #else /* DUK_USE_BASE64_FASTPATH */ |
| 15277 | DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) { |
| 15278 | duk_small_uint_t i, npad; |
| 15279 | duk_uint_t t, x, y; |
| 15280 | const duk_uint8_t *p; |
| 15281 | const duk_uint8_t *p_end; |
| 15282 | duk_uint8_t *q; |
| 15283 | |
| 15284 | p = src; |
| 15285 | p_end = src + srclen; |
| 15286 | q = dst; |
| 15287 | npad = 0U; |
| 15288 | |
| 15289 | while (p < p_end) { |
| 15290 | /* Read 3 bytes into 't', padded by zero. */ |
| 15291 | t = 0; |
| 15292 | for (i = 0; i < 3; i++) { |
| 15293 | t = t << 8; |
| 15294 | if (p < p_end) { |
| 15295 | t += (duk_uint_t) (*p++); |
| 15296 | } else { |
| 15297 | /* This only happens on the last loop and we're |
| 15298 | * guaranteed to exit on the next loop. |
| 15299 | */ |
| 15300 | npad++; |
| 15301 | } |
| 15302 | } |
| 15303 | DUK_ASSERT(npad <= 2U); |
| 15304 | |
| 15305 | /* Emit 4 encoded characters. If npad > 0, some of the |
| 15306 | * chars will be incorrect (zero bits) but we fix up the |
| 15307 | * padding after the loop. A straightforward 64-byte |
| 15308 | * lookup would be faster and cleaner, but this is shorter. |
| 15309 | */ |
| 15310 | for (i = 0; i < 4; i++) { |
| 15311 | x = ((t >> 18) & 0x3fU); |
| 15312 | t = t << 6; |
| 15313 | |
| 15314 | if (x <= 51U) { |
| 15315 | if (x <= 25) { |
| 15316 | y = x + DUK_ASC_UC_A; |
| 15317 | } else { |
| 15318 | y = x - 26 + DUK_ASC_LC_A; |
| 15319 | } |
| 15320 | } else { |
| 15321 | if (x <= 61U) { |
| 15322 | y = x - 52 + DUK_ASC_0; |
| 15323 | } else if (x == 62) { |
| 15324 | y = DUK_ASC_PLUS; |
| 15325 | } else { |
| 15326 | DUK_ASSERT(x == 63); |
| 15327 | y = DUK_ASC_SLASH; |
| 15328 | } |
| 15329 | } |
| 15330 | |
| 15331 | *q++ = (duk_uint8_t) y; |
| 15332 | } |
| 15333 | } |
| 15334 | |
| 15335 | /* Handle padding by rewriting 0-2 bogus characters at the end. |
| 15336 | * |
| 15337 | * Missing bytes npad base64 example |
| 15338 | * 0 0 #### |
| 15339 | * 1 1 ###= |
| 15340 | * 2 2 ##== |
| 15341 | */ |
| 15342 | DUK_ASSERT(npad <= 2U); |
| 15343 | while (npad > 0U) { |
| 15344 | *(q - npad) = DUK_ASC_EQUALS; |
| 15345 | npad--; |
| 15346 | } |
| 15347 | } |
| 15348 | #endif /* DUK_USE_BASE64_FASTPATH */ |
| 15349 | |
| 15350 | #if defined(DUK_USE_BASE64_FASTPATH) |
| 15351 | DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { |
| 15352 | duk_int_t x; |
| 15353 | duk_uint_t t; |
| 15354 | duk_small_uint_t n_equal; |
| 15355 | duk_int8_t step; |
| 15356 | const duk_uint8_t *p; |
| 15357 | const duk_uint8_t *p_end; |
| 15358 | const duk_uint8_t *p_end_safe; |
| 15359 | duk_uint8_t *q; |
| 15360 | |
| 15361 | DUK_ASSERT(src != NULL); /* Required by pointer arithmetic below, which fails for NULL. */ |
| 15362 | |
| 15363 | p = src; |
| 15364 | p_end = src + srclen; |
| 15365 | p_end_safe = p_end - 8; /* If 'src <= src_end_safe', safe to read 8 bytes. */ |
| 15366 | q = dst; |
| 15367 | |
| 15368 | /* Alternate between a fast path which processes clean groups with no |
| 15369 | * padding or whitespace, and a slow path which processes one arbitrary |
| 15370 | * group and then re-enters the fast path. This handles e.g. base64 |
| 15371 | * with newlines reasonably well because the majority of a line is in |
| 15372 | * the fast path. |
| 15373 | */ |
| 15374 | for (;;) { |
| 15375 | /* Fast path, on each loop handle two 4-char input groups. |
| 15376 | * If both are clean, emit 6 bytes and continue. If first |
| 15377 | * is clean, emit 3 bytes and drop out; otherwise emit |
| 15378 | * nothing and drop out. This approach could be extended to |
| 15379 | * more groups per loop, but for inputs with e.g. periodic |
| 15380 | * newlines (which are common) it might not be an improvement. |
| 15381 | */ |
| 15382 | while (DUK_LIKELY(p <= p_end_safe)) { |
| 15383 | duk_int_t t1, t2; |
| 15384 | |
| 15385 | /* The lookup byte is intentionally sign extended to |
| 15386 | * (at least) 32 bits and then ORed. This ensures |
| 15387 | * that is at least 1 byte is negative, the highest |
| 15388 | * bit of the accumulator will be set at the end and |
| 15389 | * we don't need to check every byte. |
| 15390 | * |
| 15391 | * Read all input bytes first before writing output |
| 15392 | * bytes to minimize aliasing. |
| 15393 | */ |
| 15394 | DUK_DDD(DUK_DDDPRINT("fast loop: p=%p, p_end_safe=%p, p_end=%p" , |
| 15395 | (const void *) p, (const void *) p_end_safe, (const void *) p_end)); |
| 15396 | |
| 15397 | t1 = (duk_int_t) duk__base64_dectab_fast[p[0]]; |
| 15398 | t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[1]]; |
| 15399 | t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[2]]; |
| 15400 | t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[3]]; |
| 15401 | |
| 15402 | t2 = (duk_int_t) duk__base64_dectab_fast[p[4]]; |
| 15403 | t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[5]]; |
| 15404 | t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[6]]; |
| 15405 | t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[7]]; |
| 15406 | |
| 15407 | q[0] = (duk_uint8_t) (((duk_uint_t) t1 >> 16) & 0xffU); |
| 15408 | q[1] = (duk_uint8_t) (((duk_uint_t) t1 >> 8) & 0xffU); |
| 15409 | q[2] = (duk_uint8_t) ((duk_uint_t) t1 & 0xffU); |
| 15410 | |
| 15411 | q[3] = (duk_uint8_t) (((duk_uint_t) t2 >> 16) & 0xffU); |
| 15412 | q[4] = (duk_uint8_t) (((duk_uint_t) t2 >> 8) & 0xffU); |
| 15413 | q[5] = (duk_uint8_t) ((duk_uint_t) t2 & 0xffU); |
| 15414 | |
| 15415 | /* Optimistic check using one branch. */ |
| 15416 | if (DUK_LIKELY((t1 | t2) >= 0)) { |
| 15417 | p += 8; |
| 15418 | q += 6; |
| 15419 | } else if (t1 >= 0) { |
| 15420 | DUK_DDD(DUK_DDDPRINT("fast loop first group was clean, second was not, process one slow path group" )); |
| 15421 | DUK_ASSERT(t2 < 0); |
| 15422 | p += 4; |
| 15423 | q += 3; |
| 15424 | break; |
| 15425 | } else { |
| 15426 | DUK_DDD(DUK_DDDPRINT("fast loop first group was not clean, second does not matter, process one slow path group" )); |
| 15427 | DUK_ASSERT(t1 < 0); |
| 15428 | break; |
| 15429 | } |
| 15430 | } /* fast path */ |
| 15431 | |
| 15432 | /* Slow path step 1: try to scan a 4-character encoded group, |
| 15433 | * end-of-input, or start-of-padding. We exit with: |
| 15434 | * 1. n_chars == 4: full group, no padding, no end-of-input. |
| 15435 | * 2. n_chars < 4: partial group (may also be 0), encountered |
| 15436 | * padding or end of input. |
| 15437 | * |
| 15438 | * The accumulator is initialized to 1; this allows us to detect |
| 15439 | * a full group by comparing >= 0x1000000 without an extra |
| 15440 | * counter variable. |
| 15441 | */ |
| 15442 | t = 1UL; |
| 15443 | for (;;) { |
| 15444 | DUK_DDD(DUK_DDDPRINT("slow loop: p=%p, p_end=%p, t=%lu" , |
| 15445 | (const void *) p, (const void *) p_end, (unsigned long) t)); |
| 15446 | |
| 15447 | if (DUK_LIKELY(p < p_end)) { |
| 15448 | x = duk__base64_dectab_fast[*p++]; |
| 15449 | if (DUK_LIKELY(x >= 0)) { |
| 15450 | DUK_ASSERT(x >= 0 && x <= 63); |
| 15451 | t = (t << 6) + (duk_uint_t) x; |
| 15452 | if (t >= 0x1000000UL) { |
| 15453 | break; |
| 15454 | } |
| 15455 | } else if (x == -1) { |
| 15456 | continue; /* allowed ascii whitespace */ |
| 15457 | } else if (x == -2) { |
| 15458 | p--; |
| 15459 | break; /* start of padding */ |
| 15460 | } else { |
| 15461 | DUK_ASSERT(x == -3); |
| 15462 | goto decode_error; |
| 15463 | } |
| 15464 | } else { |
| 15465 | break; /* end of input */ |
| 15466 | } |
| 15467 | } /* slow path step 1 */ |
| 15468 | |
| 15469 | /* Complete the padding by simulating pad characters, |
| 15470 | * regardless of actual input padding chars. |
| 15471 | */ |
| 15472 | n_equal = 0; |
| 15473 | while (t < 0x1000000UL) { |
| 15474 | t = (t << 6) + 0U; |
| 15475 | n_equal++; |
| 15476 | } |
| 15477 | |
| 15478 | /* Slow path step 2: deal with full/partial group, padding, |
| 15479 | * etc. Note that for num chars in [0,3] we intentionally emit |
| 15480 | * 3 bytes but don't step forward that much, buffer space is |
| 15481 | * guaranteed in setup. |
| 15482 | * |
| 15483 | * num chars: |
| 15484 | * 0 #### no output (= step 0) |
| 15485 | * 1 #=== reject, 6 bits of data |
| 15486 | * 2 ##== 12 bits of data, output 1 byte (= step 1) |
| 15487 | * 3 ###= 18 bits of data, output 2 bytes (= step 2) |
| 15488 | * 4 #### 24 bits of data, output 3 bytes (= step 3) |
| 15489 | */ |
| 15490 | q[0] = (duk_uint8_t) ((t >> 16) & 0xffU); |
| 15491 | q[1] = (duk_uint8_t) ((t >> 8) & 0xffU); |
| 15492 | q[2] = (duk_uint8_t) (t & 0xffU); |
| 15493 | |
| 15494 | DUK_ASSERT(n_equal <= 4); |
| 15495 | step = duk__base64_decode_nequal_step[n_equal]; |
| 15496 | if (DUK_UNLIKELY(step < 0)) { |
| 15497 | goto decode_error; |
| 15498 | } |
| 15499 | q += step; |
| 15500 | |
| 15501 | /* Slow path step 3: read and ignore padding and whitespace |
| 15502 | * until (a) next non-padding and non-whitespace character |
| 15503 | * after which we resume the fast path, or (b) end of input. |
| 15504 | * This allows us to accept missing, partial, full, and extra |
| 15505 | * padding cases uniformly. We also support concatenated |
| 15506 | * base-64 documents because we resume scanning afterwards. |
| 15507 | * |
| 15508 | * Note that to support concatenated documents well, the '=' |
| 15509 | * padding found inside the input must also allow for 'extra' |
| 15510 | * padding. For example, 'Zm===' decodes to 'f' and has one |
| 15511 | * extra padding char. So, 'Zm===Zm' should decode 'ff', even |
| 15512 | * though the standard break-up would be 'Zm==' + '=Zm' which |
| 15513 | * doesn't make sense. |
| 15514 | * |
| 15515 | * We also accept prepended padding like '==Zm9', because it |
| 15516 | * is equivalent to an empty document with extra padding ('==') |
| 15517 | * followed by a valid document. |
| 15518 | */ |
| 15519 | |
| 15520 | for (;;) { |
| 15521 | if (DUK_UNLIKELY(p >= p_end)) { |
| 15522 | goto done; |
| 15523 | } |
| 15524 | x = duk__base64_dectab_fast[*p++]; |
| 15525 | if (x == -1 || x == -2) { |
| 15526 | ; /* padding or whitespace, keep eating */ |
| 15527 | } else { |
| 15528 | p--; |
| 15529 | break; /* backtrack and go back to fast path, even for -1 */ |
| 15530 | } |
| 15531 | } /* slow path step 3 */ |
| 15532 | } /* outer fast+slow path loop */ |
| 15533 | |
| 15534 | done: |
| 15535 | DUK_DDD(DUK_DDDPRINT("done; p=%p, p_end=%p" , |
| 15536 | (const void *) p, (const void *) p_end)); |
| 15537 | |
| 15538 | DUK_ASSERT(p == p_end); |
| 15539 | |
| 15540 | *out_dst_final = q; |
| 15541 | return 1; |
| 15542 | |
| 15543 | decode_error: |
| 15544 | return 0; |
| 15545 | } |
| 15546 | #else /* DUK_USE_BASE64_FASTPATH */ |
| 15547 | DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) { |
| 15548 | duk_uint_t t, x; |
| 15549 | duk_int_t y; |
| 15550 | duk_int8_t step; |
| 15551 | const duk_uint8_t *p; |
| 15552 | const duk_uint8_t *p_end; |
| 15553 | duk_uint8_t *q; |
| 15554 | /* 0x09, 0x0a, or 0x0d */ |
| 15555 | duk_uint32_t mask_white = (1U << 9) | (1U << 10) | (1U << 13); |
| 15556 | |
| 15557 | /* 't' tracks progress of the decoded group: |
| 15558 | * |
| 15559 | * t == 1 no valid chars yet |
| 15560 | * t >= 0x40 1x6 = 6 bits shifted in |
| 15561 | * t >= 0x1000 2x6 = 12 bits shifted in |
| 15562 | * t >= 0x40000 3x6 = 18 bits shifted in |
| 15563 | * t >= 0x1000000 4x6 = 24 bits shifted in |
| 15564 | * |
| 15565 | * By initializing t=1 there's no need for a separate counter for |
| 15566 | * the number of characters found so far. |
| 15567 | */ |
| 15568 | p = src; |
| 15569 | p_end = src + srclen; |
| 15570 | q = dst; |
| 15571 | t = 1UL; |
| 15572 | |
| 15573 | for (;;) { |
| 15574 | duk_small_uint_t n_equal; |
| 15575 | |
| 15576 | DUK_ASSERT(t >= 1U); |
| 15577 | if (p >= p_end) { |
| 15578 | /* End of input: if input exists, treat like |
| 15579 | * start of padding, finish the block, then |
| 15580 | * re-enter here to see we're done. |
| 15581 | */ |
| 15582 | if (t == 1U) { |
| 15583 | break; |
| 15584 | } else { |
| 15585 | goto simulate_padding; |
| 15586 | } |
| 15587 | } |
| 15588 | |
| 15589 | x = *p++; |
| 15590 | |
| 15591 | if (x >= 0x41U) { |
| 15592 | /* Valid: a-z and A-Z. */ |
| 15593 | DUK_ASSERT(x >= 0x41U && x <= 0xffU); |
| 15594 | if (x >= 0x61U && x <= 0x7aU) { |
| 15595 | y = (duk_int_t) x - 0x61 + 26; |
| 15596 | } else if (x <= 0x5aU) { |
| 15597 | y = (duk_int_t) x - 0x41; |
| 15598 | } else { |
| 15599 | goto decode_error; |
| 15600 | } |
| 15601 | } else if (x >= 0x30U) { |
| 15602 | /* Valid: 0-9 and =. */ |
| 15603 | DUK_ASSERT(x >= 0x30U && x <= 0x40U); |
| 15604 | if (x <= 0x39U) { |
| 15605 | y = (duk_int_t) x - 0x30 + 52; |
| 15606 | } else if (x == 0x3dU) { |
| 15607 | /* Skip padding and whitespace unless we're in the |
| 15608 | * middle of a block. Otherwise complete group by |
| 15609 | * simulating shifting in the correct padding. |
| 15610 | */ |
| 15611 | if (t == 1U) { |
| 15612 | continue; |
| 15613 | } |
| 15614 | goto simulate_padding; |
| 15615 | } else { |
| 15616 | goto decode_error; |
| 15617 | } |
| 15618 | } else if (x >= 0x20U) { |
| 15619 | /* Valid: +, /, and 0x20 whitespace. */ |
| 15620 | DUK_ASSERT(x >= 0x20U && x <= 0x2fU); |
| 15621 | if (x == 0x2bU) { |
| 15622 | y = 62; |
| 15623 | } else if (x == 0x2fU) { |
| 15624 | y = 63; |
| 15625 | } else if (x == 0x20U) { |
| 15626 | continue; |
| 15627 | } else { |
| 15628 | goto decode_error; |
| 15629 | } |
| 15630 | } else { |
| 15631 | /* Valid: whitespace. */ |
| 15632 | duk_uint32_t m; |
| 15633 | DUK_ASSERT(x < 0x20U); /* 0x00 to 0x1f */ |
| 15634 | m = (1U << x); |
| 15635 | if (mask_white & m) { |
| 15636 | /* Allow basic ASCII whitespace. */ |
| 15637 | continue; |
| 15638 | } else { |
| 15639 | goto decode_error; |
| 15640 | } |
| 15641 | } |
| 15642 | |
| 15643 | DUK_ASSERT(y >= 0 && y <= 63); |
| 15644 | t = (t << 6) + (duk_uint_t) y; |
| 15645 | if (t < 0x1000000UL) { |
| 15646 | continue; |
| 15647 | } |
| 15648 | /* fall through; no padding will be added */ |
| 15649 | |
| 15650 | simulate_padding: |
| 15651 | n_equal = 0; |
| 15652 | while (t < 0x1000000UL) { |
| 15653 | t = (t << 6) + 0U; |
| 15654 | n_equal++; |
| 15655 | } |
| 15656 | |
| 15657 | /* Output 3 bytes from 't' and advance as needed. */ |
| 15658 | q[0] = (duk_uint8_t) ((t >> 16) & 0xffU); |
| 15659 | q[1] = (duk_uint8_t) ((t >> 8) & 0xffU); |
| 15660 | q[2] = (duk_uint8_t) (t & 0xffU); |
| 15661 | |
| 15662 | DUK_ASSERT(n_equal <= 4U); |
| 15663 | step = duk__base64_decode_nequal_step[n_equal]; |
| 15664 | if (step < 0) { |
| 15665 | goto decode_error; |
| 15666 | } |
| 15667 | q += step; |
| 15668 | |
| 15669 | /* Re-enter loop. The actual padding characters are skipped |
| 15670 | * by the main loop. This handles cases like missing, partial, |
| 15671 | * full, and extra padding, and allows parsing of concatenated |
| 15672 | * documents (with extra padding) like: Zm===Zm. Also extra |
| 15673 | * prepended padding is accepted: ===Zm9v. |
| 15674 | */ |
| 15675 | t = 1U; |
| 15676 | } |
| 15677 | DUK_ASSERT(t == 1UL); |
| 15678 | |
| 15679 | *out_dst_final = q; |
| 15680 | return 1; |
| 15681 | |
| 15682 | decode_error: |
| 15683 | return 0; |
| 15684 | } |
| 15685 | #endif /* DUK_USE_BASE64_FASTPATH */ |
| 15686 | |
| 15687 | DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) { |
| 15688 | const duk_uint8_t *src; |
| 15689 | duk_size_t srclen; |
| 15690 | duk_size_t dstlen; |
| 15691 | duk_uint8_t *dst; |
| 15692 | const char *ret; |
| 15693 | |
| 15694 | DUK_ASSERT_API_ENTRY(thr); |
| 15695 | |
| 15696 | idx = duk_require_normalize_index(thr, idx); |
| 15697 | src = duk__prep_codec_arg(thr, idx, &srclen); |
| 15698 | DUK_ASSERT(src != NULL); |
| 15699 | |
| 15700 | /* Compute exact output length. Computation must not wrap; this |
| 15701 | * limit works for 32-bit size_t: |
| 15702 | * >>> srclen = 3221225469 |
| 15703 | * >>> '%x' % ((srclen + 2) / 3 * 4) |
| 15704 | * 'fffffffc' |
| 15705 | */ |
| 15706 | if (srclen > 3221225469UL) { |
| 15707 | goto type_error; |
| 15708 | } |
| 15709 | dstlen = (srclen + 2U) / 3U * 4U; |
| 15710 | dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen); |
| 15711 | |
| 15712 | duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst); |
| 15713 | |
| 15714 | ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */ |
| 15715 | duk_replace(thr, idx); |
| 15716 | return ret; |
| 15717 | |
| 15718 | type_error: |
| 15719 | DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED); |
| 15720 | DUK_WO_NORETURN(return NULL;); |
| 15721 | } |
| 15722 | |
| 15723 | DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) { |
| 15724 | const duk_uint8_t *src; |
| 15725 | duk_size_t srclen; |
| 15726 | duk_size_t dstlen; |
| 15727 | duk_uint8_t *dst; |
| 15728 | duk_uint8_t *dst_final; |
| 15729 | |
| 15730 | DUK_ASSERT_API_ENTRY(thr); |
| 15731 | |
| 15732 | idx = duk_require_normalize_index(thr, idx); |
| 15733 | src = duk__prep_codec_arg(thr, idx, &srclen); |
| 15734 | DUK_ASSERT(src != NULL); |
| 15735 | |
| 15736 | /* Round up and add safety margin. Avoid addition before division to |
| 15737 | * avoid possibility of wrapping. Margin includes +3 for rounding up, |
| 15738 | * and +3 for one extra group: the decoder may emit and then backtrack |
| 15739 | * a full group (3 bytes) from zero-sized input for technical reasons. |
| 15740 | * Similarly, 'xx' may ecause 1+3 = bytes to be emitted and then |
| 15741 | * backtracked. |
| 15742 | */ |
| 15743 | dstlen = (srclen / 4) * 3 + 6; /* upper limit, assuming no whitespace etc */ |
| 15744 | dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen); |
| 15745 | /* Note: for dstlen=0, dst may be NULL */ |
| 15746 | |
| 15747 | if (!duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final)) { |
| 15748 | goto type_error; |
| 15749 | } |
| 15750 | |
| 15751 | /* XXX: convert to fixed buffer? */ |
| 15752 | (void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst)); |
| 15753 | duk_replace(thr, idx); |
| 15754 | return; |
| 15755 | |
| 15756 | type_error: |
| 15757 | DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED); |
| 15758 | DUK_WO_NORETURN(return;); |
| 15759 | } |
| 15760 | #else /* DUK_USE_BASE64_SUPPORT */ |
| 15761 | DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) { |
| 15762 | DUK_UNREF(idx); |
| 15763 | DUK_ERROR_UNSUPPORTED(thr); |
| 15764 | DUK_WO_NORETURN(return NULL;); |
| 15765 | } |
| 15766 | |
| 15767 | DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) { |
| 15768 | DUK_UNREF(idx); |
| 15769 | DUK_ERROR_UNSUPPORTED(thr); |
| 15770 | DUK_WO_NORETURN(return;); |
| 15771 | } |
| 15772 | #endif /* DUK_USE_BASE64_SUPPORT */ |
| 15773 | |
| 15774 | /* |
| 15775 | * Hex |
| 15776 | */ |
| 15777 | |
| 15778 | #if defined(DUK_USE_HEX_SUPPORT) |
| 15779 | DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) { |
| 15780 | const duk_uint8_t *inp; |
| 15781 | duk_size_t len; |
| 15782 | duk_size_t i; |
| 15783 | duk_uint8_t *buf; |
| 15784 | const char *ret; |
| 15785 | #if defined(DUK_USE_HEX_FASTPATH) |
| 15786 | duk_size_t len_safe; |
| 15787 | duk_uint16_t *p16; |
| 15788 | #endif |
| 15789 | |
| 15790 | DUK_ASSERT_API_ENTRY(thr); |
| 15791 | |
| 15792 | idx = duk_require_normalize_index(thr, idx); |
| 15793 | inp = duk__prep_codec_arg(thr, idx, &len); |
| 15794 | DUK_ASSERT(inp != NULL); |
| 15795 | |
| 15796 | /* Fixed buffer, no zeroing because we'll fill all the data. */ |
| 15797 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2); |
| 15798 | DUK_ASSERT(buf != NULL); |
| 15799 | |
| 15800 | #if defined(DUK_USE_HEX_FASTPATH) |
| 15801 | DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */ |
| 15802 | p16 = (duk_uint16_t *) (void *) buf; |
| 15803 | len_safe = len & ~0x03U; |
| 15804 | for (i = 0; i < len_safe; i += 4) { |
| 15805 | p16[0] = duk_hex_enctab[inp[i]]; |
| 15806 | p16[1] = duk_hex_enctab[inp[i + 1]]; |
| 15807 | p16[2] = duk_hex_enctab[inp[i + 2]]; |
| 15808 | p16[3] = duk_hex_enctab[inp[i + 3]]; |
| 15809 | p16 += 4; |
| 15810 | } |
| 15811 | for (; i < len; i++) { |
| 15812 | *p16++ = duk_hex_enctab[inp[i]]; |
| 15813 | } |
| 15814 | #else /* DUK_USE_HEX_FASTPATH */ |
| 15815 | for (i = 0; i < len; i++) { |
| 15816 | duk_small_uint_t t; |
| 15817 | t = (duk_small_uint_t) inp[i]; |
| 15818 | buf[i*2 + 0] = duk_lc_digits[t >> 4]; |
| 15819 | buf[i*2 + 1] = duk_lc_digits[t & 0x0f]; |
| 15820 | } |
| 15821 | #endif /* DUK_USE_HEX_FASTPATH */ |
| 15822 | |
| 15823 | /* XXX: Using a string return value forces a string intern which is |
| 15824 | * not always necessary. As a rough performance measure, hex encode |
| 15825 | * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s |
| 15826 | * without string coercion. Change to returning a buffer and let the |
| 15827 | * caller coerce to string if necessary? |
| 15828 | */ |
| 15829 | |
| 15830 | ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */ |
| 15831 | duk_replace(thr, idx); |
| 15832 | return ret; |
| 15833 | } |
| 15834 | |
| 15835 | DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) { |
| 15836 | const duk_uint8_t *inp; |
| 15837 | duk_size_t len; |
| 15838 | duk_size_t i; |
| 15839 | duk_int_t t; |
| 15840 | duk_uint8_t *buf; |
| 15841 | #if defined(DUK_USE_HEX_FASTPATH) |
| 15842 | duk_int_t chk; |
| 15843 | duk_uint8_t *p; |
| 15844 | duk_size_t len_safe; |
| 15845 | #endif |
| 15846 | |
| 15847 | DUK_ASSERT_API_ENTRY(thr); |
| 15848 | |
| 15849 | idx = duk_require_normalize_index(thr, idx); |
| 15850 | inp = duk__prep_codec_arg(thr, idx, &len); |
| 15851 | DUK_ASSERT(inp != NULL); |
| 15852 | |
| 15853 | if (len & 0x01) { |
| 15854 | goto type_error; |
| 15855 | } |
| 15856 | |
| 15857 | /* Fixed buffer, no zeroing because we'll fill all the data. */ |
| 15858 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2); |
| 15859 | DUK_ASSERT(buf != NULL); |
| 15860 | |
| 15861 | #if defined(DUK_USE_HEX_FASTPATH) |
| 15862 | p = buf; |
| 15863 | len_safe = len & ~0x07U; |
| 15864 | for (i = 0; i < len_safe; i += 8) { |
| 15865 | t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) | |
| 15866 | ((duk_int_t) duk_hex_dectab[inp[i + 1]]); |
| 15867 | chk = t; |
| 15868 | p[0] = (duk_uint8_t) t; |
| 15869 | t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) | |
| 15870 | ((duk_int_t) duk_hex_dectab[inp[i + 3]]); |
| 15871 | chk |= t; |
| 15872 | p[1] = (duk_uint8_t) t; |
| 15873 | t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) | |
| 15874 | ((duk_int_t) duk_hex_dectab[inp[i + 5]]); |
| 15875 | chk |= t; |
| 15876 | p[2] = (duk_uint8_t) t; |
| 15877 | t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) | |
| 15878 | ((duk_int_t) duk_hex_dectab[inp[i + 7]]); |
| 15879 | chk |= t; |
| 15880 | p[3] = (duk_uint8_t) t; |
| 15881 | p += 4; |
| 15882 | |
| 15883 | /* Check if any lookup above had a negative result. */ |
| 15884 | if (DUK_UNLIKELY(chk < 0)) { |
| 15885 | goto type_error; |
| 15886 | } |
| 15887 | } |
| 15888 | for (; i < len; i += 2) { |
| 15889 | /* First cast to duk_int_t to sign extend, second cast to |
| 15890 | * duk_uint_t to avoid signed left shift, and final cast to |
| 15891 | * duk_int_t result type. |
| 15892 | */ |
| 15893 | t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) | |
| 15894 | ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]])); |
| 15895 | if (DUK_UNLIKELY(t < 0)) { |
| 15896 | goto type_error; |
| 15897 | } |
| 15898 | *p++ = (duk_uint8_t) t; |
| 15899 | } |
| 15900 | #else /* DUK_USE_HEX_FASTPATH */ |
| 15901 | for (i = 0; i < len; i += 2) { |
| 15902 | /* For invalid characters the value -1 gets extended to |
| 15903 | * at least 16 bits. If either nybble is invalid, the |
| 15904 | * resulting 't' will be < 0. |
| 15905 | */ |
| 15906 | t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) | |
| 15907 | ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]])); |
| 15908 | if (DUK_UNLIKELY(t < 0)) { |
| 15909 | goto type_error; |
| 15910 | } |
| 15911 | buf[i >> 1] = (duk_uint8_t) t; |
| 15912 | } |
| 15913 | #endif /* DUK_USE_HEX_FASTPATH */ |
| 15914 | |
| 15915 | duk_replace(thr, idx); |
| 15916 | return; |
| 15917 | |
| 15918 | type_error: |
| 15919 | DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED); |
| 15920 | DUK_WO_NORETURN(return;); |
| 15921 | } |
| 15922 | #else /* DUK_USE_HEX_SUPPORT */ |
| 15923 | DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) { |
| 15924 | DUK_UNREF(idx); |
| 15925 | DUK_ERROR_UNSUPPORTED(thr); |
| 15926 | DUK_WO_NORETURN(return NULL;); |
| 15927 | } |
| 15928 | DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) { |
| 15929 | DUK_UNREF(idx); |
| 15930 | DUK_ERROR_UNSUPPORTED(thr); |
| 15931 | DUK_WO_NORETURN(return;); |
| 15932 | } |
| 15933 | #endif /* DUK_USE_HEX_SUPPORT */ |
| 15934 | |
| 15935 | /* |
| 15936 | * JSON |
| 15937 | */ |
| 15938 | |
| 15939 | #if defined(DUK_USE_JSON_SUPPORT) |
| 15940 | DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) { |
| 15941 | #if defined(DUK_USE_ASSERTIONS) |
| 15942 | duk_idx_t top_at_entry; |
| 15943 | #endif |
| 15944 | const char *ret; |
| 15945 | |
| 15946 | DUK_ASSERT_API_ENTRY(thr); |
| 15947 | #if defined(DUK_USE_ASSERTIONS) |
| 15948 | top_at_entry = duk_get_top(thr); |
| 15949 | #endif |
| 15950 | |
| 15951 | idx = duk_require_normalize_index(thr, idx); |
| 15952 | duk_bi_json_stringify_helper(thr, |
| 15953 | idx /*idx_value*/, |
| 15954 | DUK_INVALID_INDEX /*idx_replacer*/, |
| 15955 | DUK_INVALID_INDEX /*idx_space*/, |
| 15956 | 0 /*flags*/); |
| 15957 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 15958 | duk_replace(thr, idx); |
| 15959 | ret = duk_get_string(thr, idx); |
| 15960 | |
| 15961 | DUK_ASSERT(duk_get_top(thr) == top_at_entry); |
| 15962 | |
| 15963 | return ret; |
| 15964 | } |
| 15965 | |
| 15966 | DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) { |
| 15967 | #if defined(DUK_USE_ASSERTIONS) |
| 15968 | duk_idx_t top_at_entry; |
| 15969 | #endif |
| 15970 | |
| 15971 | DUK_ASSERT_API_ENTRY(thr); |
| 15972 | #if defined(DUK_USE_ASSERTIONS) |
| 15973 | top_at_entry = duk_get_top(thr); |
| 15974 | #endif |
| 15975 | |
| 15976 | idx = duk_require_normalize_index(thr, idx); |
| 15977 | duk_bi_json_parse_helper(thr, |
| 15978 | idx /*idx_value*/, |
| 15979 | DUK_INVALID_INDEX /*idx_reviver*/, |
| 15980 | 0 /*flags*/); |
| 15981 | duk_replace(thr, idx); |
| 15982 | |
| 15983 | DUK_ASSERT(duk_get_top(thr) == top_at_entry); |
| 15984 | } |
| 15985 | #else /* DUK_USE_JSON_SUPPORT */ |
| 15986 | DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) { |
| 15987 | DUK_ASSERT_API_ENTRY(thr); |
| 15988 | DUK_UNREF(idx); |
| 15989 | DUK_ERROR_UNSUPPORTED(thr); |
| 15990 | DUK_WO_NORETURN(return NULL;); |
| 15991 | } |
| 15992 | |
| 15993 | DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) { |
| 15994 | DUK_ASSERT_API_ENTRY(thr); |
| 15995 | DUK_UNREF(idx); |
| 15996 | DUK_ERROR_UNSUPPORTED(thr); |
| 15997 | DUK_WO_NORETURN(return;); |
| 15998 | } |
| 15999 | #endif /* DUK_USE_JSON_SUPPORT */ |
| 16000 | #line 1 "duk_api_compile.c" |
| 16001 | /* |
| 16002 | * Compilation and evaluation |
| 16003 | */ |
| 16004 | |
| 16005 | /* #include duk_internal.h -> already included */ |
| 16006 | |
| 16007 | typedef struct duk__compile_raw_args duk__compile_raw_args; |
| 16008 | struct duk__compile_raw_args { |
| 16009 | duk_size_t src_length; /* should be first on 64-bit platforms */ |
| 16010 | const duk_uint8_t *src_buffer; |
| 16011 | duk_uint_t flags; |
| 16012 | }; |
| 16013 | |
| 16014 | /* Eval is just a wrapper now. */ |
| 16015 | DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { |
| 16016 | duk_int_t rc; |
| 16017 | |
| 16018 | DUK_ASSERT_API_ENTRY(thr); |
| 16019 | |
| 16020 | /* Note: strictness is *not* inherited from the current Duktape/C. |
| 16021 | * This would be confusing because the current strictness state |
| 16022 | * depends on whether we're running inside a Duktape/C activation |
| 16023 | * (= strict mode) or outside of any activation (= non-strict mode). |
| 16024 | * See tests/api/test-eval-strictness.c for more discussion. |
| 16025 | */ |
| 16026 | |
| 16027 | /* [ ... source? filename? ] (depends on flags) */ |
| 16028 | |
| 16029 | rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */ |
| 16030 | |
| 16031 | /* [ ... closure/error ] */ |
| 16032 | |
| 16033 | if (rc != DUK_EXEC_SUCCESS) { |
| 16034 | rc = DUK_EXEC_ERROR; |
| 16035 | goto got_rc; |
| 16036 | } |
| 16037 | |
| 16038 | duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */ |
| 16039 | |
| 16040 | if (flags & DUK_COMPILE_SAFE) { |
| 16041 | rc = duk_pcall_method(thr, 0); |
| 16042 | } else { |
| 16043 | duk_call_method(thr, 0); |
| 16044 | rc = DUK_EXEC_SUCCESS; |
| 16045 | } |
| 16046 | |
| 16047 | /* [ ... result/error ] */ |
| 16048 | |
| 16049 | got_rc: |
| 16050 | if (flags & DUK_COMPILE_NORESULT) { |
| 16051 | duk_pop(thr); |
| 16052 | } |
| 16053 | |
| 16054 | return rc; |
| 16055 | } |
| 16056 | |
| 16057 | /* Helper which can be called both directly and with duk_safe_call(). */ |
| 16058 | DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) { |
| 16059 | duk__compile_raw_args *comp_args; |
| 16060 | duk_uint_t flags; |
| 16061 | duk_hcompfunc *h_templ; |
| 16062 | |
| 16063 | DUK_CTX_ASSERT_VALID(thr); |
| 16064 | DUK_ASSERT(udata != NULL); |
| 16065 | |
| 16066 | /* Note: strictness is not inherited from the current Duktape/C |
| 16067 | * context. Otherwise it would not be possible to compile |
| 16068 | * non-strict code inside a Duktape/C activation (which is |
| 16069 | * always strict now). See tests/api/test-eval-strictness.c |
| 16070 | * for discussion. |
| 16071 | */ |
| 16072 | |
| 16073 | /* [ ... source? filename? ] (depends on flags) */ |
| 16074 | |
| 16075 | comp_args = (duk__compile_raw_args *) udata; |
| 16076 | flags = comp_args->flags; |
| 16077 | |
| 16078 | if (flags & DUK_COMPILE_NOFILENAME) { |
| 16079 | /* Automatic filename: 'eval' or 'input'. */ |
| 16080 | duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT); |
| 16081 | } |
| 16082 | |
| 16083 | /* [ ... source? filename ] */ |
| 16084 | |
| 16085 | if (!comp_args->src_buffer) { |
| 16086 | duk_hstring *h_sourcecode; |
| 16087 | |
| 16088 | h_sourcecode = duk_get_hstring(thr, -2); |
| 16089 | if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */ |
| 16090 | (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */ |
| 16091 | DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE); |
| 16092 | DUK_WO_NORETURN(return 0;); |
| 16093 | } |
| 16094 | DUK_ASSERT(h_sourcecode != NULL); |
| 16095 | comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode); |
| 16096 | comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode); |
| 16097 | } |
| 16098 | DUK_ASSERT(comp_args->src_buffer != NULL); |
| 16099 | |
| 16100 | if (flags & DUK_COMPILE_FUNCTION) { |
| 16101 | flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR; |
| 16102 | } |
| 16103 | |
| 16104 | /* [ ... source? filename ] */ |
| 16105 | |
| 16106 | duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags); |
| 16107 | |
| 16108 | /* [ ... source? func_template ] */ |
| 16109 | |
| 16110 | if (flags & DUK_COMPILE_NOSOURCE) { |
| 16111 | ; |
| 16112 | } else { |
| 16113 | duk_remove_m2(thr); |
| 16114 | } |
| 16115 | |
| 16116 | /* [ ... func_template ] */ |
| 16117 | |
| 16118 | h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1); |
| 16119 | duk_js_push_closure(thr, |
| 16120 | h_templ, |
| 16121 | thr->builtins[DUK_BIDX_GLOBAL_ENV], |
| 16122 | thr->builtins[DUK_BIDX_GLOBAL_ENV], |
| 16123 | 1 /*add_auto_proto*/); |
| 16124 | duk_remove_m2(thr); /* -> [ ... closure ] */ |
| 16125 | |
| 16126 | /* [ ... closure ] */ |
| 16127 | |
| 16128 | return 1; |
| 16129 | } |
| 16130 | |
| 16131 | DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) { |
| 16132 | duk__compile_raw_args comp_args_alloc; |
| 16133 | duk__compile_raw_args *comp_args = &comp_args_alloc; |
| 16134 | |
| 16135 | DUK_ASSERT_API_ENTRY(thr); |
| 16136 | |
| 16137 | if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) { |
| 16138 | /* String length is computed here to avoid multiple evaluation |
| 16139 | * of a macro argument in the calling side. |
| 16140 | */ |
| 16141 | src_length = DUK_STRLEN(src_buffer); |
| 16142 | } |
| 16143 | |
| 16144 | comp_args->src_buffer = (const duk_uint8_t *) src_buffer; |
| 16145 | comp_args->src_length = src_length; |
| 16146 | comp_args->flags = flags; |
| 16147 | |
| 16148 | /* [ ... source? filename? ] (depends on flags) */ |
| 16149 | |
| 16150 | if (flags & DUK_COMPILE_SAFE) { |
| 16151 | duk_int_t rc; |
| 16152 | duk_int_t nargs; |
| 16153 | duk_int_t nrets = 1; |
| 16154 | |
| 16155 | /* Arguments can be: [ source? filename? &comp_args] so that |
| 16156 | * nargs is 1 to 3. Call site encodes the correct nargs count |
| 16157 | * directly into flags. |
| 16158 | */ |
| 16159 | nargs = flags & 0x07; |
| 16160 | DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) + |
| 16161 | ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)); |
| 16162 | rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets); |
| 16163 | |
| 16164 | /* [ ... closure ] */ |
| 16165 | return rc; |
| 16166 | } |
| 16167 | |
| 16168 | (void) duk__do_compile(thr, (void *) comp_args); |
| 16169 | |
| 16170 | /* [ ... closure ] */ |
| 16171 | return DUK_EXEC_SUCCESS; |
| 16172 | } |
| 16173 | #line 1 "duk_api_debug.c" |
| 16174 | /* |
| 16175 | * Debugging related API calls |
| 16176 | */ |
| 16177 | |
| 16178 | /* #include duk_internal.h -> already included */ |
| 16179 | |
| 16180 | #if defined(DUK_USE_JSON_SUPPORT) |
| 16181 | DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) { |
| 16182 | duk_idx_t idx; |
| 16183 | duk_idx_t top; |
| 16184 | |
| 16185 | DUK_ASSERT_API_ENTRY(thr); |
| 16186 | |
| 16187 | /* We don't duk_require_stack() here now, but rely on the caller having |
| 16188 | * enough space. |
| 16189 | */ |
| 16190 | |
| 16191 | top = duk_get_top(thr); |
| 16192 | duk_push_bare_array(thr); |
| 16193 | for (idx = 0; idx < top; idx++) { |
| 16194 | duk_dup(thr, idx); |
| 16195 | duk_put_prop_index(thr, -2, (duk_uarridx_t) idx); |
| 16196 | } |
| 16197 | |
| 16198 | /* XXX: conversion errors should not propagate outwards. |
| 16199 | * Perhaps values need to be coerced individually? |
| 16200 | */ |
| 16201 | duk_bi_json_stringify_helper(thr, |
| 16202 | duk_get_top_index(thr), /*idx_value*/ |
| 16203 | DUK_INVALID_INDEX, /*idx_replacer*/ |
| 16204 | DUK_INVALID_INDEX, /*idx_space*/ |
| 16205 | DUK_JSON_FLAG_EXT_CUSTOM | |
| 16206 | DUK_JSON_FLAG_ASCII_ONLY | |
| 16207 | DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/); |
| 16208 | |
| 16209 | duk_push_sprintf(thr, "ctx: top=%ld, stack=%s" , (long) top, (const char *) duk_safe_to_string(thr, -1)); |
| 16210 | duk_replace(thr, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */ |
| 16211 | duk_pop(thr); |
| 16212 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 16213 | } |
| 16214 | #else /* DUK_USE_JSON_SUPPORT */ |
| 16215 | DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) { |
| 16216 | DUK_ASSERT_API_ENTRY(thr); |
| 16217 | DUK_ERROR_UNSUPPORTED(thr); |
| 16218 | DUK_WO_NORETURN(return;); |
| 16219 | } |
| 16220 | #endif /* DUK_USE_JSON_SUPPORT */ |
| 16221 | |
| 16222 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 16223 | |
| 16224 | DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr, |
| 16225 | duk_debug_read_function read_cb, |
| 16226 | duk_debug_write_function write_cb, |
| 16227 | duk_debug_peek_function peek_cb, |
| 16228 | duk_debug_read_flush_function read_flush_cb, |
| 16229 | duk_debug_write_flush_function write_flush_cb, |
| 16230 | duk_debug_request_function request_cb, |
| 16231 | duk_debug_detached_function detached_cb, |
| 16232 | void *udata) { |
| 16233 | duk_heap *heap; |
| 16234 | const char *str; |
| 16235 | duk_size_t len; |
| 16236 | |
| 16237 | /* XXX: should there be an error or an automatic detach if |
| 16238 | * already attached? |
| 16239 | */ |
| 16240 | |
| 16241 | DUK_D(DUK_DPRINT("application called duk_debugger_attach()" )); |
| 16242 | |
| 16243 | DUK_ASSERT_API_ENTRY(thr); |
| 16244 | DUK_ASSERT(read_cb != NULL); |
| 16245 | DUK_ASSERT(write_cb != NULL); |
| 16246 | /* Other callbacks are optional. */ |
| 16247 | |
| 16248 | heap = thr->heap; |
| 16249 | heap->dbg_read_cb = read_cb; |
| 16250 | heap->dbg_write_cb = write_cb; |
| 16251 | heap->dbg_peek_cb = peek_cb; |
| 16252 | heap->dbg_read_flush_cb = read_flush_cb; |
| 16253 | heap->dbg_write_flush_cb = write_flush_cb; |
| 16254 | heap->dbg_request_cb = request_cb; |
| 16255 | heap->dbg_detached_cb = detached_cb; |
| 16256 | heap->dbg_udata = udata; |
| 16257 | heap->dbg_have_next_byte = 0; |
| 16258 | |
| 16259 | /* Start in paused state. */ |
| 16260 | heap->dbg_processing = 0; |
| 16261 | heap->dbg_state_dirty = 0; |
| 16262 | heap->dbg_force_restart = 0; |
| 16263 | heap->dbg_pause_flags = 0; |
| 16264 | heap->dbg_pause_act = NULL; |
| 16265 | heap->dbg_pause_startline = 0; |
| 16266 | heap->dbg_exec_counter = 0; |
| 16267 | heap->dbg_last_counter = 0; |
| 16268 | heap->dbg_last_time = 0.0; |
| 16269 | duk_debug_set_paused(heap); /* XXX: overlap with fields above */ |
| 16270 | |
| 16271 | /* Send version identification and flush right afterwards. Note that |
| 16272 | * we must write raw, unframed bytes here. |
| 16273 | */ |
| 16274 | duk_push_sprintf(thr, "%ld %ld %s %s\n" , |
| 16275 | (long) DUK_DEBUG_PROTOCOL_VERSION, |
| 16276 | (long) DUK_VERSION, |
| 16277 | (const char *) DUK_GIT_DESCRIBE, |
| 16278 | (const char *) DUK_USE_TARGET_INFO); |
| 16279 | str = duk_get_lstring(thr, -1, &len); |
| 16280 | DUK_ASSERT(str != NULL); |
| 16281 | duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len); |
| 16282 | duk_debug_write_flush(thr); |
| 16283 | duk_pop(thr); |
| 16284 | } |
| 16285 | |
| 16286 | DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) { |
| 16287 | DUK_D(DUK_DPRINT("application called duk_debugger_detach()" )); |
| 16288 | |
| 16289 | DUK_ASSERT_API_ENTRY(thr); |
| 16290 | DUK_ASSERT(thr->heap != NULL); |
| 16291 | |
| 16292 | /* Can be called multiple times with no harm. */ |
| 16293 | duk_debug_do_detach(thr->heap); |
| 16294 | } |
| 16295 | |
| 16296 | DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) { |
| 16297 | duk_bool_t processed_messages; |
| 16298 | |
| 16299 | DUK_ASSERT_API_ENTRY(thr); |
| 16300 | DUK_ASSERT(thr->heap != NULL); |
| 16301 | |
| 16302 | if (!duk_debug_is_attached(thr->heap)) { |
| 16303 | return; |
| 16304 | } |
| 16305 | if (thr->callstack_curr != NULL || thr->heap->dbg_processing) { |
| 16306 | /* Calling duk_debugger_cooperate() while Duktape is being |
| 16307 | * called into is not supported. This is not a 100% check |
| 16308 | * but prevents any damage in most cases. |
| 16309 | */ |
| 16310 | return; |
| 16311 | } |
| 16312 | |
| 16313 | processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/); |
| 16314 | DUK_UNREF(processed_messages); |
| 16315 | } |
| 16316 | |
| 16317 | DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) { |
| 16318 | duk_idx_t top; |
| 16319 | duk_idx_t idx; |
| 16320 | duk_bool_t ret = 0; |
| 16321 | |
| 16322 | DUK_ASSERT_API_ENTRY(thr); |
| 16323 | DUK_ASSERT(thr->heap != NULL); |
| 16324 | |
| 16325 | DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld" , (long) nvalues)); |
| 16326 | |
| 16327 | top = duk_get_top(thr); |
| 16328 | if (top < nvalues) { |
| 16329 | DUK_ERROR_RANGE(thr, "not enough stack values for notify" ); |
| 16330 | DUK_WO_NORETURN(return 0;); |
| 16331 | } |
| 16332 | if (duk_debug_is_attached(thr->heap)) { |
| 16333 | duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY); |
| 16334 | for (idx = top - nvalues; idx < top; idx++) { |
| 16335 | duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx); |
| 16336 | duk_debug_write_tval(thr, tv); |
| 16337 | } |
| 16338 | duk_debug_write_eom(thr); |
| 16339 | |
| 16340 | /* Return non-zero (true) if we have a good reason to believe |
| 16341 | * the notify was delivered; if we're still attached at least |
| 16342 | * a transport error was not indicated by the transport write |
| 16343 | * callback. This is not a 100% guarantee of course. |
| 16344 | */ |
| 16345 | if (duk_debug_is_attached(thr->heap)) { |
| 16346 | ret = 1; |
| 16347 | } |
| 16348 | } |
| 16349 | duk_pop_n(thr, nvalues); |
| 16350 | return ret; |
| 16351 | } |
| 16352 | |
| 16353 | DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) { |
| 16354 | DUK_ASSERT_API_ENTRY(thr); |
| 16355 | DUK_ASSERT(thr->heap != NULL); |
| 16356 | |
| 16357 | DUK_D(DUK_DPRINT("application called duk_debugger_pause()" )); |
| 16358 | |
| 16359 | /* Treat like a debugger statement: ignore when not attached. */ |
| 16360 | if (duk_debug_is_attached(thr->heap)) { |
| 16361 | if (duk_debug_is_paused(thr->heap)) { |
| 16362 | DUK_D(DUK_DPRINT("duk_debugger_pause() called when already paused; ignoring" )); |
| 16363 | } else { |
| 16364 | duk_debug_set_paused(thr->heap); |
| 16365 | |
| 16366 | /* Pause on the next opcode executed. This is always safe to do even |
| 16367 | * inside the debugger message loop: the interrupt counter will be reset |
| 16368 | * to its proper value when the message loop exits. |
| 16369 | */ |
| 16370 | thr->interrupt_init = 1; |
| 16371 | thr->interrupt_counter = 0; |
| 16372 | } |
| 16373 | } |
| 16374 | } |
| 16375 | |
| 16376 | #else /* DUK_USE_DEBUGGER_SUPPORT */ |
| 16377 | |
| 16378 | DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr, |
| 16379 | duk_debug_read_function read_cb, |
| 16380 | duk_debug_write_function write_cb, |
| 16381 | duk_debug_peek_function peek_cb, |
| 16382 | duk_debug_read_flush_function read_flush_cb, |
| 16383 | duk_debug_write_flush_function write_flush_cb, |
| 16384 | duk_debug_request_function request_cb, |
| 16385 | duk_debug_detached_function detached_cb, |
| 16386 | void *udata) { |
| 16387 | DUK_ASSERT_API_ENTRY(thr); |
| 16388 | DUK_UNREF(read_cb); |
| 16389 | DUK_UNREF(write_cb); |
| 16390 | DUK_UNREF(peek_cb); |
| 16391 | DUK_UNREF(read_flush_cb); |
| 16392 | DUK_UNREF(write_flush_cb); |
| 16393 | DUK_UNREF(request_cb); |
| 16394 | DUK_UNREF(detached_cb); |
| 16395 | DUK_UNREF(udata); |
| 16396 | DUK_ERROR_TYPE(thr, "no debugger support" ); |
| 16397 | DUK_WO_NORETURN(return;); |
| 16398 | } |
| 16399 | |
| 16400 | DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) { |
| 16401 | DUK_ASSERT_API_ENTRY(thr); |
| 16402 | DUK_ERROR_TYPE(thr, "no debugger support" ); |
| 16403 | DUK_WO_NORETURN(return;); |
| 16404 | } |
| 16405 | |
| 16406 | DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) { |
| 16407 | /* nop */ |
| 16408 | DUK_ASSERT_API_ENTRY(thr); |
| 16409 | DUK_UNREF(thr); |
| 16410 | } |
| 16411 | |
| 16412 | DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) { |
| 16413 | duk_idx_t top; |
| 16414 | |
| 16415 | DUK_ASSERT_API_ENTRY(thr); |
| 16416 | |
| 16417 | top = duk_get_top(thr); |
| 16418 | if (top < nvalues) { |
| 16419 | DUK_ERROR_RANGE_INVALID_COUNT(thr); |
| 16420 | DUK_WO_NORETURN(return 0;); |
| 16421 | } |
| 16422 | |
| 16423 | /* No debugger support, just pop values. */ |
| 16424 | duk_pop_n(thr, nvalues); |
| 16425 | return 0; |
| 16426 | } |
| 16427 | |
| 16428 | DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) { |
| 16429 | /* Treat like debugger statement: nop */ |
| 16430 | DUK_ASSERT_API_ENTRY(thr); |
| 16431 | DUK_UNREF(thr); |
| 16432 | } |
| 16433 | |
| 16434 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 16435 | #line 1 "duk_api_heap.c" |
| 16436 | /* |
| 16437 | * Heap creation and destruction |
| 16438 | */ |
| 16439 | |
| 16440 | /* #include duk_internal.h -> already included */ |
| 16441 | |
| 16442 | typedef struct duk_internal_thread_state duk_internal_thread_state; |
| 16443 | |
| 16444 | struct duk_internal_thread_state { |
| 16445 | duk_ljstate lj; |
| 16446 | duk_bool_t creating_error; |
| 16447 | duk_hthread *curr_thread; |
| 16448 | duk_uint8_t thread_state; |
| 16449 | duk_int_t call_recursion_depth; |
| 16450 | }; |
| 16451 | |
| 16452 | DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func, |
| 16453 | duk_realloc_function realloc_func, |
| 16454 | duk_free_function free_func, |
| 16455 | void *heap_udata, |
| 16456 | duk_fatal_function fatal_handler) { |
| 16457 | duk_heap *heap = NULL; |
| 16458 | duk_hthread *thr; |
| 16459 | |
| 16460 | /* Assume that either all memory funcs are NULL or non-NULL, mixed |
| 16461 | * cases will now be unsafe. |
| 16462 | */ |
| 16463 | |
| 16464 | /* XXX: just assert non-NULL values here and make caller arguments |
| 16465 | * do the defaulting to the default implementations (smaller code)? |
| 16466 | */ |
| 16467 | |
| 16468 | if (!alloc_func) { |
| 16469 | DUK_ASSERT(realloc_func == NULL); |
| 16470 | DUK_ASSERT(free_func == NULL); |
| 16471 | #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS) |
| 16472 | alloc_func = duk_default_alloc_function; |
| 16473 | realloc_func = duk_default_realloc_function; |
| 16474 | free_func = duk_default_free_function; |
| 16475 | #else |
| 16476 | DUK_D(DUK_DPRINT("no allocation functions given and no default providers" )); |
| 16477 | return NULL; |
| 16478 | #endif |
| 16479 | } else { |
| 16480 | DUK_ASSERT(realloc_func != NULL); |
| 16481 | DUK_ASSERT(free_func != NULL); |
| 16482 | } |
| 16483 | |
| 16484 | if (!fatal_handler) { |
| 16485 | fatal_handler = duk_default_fatal_handler; |
| 16486 | } |
| 16487 | |
| 16488 | DUK_ASSERT(alloc_func != NULL); |
| 16489 | DUK_ASSERT(realloc_func != NULL); |
| 16490 | DUK_ASSERT(free_func != NULL); |
| 16491 | DUK_ASSERT(fatal_handler != NULL); |
| 16492 | |
| 16493 | heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler); |
| 16494 | if (!heap) { |
| 16495 | return NULL; |
| 16496 | } |
| 16497 | thr = heap->heap_thread; |
| 16498 | DUK_ASSERT(thr != NULL); |
| 16499 | DUK_ASSERT(thr->heap != NULL); |
| 16500 | return thr; |
| 16501 | } |
| 16502 | |
| 16503 | DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) { |
| 16504 | duk_heap *heap; |
| 16505 | |
| 16506 | if (!thr) { |
| 16507 | return; |
| 16508 | } |
| 16509 | DUK_ASSERT_API_ENTRY(thr); |
| 16510 | heap = thr->heap; |
| 16511 | DUK_ASSERT(heap != NULL); |
| 16512 | |
| 16513 | duk_heap_free(heap); |
| 16514 | } |
| 16515 | |
| 16516 | DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) { |
| 16517 | duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state; |
| 16518 | duk_heap *heap; |
| 16519 | duk_ljstate *lj; |
| 16520 | |
| 16521 | DUK_ASSERT_API_ENTRY(thr); |
| 16522 | DUK_ASSERT(thr->heap != NULL); |
| 16523 | DUK_ASSERT(state != NULL); /* unvalidated */ |
| 16524 | |
| 16525 | /* Currently not supported when called from within a finalizer. |
| 16526 | * If that is done, the finalizer will remain running indefinitely, |
| 16527 | * preventing other finalizers from executing. The assert is a bit |
| 16528 | * wider, checking that it would be OK to run pending finalizers. |
| 16529 | */ |
| 16530 | DUK_ASSERT(thr->heap->pf_prevent_count == 0); |
| 16531 | |
| 16532 | /* Currently not supported to duk_suspend() from an errCreate() |
| 16533 | * call. |
| 16534 | */ |
| 16535 | DUK_ASSERT(thr->heap->creating_error == 0); |
| 16536 | |
| 16537 | heap = thr->heap; |
| 16538 | lj = &heap->lj; |
| 16539 | |
| 16540 | duk_push_tval(thr, &lj->value1); |
| 16541 | duk_push_tval(thr, &lj->value2); |
| 16542 | |
| 16543 | /* XXX: creating_error == 0 is asserted above, so no need to store. */ |
| 16544 | duk_memcpy((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate)); |
| 16545 | snapshot->creating_error = heap->creating_error; |
| 16546 | snapshot->curr_thread = heap->curr_thread; |
| 16547 | snapshot->thread_state = thr->state; |
| 16548 | snapshot->call_recursion_depth = heap->call_recursion_depth; |
| 16549 | |
| 16550 | lj->jmpbuf_ptr = NULL; |
| 16551 | lj->type = DUK_LJ_TYPE_UNKNOWN; |
| 16552 | DUK_TVAL_SET_UNDEFINED(&lj->value1); |
| 16553 | DUK_TVAL_SET_UNDEFINED(&lj->value2); |
| 16554 | heap->creating_error = 0; |
| 16555 | heap->curr_thread = NULL; |
| 16556 | heap->call_recursion_depth = 0; |
| 16557 | |
| 16558 | thr->state = DUK_HTHREAD_STATE_INACTIVE; |
| 16559 | } |
| 16560 | |
| 16561 | DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) { |
| 16562 | const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state; |
| 16563 | duk_heap *heap; |
| 16564 | |
| 16565 | DUK_ASSERT_API_ENTRY(thr); |
| 16566 | DUK_ASSERT(thr->heap != NULL); |
| 16567 | DUK_ASSERT(state != NULL); /* unvalidated */ |
| 16568 | |
| 16569 | /* Shouldn't be necessary if duk_suspend() is called before |
| 16570 | * duk_resume(), but assert in case API sequence is incorrect. |
| 16571 | */ |
| 16572 | DUK_ASSERT(thr->heap->pf_prevent_count == 0); |
| 16573 | DUK_ASSERT(thr->heap->creating_error == 0); |
| 16574 | |
| 16575 | thr->state = snapshot->thread_state; |
| 16576 | |
| 16577 | heap = thr->heap; |
| 16578 | |
| 16579 | duk_memcpy((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate)); |
| 16580 | heap->creating_error = snapshot->creating_error; |
| 16581 | heap->curr_thread = snapshot->curr_thread; |
| 16582 | heap->call_recursion_depth = snapshot->call_recursion_depth; |
| 16583 | |
| 16584 | duk_pop_2(thr); |
| 16585 | } |
| 16586 | |
| 16587 | /* XXX: better place for this */ |
| 16588 | DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) { |
| 16589 | duk_hobject *h_glob; |
| 16590 | duk_hobject *h_prev_glob; |
| 16591 | duk_hobjenv *h_env; |
| 16592 | duk_hobject *h_prev_env; |
| 16593 | |
| 16594 | DUK_ASSERT_API_ENTRY(thr); |
| 16595 | |
| 16596 | DUK_D(DUK_DPRINT("replace global object with: %!T" , duk_get_tval(thr, -1))); |
| 16597 | |
| 16598 | h_glob = duk_require_hobject(thr, -1); |
| 16599 | DUK_ASSERT(h_glob != NULL); |
| 16600 | |
| 16601 | /* |
| 16602 | * Replace global object. |
| 16603 | */ |
| 16604 | |
| 16605 | h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL]; |
| 16606 | DUK_UNREF(h_prev_glob); |
| 16607 | thr->builtins[DUK_BIDX_GLOBAL] = h_glob; |
| 16608 | DUK_HOBJECT_INCREF(thr, h_glob); |
| 16609 | DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */ |
| 16610 | |
| 16611 | /* |
| 16612 | * Replace lexical environment for global scope |
| 16613 | * |
| 16614 | * Create a new object environment for the global lexical scope. |
| 16615 | * We can't just reset the _Target property of the current one, |
| 16616 | * because the lexical scope is shared by other threads with the |
| 16617 | * same (initial) built-ins. |
| 16618 | */ |
| 16619 | |
| 16620 | h_env = duk_hobjenv_alloc(thr, |
| 16621 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 16622 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); |
| 16623 | DUK_ASSERT(h_env != NULL); |
| 16624 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_env) == NULL); |
| 16625 | |
| 16626 | DUK_ASSERT(h_env->target == NULL); |
| 16627 | DUK_ASSERT(h_glob != NULL); |
| 16628 | h_env->target = h_glob; |
| 16629 | DUK_HOBJECT_INCREF(thr, h_glob); |
| 16630 | DUK_ASSERT(h_env->has_this == 0); |
| 16631 | |
| 16632 | /* [ ... new_glob ] */ |
| 16633 | |
| 16634 | h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 16635 | thr->builtins[DUK_BIDX_GLOBAL_ENV] = (duk_hobject *) h_env; |
| 16636 | DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_env); |
| 16637 | DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */ |
| 16638 | DUK_UNREF(h_env); /* without refcounts */ |
| 16639 | DUK_UNREF(h_prev_env); |
| 16640 | |
| 16641 | /* [ ... new_glob ] */ |
| 16642 | |
| 16643 | duk_pop(thr); |
| 16644 | |
| 16645 | /* [ ... ] */ |
| 16646 | } |
| 16647 | #line 1 "duk_api_inspect.c" |
| 16648 | /* |
| 16649 | * Inspection |
| 16650 | */ |
| 16651 | |
| 16652 | /* #include duk_internal.h -> already included */ |
| 16653 | |
| 16654 | /* For footprint efficient multiple value setting: arrays are much better than |
| 16655 | * varargs, format string with parsing is often better than string pointer arrays. |
| 16656 | */ |
| 16657 | DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) { |
| 16658 | duk_int_t val; |
| 16659 | const char *p; |
| 16660 | const char *p_curr; |
| 16661 | duk_size_t len; |
| 16662 | |
| 16663 | for (p = fmt;;) { |
| 16664 | len = DUK_STRLEN(p); |
| 16665 | p_curr = p; |
| 16666 | p += len + 1; |
| 16667 | if (len == 0) { |
| 16668 | /* Double NUL (= empty key) terminates. */ |
| 16669 | break; |
| 16670 | } |
| 16671 | val = *vals++; |
| 16672 | if (val >= 0) { |
| 16673 | /* Negative values are markers to skip key. */ |
| 16674 | duk_push_string(thr, p_curr); |
| 16675 | duk_push_int(thr, val); |
| 16676 | duk_put_prop(thr, -3); |
| 16677 | } |
| 16678 | } |
| 16679 | } |
| 16680 | |
| 16681 | /* Raw helper to extract internal information / statistics about a value. |
| 16682 | * The return value is an object with properties that are version specific. |
| 16683 | * The properties must not expose anything that would lead to security |
| 16684 | * issues (e.g. exposing compiled function 'data' buffer might be an issue). |
| 16685 | * Currently only counts and sizes and such are given so there shouldn't |
| 16686 | * be security implications. |
| 16687 | */ |
| 16688 | |
| 16689 | #define DUK__IDX_TYPE 0 |
| 16690 | #define DUK__IDX_ITAG 1 |
| 16691 | #define DUK__IDX_REFC 2 |
| 16692 | #define DUK__IDX_HBYTES 3 |
| 16693 | #define DUK__IDX_CLASS 4 |
| 16694 | #define DUK__IDX_PBYTES 5 |
| 16695 | #define DUK__IDX_ESIZE 6 |
| 16696 | #define DUK__IDX_ENEXT 7 |
| 16697 | #define DUK__IDX_ASIZE 8 |
| 16698 | #define DUK__IDX_HSIZE 9 |
| 16699 | #define DUK__IDX_BCBYTES 10 |
| 16700 | #define DUK__IDX_DBYTES 11 |
| 16701 | #define DUK__IDX_TSTATE 12 |
| 16702 | #define DUK__IDX_VARIANT 13 |
| 16703 | |
| 16704 | DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) { |
| 16705 | duk_tval *tv; |
| 16706 | duk_heaphdr *h; |
| 16707 | /* The temporary values should be in an array rather than individual |
| 16708 | * variables which (in practice) ensures that the compiler won't map |
| 16709 | * them to registers and emit a lot of unnecessary shuffling code. |
| 16710 | */ |
| 16711 | duk_int_t vals[14]; |
| 16712 | |
| 16713 | DUK_ASSERT_API_ENTRY(thr); |
| 16714 | |
| 16715 | /* Assume two's complement and set everything to -1. */ |
| 16716 | duk_memset((void *) &vals, (int) 0xff, sizeof(vals)); |
| 16717 | DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */ |
| 16718 | |
| 16719 | tv = duk_get_tval_or_unused(thr, idx); |
| 16720 | h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL); |
| 16721 | |
| 16722 | vals[DUK__IDX_TYPE] = duk_get_type_tval(tv); |
| 16723 | vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv); |
| 16724 | |
| 16725 | duk_push_bare_object(thr); /* Invalidates 'tv'. */ |
| 16726 | tv = NULL; |
| 16727 | |
| 16728 | if (h == NULL) { |
| 16729 | goto finish; |
| 16730 | } |
| 16731 | duk_push_pointer(thr, (void *) h); |
| 16732 | duk_put_prop_literal(thr, -2, "hptr" ); |
| 16733 | |
| 16734 | #if 0 |
| 16735 | /* Covers a lot of information, e.g. buffer and string variants. */ |
| 16736 | duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h)); |
| 16737 | duk_put_prop_literal(thr, -2, "hflags" ); |
| 16738 | #endif |
| 16739 | |
| 16740 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 16741 | vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h); |
| 16742 | #endif |
| 16743 | vals[DUK__IDX_VARIANT] = 0; |
| 16744 | |
| 16745 | /* Heaphdr size and additional allocation size, followed by |
| 16746 | * type specific stuff (with varying value count). |
| 16747 | */ |
| 16748 | switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) { |
| 16749 | case DUK_HTYPE_STRING: { |
| 16750 | duk_hstring *h_str = (duk_hstring *) h; |
| 16751 | vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1); |
| 16752 | #if defined(DUK_USE_HSTRING_EXTDATA) |
| 16753 | if (DUK_HSTRING_HAS_EXTDATA(h_str)) { |
| 16754 | vals[DUK__IDX_VARIANT] = 1; |
| 16755 | } |
| 16756 | #endif |
| 16757 | break; |
| 16758 | } |
| 16759 | case DUK_HTYPE_OBJECT: { |
| 16760 | duk_hobject *h_obj = (duk_hobject *) h; |
| 16761 | |
| 16762 | /* XXX: variants here are maybe pointless; class is enough? */ |
| 16763 | if (DUK_HOBJECT_IS_ARRAY(h_obj)) { |
| 16764 | vals[DUK__IDX_HBYTES] = sizeof(duk_harray); |
| 16765 | } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { |
| 16766 | vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc); |
| 16767 | } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) { |
| 16768 | vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc); |
| 16769 | } else if (DUK_HOBJECT_IS_THREAD(h_obj)) { |
| 16770 | vals[DUK__IDX_HBYTES] = sizeof(duk_hthread); |
| 16771 | vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state; |
| 16772 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 16773 | } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { |
| 16774 | vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj); |
| 16775 | /* XXX: some size information */ |
| 16776 | #endif |
| 16777 | } else { |
| 16778 | vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject); |
| 16779 | } |
| 16780 | |
| 16781 | vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj); |
| 16782 | vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj); |
| 16783 | vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj); |
| 16784 | vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj); |
| 16785 | vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj); |
| 16786 | vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj); |
| 16787 | |
| 16788 | /* Note: e_next indicates the number of gc-reachable entries |
| 16789 | * in the entry part, and also indicates the index where the |
| 16790 | * next new property would be inserted. It does *not* indicate |
| 16791 | * the number of non-NULL keys present in the object. That |
| 16792 | * value could be counted separately but requires a pass through |
| 16793 | * the key list. |
| 16794 | */ |
| 16795 | |
| 16796 | if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { |
| 16797 | duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj); |
| 16798 | vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0); |
| 16799 | } |
| 16800 | break; |
| 16801 | } |
| 16802 | case DUK_HTYPE_BUFFER: { |
| 16803 | duk_hbuffer *h_buf = (duk_hbuffer *) h; |
| 16804 | |
| 16805 | if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) { |
| 16806 | if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) { |
| 16807 | vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */ |
| 16808 | vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external)); |
| 16809 | } else { |
| 16810 | /* When alloc_size == 0 the second allocation may not |
| 16811 | * actually exist. |
| 16812 | */ |
| 16813 | vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */ |
| 16814 | vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic)); |
| 16815 | } |
| 16816 | vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf)); |
| 16817 | } else { |
| 16818 | DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */ |
| 16819 | vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf)); |
| 16820 | } |
| 16821 | break; |
| 16822 | } |
| 16823 | } |
| 16824 | |
| 16825 | finish: |
| 16826 | duk__inspect_multiple_uint(thr, |
| 16827 | "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00" |
| 16828 | "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00" |
| 16829 | "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00" , |
| 16830 | (duk_int_t *) &vals); |
| 16831 | } |
| 16832 | |
| 16833 | DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) { |
| 16834 | duk_activation *act; |
| 16835 | duk_uint_fast32_t pc; |
| 16836 | duk_uint_fast32_t line; |
| 16837 | |
| 16838 | DUK_ASSERT_API_ENTRY(thr); |
| 16839 | |
| 16840 | /* -1 = top callstack entry |
| 16841 | * -2 = caller of level -1 |
| 16842 | * etc |
| 16843 | */ |
| 16844 | act = duk_hthread_get_activation_for_level(thr, level); |
| 16845 | if (act == NULL) { |
| 16846 | duk_push_undefined(thr); |
| 16847 | return; |
| 16848 | } |
| 16849 | duk_push_bare_object(thr); |
| 16850 | |
| 16851 | /* Relevant PC is just before current one because PC is |
| 16852 | * post-incremented. This should match what error augment |
| 16853 | * code does. |
| 16854 | */ |
| 16855 | pc = duk_hthread_get_act_prev_pc(thr, act); |
| 16856 | |
| 16857 | duk_push_tval(thr, &act->tv_func); |
| 16858 | |
| 16859 | duk_push_uint(thr, (duk_uint_t) pc); |
| 16860 | duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC); |
| 16861 | |
| 16862 | #if defined(DUK_USE_PC2LINE) |
| 16863 | line = duk_hobject_pc2line_query(thr, -1, pc); |
| 16864 | #else |
| 16865 | line = 0; |
| 16866 | #endif |
| 16867 | duk_push_uint(thr, (duk_uint_t) line); |
| 16868 | duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER); |
| 16869 | |
| 16870 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION); |
| 16871 | /* Providing access to e.g. act->lex_env would be dangerous: these |
| 16872 | * internal structures must never be accessible to the application. |
| 16873 | * Duktape relies on them having consistent data, and this consistency |
| 16874 | * is only asserted for, not checked for. |
| 16875 | */ |
| 16876 | } |
| 16877 | |
| 16878 | /* automatic undefs */ |
| 16879 | #undef DUK__IDX_ASIZE |
| 16880 | #undef DUK__IDX_BCBYTES |
| 16881 | #undef DUK__IDX_CLASS |
| 16882 | #undef DUK__IDX_DBYTES |
| 16883 | #undef DUK__IDX_ENEXT |
| 16884 | #undef DUK__IDX_ESIZE |
| 16885 | #undef DUK__IDX_HBYTES |
| 16886 | #undef DUK__IDX_HSIZE |
| 16887 | #undef DUK__IDX_ITAG |
| 16888 | #undef DUK__IDX_PBYTES |
| 16889 | #undef DUK__IDX_REFC |
| 16890 | #undef DUK__IDX_TSTATE |
| 16891 | #undef DUK__IDX_TYPE |
| 16892 | #undef DUK__IDX_VARIANT |
| 16893 | #line 1 "duk_api_memory.c" |
| 16894 | /* |
| 16895 | * Memory calls. |
| 16896 | */ |
| 16897 | |
| 16898 | /* #include duk_internal.h -> already included */ |
| 16899 | |
| 16900 | DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) { |
| 16901 | DUK_ASSERT_API_ENTRY(thr); |
| 16902 | |
| 16903 | return DUK_ALLOC_RAW(thr->heap, size); |
| 16904 | } |
| 16905 | |
| 16906 | DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) { |
| 16907 | DUK_ASSERT_API_ENTRY(thr); |
| 16908 | |
| 16909 | DUK_FREE_RAW(thr->heap, ptr); |
| 16910 | } |
| 16911 | |
| 16912 | DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) { |
| 16913 | DUK_ASSERT_API_ENTRY(thr); |
| 16914 | |
| 16915 | return DUK_REALLOC_RAW(thr->heap, ptr, size); |
| 16916 | } |
| 16917 | |
| 16918 | DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) { |
| 16919 | DUK_ASSERT_API_ENTRY(thr); |
| 16920 | |
| 16921 | return DUK_ALLOC(thr->heap, size); |
| 16922 | } |
| 16923 | |
| 16924 | DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) { |
| 16925 | DUK_ASSERT_API_ENTRY(thr); |
| 16926 | |
| 16927 | DUK_FREE_CHECKED(thr, ptr); |
| 16928 | } |
| 16929 | |
| 16930 | DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) { |
| 16931 | DUK_ASSERT_API_ENTRY(thr); |
| 16932 | |
| 16933 | /* |
| 16934 | * Note: since this is an exposed API call, there should be |
| 16935 | * no way a mark-and-sweep could have a side effect on the |
| 16936 | * memory allocation behind 'ptr'; the pointer should never |
| 16937 | * be something that Duktape wants to change. |
| 16938 | * |
| 16939 | * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't |
| 16940 | * have the storage location here anyway). |
| 16941 | */ |
| 16942 | |
| 16943 | return DUK_REALLOC(thr->heap, ptr, size); |
| 16944 | } |
| 16945 | |
| 16946 | DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) { |
| 16947 | duk_heap *heap; |
| 16948 | |
| 16949 | DUK_ASSERT_API_ENTRY(thr); |
| 16950 | DUK_ASSERT(out_funcs != NULL); |
| 16951 | DUK_ASSERT(thr != NULL); |
| 16952 | DUK_ASSERT(thr->heap != NULL); |
| 16953 | |
| 16954 | heap = thr->heap; |
| 16955 | out_funcs->alloc_func = heap->alloc_func; |
| 16956 | out_funcs->realloc_func = heap->realloc_func; |
| 16957 | out_funcs->free_func = heap->free_func; |
| 16958 | out_funcs->udata = heap->heap_udata; |
| 16959 | } |
| 16960 | |
| 16961 | DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) { |
| 16962 | duk_heap *heap; |
| 16963 | duk_small_uint_t ms_flags; |
| 16964 | |
| 16965 | DUK_ASSERT_API_ENTRY(thr); |
| 16966 | heap = thr->heap; |
| 16967 | DUK_ASSERT(heap != NULL); |
| 16968 | |
| 16969 | DUK_D(DUK_DPRINT("mark-and-sweep requested by application" )); |
| 16970 | DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */ |
| 16971 | ms_flags = (duk_small_uint_t) flags; |
| 16972 | duk_heap_mark_and_sweep(heap, ms_flags); |
| 16973 | } |
| 16974 | #line 1 "duk_api_object.c" |
| 16975 | /* |
| 16976 | * Object handling: property access and other support functions. |
| 16977 | */ |
| 16978 | |
| 16979 | /* #include duk_internal.h -> already included */ |
| 16980 | |
| 16981 | /* |
| 16982 | * Property handling |
| 16983 | * |
| 16984 | * The API exposes only the most common property handling functions. |
| 16985 | * The caller can invoke ECMAScript built-ins for full control (e.g. |
| 16986 | * defineProperty, getOwnPropertyDescriptor). |
| 16987 | */ |
| 16988 | |
| 16989 | DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx) { |
| 16990 | duk_tval *tv_obj; |
| 16991 | duk_tval *tv_key; |
| 16992 | duk_bool_t rc; |
| 16993 | |
| 16994 | DUK_ASSERT_API_ENTRY(thr); |
| 16995 | |
| 16996 | /* Note: copying tv_obj and tv_key to locals to shield against a valstack |
| 16997 | * resize is not necessary for a property get right now. |
| 16998 | */ |
| 16999 | |
| 17000 | tv_obj = duk_require_tval(thr, obj_idx); |
| 17001 | tv_key = duk_require_tval(thr, -1); |
| 17002 | |
| 17003 | rc = duk_hobject_getprop(thr, tv_obj, tv_key); |
| 17004 | DUK_ASSERT(rc == 0 || rc == 1); |
| 17005 | /* a value is left on stack regardless of rc */ |
| 17006 | |
| 17007 | duk_remove_m2(thr); /* remove key */ |
| 17008 | DUK_ASSERT(duk_is_undefined(thr, -1) || rc == 1); |
| 17009 | return rc; /* 1 if property found, 0 otherwise */ |
| 17010 | } |
| 17011 | |
| 17012 | DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { |
| 17013 | DUK_ASSERT_API_ENTRY(thr); |
| 17014 | DUK_ASSERT(key != NULL); |
| 17015 | |
| 17016 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17017 | (void) duk_push_string(thr, key); |
| 17018 | return duk_get_prop(thr, obj_idx); |
| 17019 | } |
| 17020 | |
| 17021 | DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17022 | DUK_ASSERT_API_ENTRY(thr); |
| 17023 | DUK_ASSERT(key != NULL); |
| 17024 | |
| 17025 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17026 | (void) duk_push_lstring(thr, key, key_len); |
| 17027 | return duk_get_prop(thr, obj_idx); |
| 17028 | } |
| 17029 | |
| 17030 | #if !defined(DUK_USE_PREFER_SIZE) |
| 17031 | DUK_EXTERNAL duk_bool_t duk_get_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17032 | DUK_ASSERT_API_ENTRY(thr); |
| 17033 | DUK_ASSERT(key != NULL); |
| 17034 | DUK_ASSERT(key[key_len] == (char) 0); |
| 17035 | |
| 17036 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17037 | (void) duk_push_literal_raw(thr, key, key_len); |
| 17038 | return duk_get_prop(thr, obj_idx); |
| 17039 | } |
| 17040 | #endif |
| 17041 | |
| 17042 | DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { |
| 17043 | DUK_ASSERT_API_ENTRY(thr); |
| 17044 | |
| 17045 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17046 | duk_push_uarridx(thr, arr_idx); |
| 17047 | return duk_get_prop(thr, obj_idx); |
| 17048 | } |
| 17049 | |
| 17050 | DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { |
| 17051 | DUK_ASSERT_API_ENTRY(thr); |
| 17052 | |
| 17053 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17054 | (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ |
| 17055 | return duk_get_prop(thr, obj_idx); |
| 17056 | } |
| 17057 | |
| 17058 | DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { |
| 17059 | DUK_ASSERT_API_ENTRY(thr); |
| 17060 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17061 | |
| 17062 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17063 | (void) duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); |
| 17064 | return duk_get_prop(thr, obj_idx); |
| 17065 | } |
| 17066 | |
| 17067 | DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { |
| 17068 | return duk_get_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), |
| 17069 | (duk_small_uint_t) (packed_args & 0xffffUL)); |
| 17070 | } |
| 17071 | |
| 17072 | DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) { |
| 17073 | duk_bool_t rc; |
| 17074 | |
| 17075 | DUK_ASSERT_API_ENTRY(thr); |
| 17076 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17077 | |
| 17078 | rc = duk_get_prop_stridx(thr, obj_idx, stridx); |
| 17079 | if (out_has_prop) { |
| 17080 | *out_has_prop = rc; |
| 17081 | } |
| 17082 | return duk_to_boolean_top_pop(thr); |
| 17083 | } |
| 17084 | |
| 17085 | /* This get variant is for internal use, it differs from standard |
| 17086 | * duk_get_prop() in that: |
| 17087 | * - Object argument must be an object (primitive values not supported). |
| 17088 | * - Key argument must be a string (no coercion). |
| 17089 | * - Only own properties are checked (no inheritance). Only "entry part" |
| 17090 | * properties are checked (not array index properties). |
| 17091 | * - Property must be a plain data property, not a getter. |
| 17092 | * - Proxy traps are not triggered. |
| 17093 | */ |
| 17094 | DUK_INTERNAL duk_bool_t duk_xget_owndataprop(duk_hthread *thr, duk_idx_t obj_idx) { |
| 17095 | duk_hobject *h_obj; |
| 17096 | duk_hstring *h_key; |
| 17097 | duk_tval *tv_val; |
| 17098 | |
| 17099 | DUK_ASSERT_API_ENTRY(thr); |
| 17100 | |
| 17101 | /* Note: copying tv_obj and tv_key to locals to shield against a valstack |
| 17102 | * resize is not necessary for a property get right now. |
| 17103 | */ |
| 17104 | |
| 17105 | h_obj = duk_get_hobject(thr, obj_idx); |
| 17106 | if (h_obj == NULL) { |
| 17107 | return 0; |
| 17108 | } |
| 17109 | h_key = duk_require_hstring(thr, -1); |
| 17110 | |
| 17111 | tv_val = duk_hobject_find_entry_tval_ptr(thr->heap, h_obj, h_key); |
| 17112 | if (tv_val == NULL) { |
| 17113 | return 0; |
| 17114 | } |
| 17115 | |
| 17116 | duk_push_tval(thr, tv_val); |
| 17117 | duk_remove_m2(thr); /* remove key */ |
| 17118 | |
| 17119 | return 1; |
| 17120 | } |
| 17121 | |
| 17122 | DUK_INTERNAL duk_bool_t duk_xget_owndataprop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { |
| 17123 | DUK_ASSERT_API_ENTRY(thr); |
| 17124 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17125 | |
| 17126 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17127 | (void) duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); |
| 17128 | return duk_xget_owndataprop(thr, obj_idx); |
| 17129 | } |
| 17130 | |
| 17131 | DUK_INTERNAL duk_bool_t duk_xget_owndataprop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { |
| 17132 | return duk_xget_owndataprop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), |
| 17133 | (duk_small_uint_t) (packed_args & 0xffffUL)); |
| 17134 | } |
| 17135 | |
| 17136 | DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) { |
| 17137 | duk_tval *tv_obj; |
| 17138 | duk_tval *tv_key; |
| 17139 | duk_tval *tv_val; |
| 17140 | duk_bool_t throw_flag; |
| 17141 | duk_bool_t rc; |
| 17142 | |
| 17143 | /* Note: copying tv_obj and tv_key to locals to shield against a valstack |
| 17144 | * resize is not necessary for a property put right now (putprop protects |
| 17145 | * against it internally). |
| 17146 | */ |
| 17147 | |
| 17148 | /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key, |
| 17149 | * idx_val is always (idx_key ^ 0x01). |
| 17150 | */ |
| 17151 | DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) || |
| 17152 | (idx_key == -1 && (idx_key ^ 1) == -2)); |
| 17153 | /* XXX: Direct access; faster validation. */ |
| 17154 | tv_obj = duk_require_tval(thr, obj_idx); |
| 17155 | tv_key = duk_require_tval(thr, idx_key); |
| 17156 | tv_val = duk_require_tval(thr, idx_key ^ 1); |
| 17157 | throw_flag = duk_is_strict_call(thr); |
| 17158 | |
| 17159 | rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag); |
| 17160 | DUK_ASSERT(rc == 0 || rc == 1); |
| 17161 | |
| 17162 | duk_pop_2(thr); /* remove key and value */ |
| 17163 | return rc; /* 1 if property found, 0 otherwise */ |
| 17164 | } |
| 17165 | |
| 17166 | DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx) { |
| 17167 | DUK_ASSERT_API_ENTRY(thr); |
| 17168 | return duk__put_prop_shared(thr, obj_idx, -2); |
| 17169 | } |
| 17170 | |
| 17171 | DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { |
| 17172 | DUK_ASSERT_API_ENTRY(thr); |
| 17173 | DUK_ASSERT(key != NULL); |
| 17174 | |
| 17175 | /* Careful here and with other duk_put_prop_xxx() helpers: the |
| 17176 | * target object and the property value may be in the same value |
| 17177 | * stack slot (unusual, but still conceptually clear). |
| 17178 | */ |
| 17179 | obj_idx = duk_normalize_index(thr, obj_idx); |
| 17180 | (void) duk_push_string(thr, key); |
| 17181 | return duk__put_prop_shared(thr, obj_idx, -1); |
| 17182 | } |
| 17183 | |
| 17184 | DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17185 | DUK_ASSERT_API_ENTRY(thr); |
| 17186 | DUK_ASSERT(key != NULL); |
| 17187 | |
| 17188 | obj_idx = duk_normalize_index(thr, obj_idx); |
| 17189 | (void) duk_push_lstring(thr, key, key_len); |
| 17190 | return duk__put_prop_shared(thr, obj_idx, -1); |
| 17191 | } |
| 17192 | |
| 17193 | #if !defined(DUK_USE_PREFER_SIZE) |
| 17194 | DUK_EXTERNAL duk_bool_t duk_put_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17195 | DUK_ASSERT_API_ENTRY(thr); |
| 17196 | DUK_ASSERT(key != NULL); |
| 17197 | DUK_ASSERT(key[key_len] == (char) 0); |
| 17198 | |
| 17199 | obj_idx = duk_normalize_index(thr, obj_idx); |
| 17200 | (void) duk_push_literal_raw(thr, key, key_len); |
| 17201 | return duk__put_prop_shared(thr, obj_idx, -1); |
| 17202 | } |
| 17203 | #endif |
| 17204 | |
| 17205 | DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { |
| 17206 | DUK_ASSERT_API_ENTRY(thr); |
| 17207 | |
| 17208 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17209 | duk_push_uarridx(thr, arr_idx); |
| 17210 | return duk__put_prop_shared(thr, obj_idx, -1); |
| 17211 | } |
| 17212 | |
| 17213 | DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { |
| 17214 | DUK_ASSERT_API_ENTRY(thr); |
| 17215 | |
| 17216 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17217 | (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ |
| 17218 | return duk__put_prop_shared(thr, obj_idx, -1); |
| 17219 | } |
| 17220 | |
| 17221 | |
| 17222 | DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { |
| 17223 | DUK_ASSERT_API_ENTRY(thr); |
| 17224 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17225 | |
| 17226 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17227 | duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); |
| 17228 | return duk__put_prop_shared(thr, obj_idx, -1); |
| 17229 | } |
| 17230 | |
| 17231 | DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { |
| 17232 | return duk_put_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), |
| 17233 | (duk_small_uint_t) (packed_args & 0xffffUL)); |
| 17234 | } |
| 17235 | |
| 17236 | DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx) { |
| 17237 | duk_tval *tv_obj; |
| 17238 | duk_tval *tv_key; |
| 17239 | duk_bool_t throw_flag; |
| 17240 | duk_bool_t rc; |
| 17241 | |
| 17242 | DUK_ASSERT_API_ENTRY(thr); |
| 17243 | |
| 17244 | /* Note: copying tv_obj and tv_key to locals to shield against a valstack |
| 17245 | * resize is not necessary for a property delete right now. |
| 17246 | */ |
| 17247 | |
| 17248 | tv_obj = duk_require_tval(thr, obj_idx); |
| 17249 | tv_key = duk_require_tval(thr, -1); |
| 17250 | throw_flag = duk_is_strict_call(thr); |
| 17251 | |
| 17252 | rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag); |
| 17253 | DUK_ASSERT(rc == 0 || rc == 1); |
| 17254 | |
| 17255 | duk_pop(thr); /* remove key */ |
| 17256 | return rc; |
| 17257 | } |
| 17258 | |
| 17259 | DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { |
| 17260 | DUK_ASSERT_API_ENTRY(thr); |
| 17261 | DUK_ASSERT(key != NULL); |
| 17262 | |
| 17263 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17264 | (void) duk_push_string(thr, key); |
| 17265 | return duk_del_prop(thr, obj_idx); |
| 17266 | } |
| 17267 | |
| 17268 | DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17269 | DUK_ASSERT_API_ENTRY(thr); |
| 17270 | DUK_ASSERT(key != NULL); |
| 17271 | |
| 17272 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17273 | (void) duk_push_lstring(thr, key, key_len); |
| 17274 | return duk_del_prop(thr, obj_idx); |
| 17275 | } |
| 17276 | |
| 17277 | #if !defined(DUK_USE_PREFER_SIZE) |
| 17278 | DUK_EXTERNAL duk_bool_t duk_del_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17279 | DUK_ASSERT_API_ENTRY(thr); |
| 17280 | DUK_ASSERT(key != NULL); |
| 17281 | DUK_ASSERT(key[key_len] == (char) 0); |
| 17282 | |
| 17283 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17284 | (void) duk_push_literal_raw(thr, key, key_len); |
| 17285 | return duk_del_prop(thr, obj_idx); |
| 17286 | } |
| 17287 | #endif |
| 17288 | |
| 17289 | DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { |
| 17290 | DUK_ASSERT_API_ENTRY(thr); |
| 17291 | |
| 17292 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17293 | duk_push_uarridx(thr, arr_idx); |
| 17294 | return duk_del_prop(thr, obj_idx); |
| 17295 | } |
| 17296 | |
| 17297 | DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { |
| 17298 | DUK_ASSERT_API_ENTRY(thr); |
| 17299 | |
| 17300 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17301 | (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ |
| 17302 | return duk_del_prop(thr, obj_idx); |
| 17303 | } |
| 17304 | |
| 17305 | DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { |
| 17306 | DUK_ASSERT_API_ENTRY(thr); |
| 17307 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17308 | |
| 17309 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17310 | duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); |
| 17311 | return duk_del_prop(thr, obj_idx); |
| 17312 | } |
| 17313 | |
| 17314 | #if 0 |
| 17315 | DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { |
| 17316 | return duk_del_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), |
| 17317 | (duk_small_uint_t) (packed_args & 0xffffUL)); |
| 17318 | } |
| 17319 | #endif |
| 17320 | |
| 17321 | DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx) { |
| 17322 | duk_tval *tv_obj; |
| 17323 | duk_tval *tv_key; |
| 17324 | duk_bool_t rc; |
| 17325 | |
| 17326 | DUK_ASSERT_API_ENTRY(thr); |
| 17327 | |
| 17328 | /* Note: copying tv_obj and tv_key to locals to shield against a valstack |
| 17329 | * resize is not necessary for a property existence check right now. |
| 17330 | */ |
| 17331 | |
| 17332 | tv_obj = duk_require_tval(thr, obj_idx); |
| 17333 | tv_key = duk_require_tval(thr, -1); |
| 17334 | |
| 17335 | rc = duk_hobject_hasprop(thr, tv_obj, tv_key); |
| 17336 | DUK_ASSERT(rc == 0 || rc == 1); |
| 17337 | |
| 17338 | duk_pop(thr); /* remove key */ |
| 17339 | return rc; /* 1 if property found, 0 otherwise */ |
| 17340 | } |
| 17341 | |
| 17342 | DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) { |
| 17343 | DUK_ASSERT_API_ENTRY(thr); |
| 17344 | DUK_ASSERT(key != NULL); |
| 17345 | |
| 17346 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17347 | (void) duk_push_string(thr, key); |
| 17348 | return duk_has_prop(thr, obj_idx); |
| 17349 | } |
| 17350 | |
| 17351 | DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17352 | DUK_ASSERT_API_ENTRY(thr); |
| 17353 | DUK_ASSERT(key != NULL); |
| 17354 | |
| 17355 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17356 | (void) duk_push_lstring(thr, key, key_len); |
| 17357 | return duk_has_prop(thr, obj_idx); |
| 17358 | } |
| 17359 | |
| 17360 | #if !defined(DUK_USE_PREFER_SIZE) |
| 17361 | DUK_EXTERNAL duk_bool_t duk_has_prop_literal_raw(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) { |
| 17362 | DUK_ASSERT_API_ENTRY(thr); |
| 17363 | DUK_ASSERT(key != NULL); |
| 17364 | DUK_ASSERT(key[key_len] == (char) 0); |
| 17365 | |
| 17366 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17367 | (void) duk_push_literal_raw(thr, key, key_len); |
| 17368 | return duk_has_prop(thr, obj_idx); |
| 17369 | } |
| 17370 | #endif |
| 17371 | |
| 17372 | DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) { |
| 17373 | DUK_ASSERT_API_ENTRY(thr); |
| 17374 | |
| 17375 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17376 | duk_push_uarridx(thr, arr_idx); |
| 17377 | return duk_has_prop(thr, obj_idx); |
| 17378 | } |
| 17379 | |
| 17380 | DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) { |
| 17381 | DUK_ASSERT_API_ENTRY(thr); |
| 17382 | |
| 17383 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17384 | (void) duk_push_heapptr(thr, ptr); /* NULL -> 'undefined' */ |
| 17385 | return duk_has_prop(thr, obj_idx); |
| 17386 | } |
| 17387 | |
| 17388 | DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { |
| 17389 | DUK_ASSERT_API_ENTRY(thr); |
| 17390 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17391 | |
| 17392 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17393 | duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); |
| 17394 | return duk_has_prop(thr, obj_idx); |
| 17395 | } |
| 17396 | |
| 17397 | #if 0 |
| 17398 | DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { |
| 17399 | return duk_has_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16), |
| 17400 | (duk_small_uint_t) (packed_args & 0xffffUL)); |
| 17401 | } |
| 17402 | #endif |
| 17403 | |
| 17404 | /* Define own property without inheritance lookups and such. This differs from |
| 17405 | * [[DefineOwnProperty]] because special behaviors (like Array 'length') are |
| 17406 | * not invoked by this method. The caller must be careful to invoke any such |
| 17407 | * behaviors if necessary. |
| 17408 | */ |
| 17409 | DUK_INTERNAL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags) { |
| 17410 | duk_hobject *obj; |
| 17411 | duk_hstring *key; |
| 17412 | |
| 17413 | DUK_ASSERT_API_ENTRY(thr); |
| 17414 | |
| 17415 | obj = duk_require_hobject(thr, obj_idx); |
| 17416 | DUK_ASSERT(obj != NULL); |
| 17417 | key = duk_to_property_key_hstring(thr, -2); |
| 17418 | DUK_ASSERT(key != NULL); |
| 17419 | DUK_ASSERT(duk_require_tval(thr, -1) != NULL); |
| 17420 | |
| 17421 | duk_hobject_define_property_internal(thr, obj, key, desc_flags); |
| 17422 | |
| 17423 | duk_pop(thr); /* pop key */ |
| 17424 | } |
| 17425 | |
| 17426 | DUK_INTERNAL void duk_xdef_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) { |
| 17427 | duk_hobject *obj; |
| 17428 | |
| 17429 | DUK_ASSERT_API_ENTRY(thr); |
| 17430 | |
| 17431 | obj = duk_require_hobject(thr, obj_idx); |
| 17432 | DUK_ASSERT(obj != NULL); |
| 17433 | |
| 17434 | duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags); |
| 17435 | /* value popped by call */ |
| 17436 | } |
| 17437 | |
| 17438 | DUK_INTERNAL void duk_xdef_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) { |
| 17439 | duk_hobject *obj; |
| 17440 | duk_hstring *key; |
| 17441 | |
| 17442 | DUK_ASSERT_API_ENTRY(thr); |
| 17443 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17444 | |
| 17445 | obj = duk_require_hobject(thr, obj_idx); |
| 17446 | DUK_ASSERT(obj != NULL); |
| 17447 | key = DUK_HTHREAD_GET_STRING(thr, stridx); |
| 17448 | DUK_ASSERT(key != NULL); |
| 17449 | DUK_ASSERT(duk_require_tval(thr, -1) != NULL); |
| 17450 | |
| 17451 | duk_hobject_define_property_internal(thr, obj, key, desc_flags); |
| 17452 | /* value popped by call */ |
| 17453 | } |
| 17454 | |
| 17455 | DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) { |
| 17456 | duk_xdef_prop_stridx(thr, (duk_idx_t) (duk_int8_t) (packed_args >> 24), |
| 17457 | (duk_small_uint_t) (packed_args >> 8) & 0xffffUL, |
| 17458 | (duk_small_uint_t) (packed_args & 0xffL)); |
| 17459 | } |
| 17460 | |
| 17461 | #if 0 /*unused*/ |
| 17462 | DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) { |
| 17463 | duk_hobject *obj; |
| 17464 | duk_hstring *key; |
| 17465 | |
| 17466 | DUK_ASSERT_API_ENTRY(thr); |
| 17467 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 17468 | DUK_ASSERT_BIDX_VALID(builtin_idx); |
| 17469 | |
| 17470 | obj = duk_require_hobject(thr, obj_idx); |
| 17471 | DUK_ASSERT(obj != NULL); |
| 17472 | key = DUK_HTHREAD_GET_STRING(thr, stridx); |
| 17473 | DUK_ASSERT(key != NULL); |
| 17474 | |
| 17475 | duk_push_hobject(thr, thr->builtins[builtin_idx]); |
| 17476 | duk_hobject_define_property_internal(thr, obj, key, desc_flags); |
| 17477 | /* value popped by call */ |
| 17478 | } |
| 17479 | #endif |
| 17480 | |
| 17481 | /* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3) |
| 17482 | * setter/getter into an object property. This is needed by the 'arguments' |
| 17483 | * object creation code, function instance creation code, and Function.prototype.bind(). |
| 17484 | */ |
| 17485 | |
| 17486 | DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) { |
| 17487 | DUK_ASSERT_API_ENTRY(thr); |
| 17488 | |
| 17489 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17490 | duk_push_hstring_stridx(thr, stridx); |
| 17491 | duk_push_hobject_bidx(thr, DUK_BIDX_TYPE_ERROR_THROWER); |
| 17492 | duk_dup_top(thr); |
| 17493 | duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */ |
| 17494 | } |
| 17495 | |
| 17496 | /* Object.getOwnPropertyDescriptor() equivalent C binding. */ |
| 17497 | DUK_EXTERNAL void duk_get_prop_desc(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) { |
| 17498 | DUK_ASSERT_API_ENTRY(thr); |
| 17499 | DUK_UNREF(flags); /* no flags defined yet */ |
| 17500 | |
| 17501 | duk_hobject_object_get_own_property_descriptor(thr, obj_idx); /* [ ... key ] -> [ ... desc ] */ |
| 17502 | } |
| 17503 | |
| 17504 | /* Object.defineProperty() equivalent C binding. */ |
| 17505 | DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) { |
| 17506 | duk_idx_t idx_base; |
| 17507 | duk_hobject *obj; |
| 17508 | duk_hstring *key; |
| 17509 | duk_idx_t idx_value; |
| 17510 | duk_hobject *get; |
| 17511 | duk_hobject *set; |
| 17512 | duk_uint_t is_data_desc; |
| 17513 | duk_uint_t is_acc_desc; |
| 17514 | |
| 17515 | DUK_ASSERT_API_ENTRY(thr); |
| 17516 | |
| 17517 | obj = duk_require_hobject(thr, obj_idx); |
| 17518 | |
| 17519 | is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE); |
| 17520 | is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER); |
| 17521 | if (is_data_desc && is_acc_desc) { |
| 17522 | /* "Have" flags must not be conflicting so that they would |
| 17523 | * apply to both a plain property and an accessor at the same |
| 17524 | * time. |
| 17525 | */ |
| 17526 | goto fail_invalid_desc; |
| 17527 | } |
| 17528 | |
| 17529 | idx_base = duk_get_top_index(thr); |
| 17530 | if (flags & DUK_DEFPROP_HAVE_SETTER) { |
| 17531 | duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED | |
| 17532 | DUK_TYPE_MASK_OBJECT | |
| 17533 | DUK_TYPE_MASK_LIGHTFUNC); |
| 17534 | set = duk_get_hobject_promote_lfunc(thr, idx_base); |
| 17535 | if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) { |
| 17536 | goto fail_not_callable; |
| 17537 | } |
| 17538 | idx_base--; |
| 17539 | } else { |
| 17540 | set = NULL; |
| 17541 | } |
| 17542 | if (flags & DUK_DEFPROP_HAVE_GETTER) { |
| 17543 | duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED | |
| 17544 | DUK_TYPE_MASK_OBJECT | |
| 17545 | DUK_TYPE_MASK_LIGHTFUNC); |
| 17546 | get = duk_get_hobject_promote_lfunc(thr, idx_base); |
| 17547 | if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) { |
| 17548 | goto fail_not_callable; |
| 17549 | } |
| 17550 | idx_base--; |
| 17551 | } else { |
| 17552 | get = NULL; |
| 17553 | } |
| 17554 | if (flags & DUK_DEFPROP_HAVE_VALUE) { |
| 17555 | idx_value = idx_base; |
| 17556 | idx_base--; |
| 17557 | } else { |
| 17558 | idx_value = (duk_idx_t) -1; |
| 17559 | } |
| 17560 | key = duk_to_property_key_hstring(thr, idx_base); |
| 17561 | DUK_ASSERT(key != NULL); |
| 17562 | |
| 17563 | duk_require_valid_index(thr, idx_base); |
| 17564 | |
| 17565 | duk_hobject_define_property_helper(thr, |
| 17566 | flags /*defprop_flags*/, |
| 17567 | obj, |
| 17568 | key, |
| 17569 | idx_value, |
| 17570 | get, |
| 17571 | set, |
| 17572 | 1 /*throw_flag*/); |
| 17573 | |
| 17574 | /* Clean up stack */ |
| 17575 | |
| 17576 | duk_set_top(thr, idx_base); |
| 17577 | |
| 17578 | /* [ ... obj ... ] */ |
| 17579 | |
| 17580 | return; |
| 17581 | |
| 17582 | fail_invalid_desc: |
| 17583 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR); |
| 17584 | DUK_WO_NORETURN(return;); |
| 17585 | |
| 17586 | fail_not_callable: |
| 17587 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); |
| 17588 | DUK_WO_NORETURN(return;); |
| 17589 | } |
| 17590 | |
| 17591 | /* |
| 17592 | * Object related |
| 17593 | */ |
| 17594 | |
| 17595 | DUK_EXTERNAL void duk_compact(duk_hthread *thr, duk_idx_t obj_idx) { |
| 17596 | duk_hobject *obj; |
| 17597 | |
| 17598 | DUK_ASSERT_API_ENTRY(thr); |
| 17599 | |
| 17600 | obj = duk_get_hobject(thr, obj_idx); |
| 17601 | if (obj) { |
| 17602 | /* Note: this may fail, caller should protect the call if necessary */ |
| 17603 | duk_hobject_compact_props(thr, obj); |
| 17604 | } |
| 17605 | } |
| 17606 | |
| 17607 | DUK_INTERNAL void duk_compact_m1(duk_hthread *thr) { |
| 17608 | DUK_ASSERT_API_ENTRY(thr); |
| 17609 | |
| 17610 | duk_compact(thr, -1); |
| 17611 | } |
| 17612 | |
| 17613 | /* XXX: the duk_hobject_enum.c stack APIs should be reworked */ |
| 17614 | |
| 17615 | DUK_EXTERNAL void duk_enum(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t enum_flags) { |
| 17616 | DUK_ASSERT_API_ENTRY(thr); |
| 17617 | |
| 17618 | duk_dup(thr, obj_idx); |
| 17619 | duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 17620 | duk_hobject_enumerator_create(thr, enum_flags); /* [target] -> [enum] */ |
| 17621 | } |
| 17622 | |
| 17623 | DUK_EXTERNAL duk_bool_t duk_next(duk_hthread *thr, duk_idx_t enum_index, duk_bool_t get_value) { |
| 17624 | DUK_ASSERT_API_ENTRY(thr); |
| 17625 | |
| 17626 | duk_require_hobject(thr, enum_index); |
| 17627 | duk_dup(thr, enum_index); |
| 17628 | return duk_hobject_enumerator_next(thr, get_value); |
| 17629 | } |
| 17630 | |
| 17631 | DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze) { |
| 17632 | duk_tval *tv; |
| 17633 | duk_hobject *h; |
| 17634 | |
| 17635 | DUK_ASSERT_API_ENTRY(thr); |
| 17636 | |
| 17637 | tv = duk_require_tval(thr, obj_idx); |
| 17638 | DUK_ASSERT(tv != NULL); |
| 17639 | |
| 17640 | /* Seal/freeze are quite rare in practice so it'd be nice to get the |
| 17641 | * correct behavior simply via automatic promotion (at the cost of some |
| 17642 | * memory churn). However, the promoted objects don't behave the same, |
| 17643 | * e.g. promoted lightfuncs are extensible. |
| 17644 | */ |
| 17645 | |
| 17646 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 17647 | case DUK_TAG_BUFFER: |
| 17648 | /* Plain buffer: already sealed, but not frozen (and can't be frozen |
| 17649 | * because index properties can't be made non-writable. |
| 17650 | */ |
| 17651 | if (is_freeze) { |
| 17652 | goto fail_cannot_freeze; |
| 17653 | } |
| 17654 | break; |
| 17655 | case DUK_TAG_LIGHTFUNC: |
| 17656 | /* Lightfunc: already sealed and frozen, success. */ |
| 17657 | break; |
| 17658 | case DUK_TAG_OBJECT: |
| 17659 | h = DUK_TVAL_GET_OBJECT(tv); |
| 17660 | DUK_ASSERT(h != NULL); |
| 17661 | if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 17662 | /* Buffer objects cannot be frozen because there's no internal |
| 17663 | * support for making virtual array indices non-writable. |
| 17664 | */ |
| 17665 | DUK_DD(DUK_DDPRINT("cannot freeze a buffer object" )); |
| 17666 | goto fail_cannot_freeze; |
| 17667 | } |
| 17668 | duk_hobject_object_seal_freeze_helper(thr, h, is_freeze); |
| 17669 | |
| 17670 | /* Sealed and frozen objects cannot gain any more properties, |
| 17671 | * so this is a good time to compact them. |
| 17672 | */ |
| 17673 | duk_hobject_compact_props(thr, h); |
| 17674 | break; |
| 17675 | default: |
| 17676 | /* ES2015 Sections 19.1.2.5, 19.1.2.17 */ |
| 17677 | break; |
| 17678 | } |
| 17679 | return; |
| 17680 | |
| 17681 | fail_cannot_freeze: |
| 17682 | DUK_ERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */ |
| 17683 | DUK_WO_NORETURN(return;); |
| 17684 | } |
| 17685 | |
| 17686 | DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) { |
| 17687 | DUK_ASSERT_API_ENTRY(thr); |
| 17688 | |
| 17689 | duk_seal_freeze_raw(thr, obj_idx, 0 /*is_freeze*/); |
| 17690 | } |
| 17691 | |
| 17692 | DUK_EXTERNAL void duk_freeze(duk_hthread *thr, duk_idx_t obj_idx) { |
| 17693 | DUK_ASSERT_API_ENTRY(thr); |
| 17694 | |
| 17695 | duk_seal_freeze_raw(thr, obj_idx, 1 /*is_freeze*/); |
| 17696 | } |
| 17697 | |
| 17698 | /* |
| 17699 | * Helpers for writing multiple properties |
| 17700 | */ |
| 17701 | |
| 17702 | DUK_EXTERNAL void duk_put_function_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_function_list_entry *funcs) { |
| 17703 | const duk_function_list_entry *ent = funcs; |
| 17704 | |
| 17705 | DUK_ASSERT_API_ENTRY(thr); |
| 17706 | |
| 17707 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17708 | if (ent != NULL) { |
| 17709 | while (ent->key != NULL) { |
| 17710 | duk_push_c_function(thr, ent->value, ent->nargs); |
| 17711 | duk_put_prop_string(thr, obj_idx, ent->key); |
| 17712 | ent++; |
| 17713 | } |
| 17714 | } |
| 17715 | } |
| 17716 | |
| 17717 | DUK_EXTERNAL void duk_put_number_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_number_list_entry *numbers) { |
| 17718 | const duk_number_list_entry *ent = numbers; |
| 17719 | duk_tval *tv; |
| 17720 | |
| 17721 | DUK_ASSERT_API_ENTRY(thr); |
| 17722 | |
| 17723 | obj_idx = duk_require_normalize_index(thr, obj_idx); |
| 17724 | if (ent != NULL) { |
| 17725 | while (ent->key != NULL) { |
| 17726 | tv = thr->valstack_top++; |
| 17727 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */ |
| 17728 | DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */ |
| 17729 | duk_put_prop_string(thr, obj_idx, ent->key); |
| 17730 | ent++; |
| 17731 | } |
| 17732 | } |
| 17733 | } |
| 17734 | |
| 17735 | /* |
| 17736 | * Shortcut for accessing global object properties |
| 17737 | */ |
| 17738 | |
| 17739 | DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key) { |
| 17740 | duk_bool_t ret; |
| 17741 | |
| 17742 | DUK_ASSERT_API_ENTRY(thr); |
| 17743 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17744 | |
| 17745 | /* XXX: direct implementation */ |
| 17746 | |
| 17747 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17748 | ret = duk_get_prop_string(thr, -1, key); |
| 17749 | duk_remove_m2(thr); |
| 17750 | return ret; |
| 17751 | } |
| 17752 | |
| 17753 | DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) { |
| 17754 | duk_bool_t ret; |
| 17755 | |
| 17756 | DUK_ASSERT_API_ENTRY(thr); |
| 17757 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17758 | |
| 17759 | /* XXX: direct implementation */ |
| 17760 | |
| 17761 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17762 | ret = duk_get_prop_lstring(thr, -1, key, key_len); |
| 17763 | duk_remove_m2(thr); |
| 17764 | return ret; |
| 17765 | } |
| 17766 | |
| 17767 | #if !defined(DUK_USE_PREFER_SIZE) |
| 17768 | DUK_EXTERNAL duk_bool_t duk_get_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) { |
| 17769 | duk_bool_t ret; |
| 17770 | |
| 17771 | DUK_ASSERT_API_ENTRY(thr); |
| 17772 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17773 | DUK_ASSERT(key[key_len] == (char) 0); |
| 17774 | |
| 17775 | /* XXX: direct implementation */ |
| 17776 | |
| 17777 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17778 | ret = duk_get_prop_literal_raw(thr, -1, key, key_len); |
| 17779 | duk_remove_m2(thr); |
| 17780 | return ret; |
| 17781 | } |
| 17782 | #endif |
| 17783 | |
| 17784 | DUK_EXTERNAL duk_bool_t duk_get_global_heapptr(duk_hthread *thr, void *ptr) { |
| 17785 | duk_bool_t ret; |
| 17786 | |
| 17787 | DUK_ASSERT_API_ENTRY(thr); |
| 17788 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17789 | |
| 17790 | /* XXX: direct implementation */ |
| 17791 | |
| 17792 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17793 | ret = duk_get_prop_heapptr(thr, -1, ptr); |
| 17794 | duk_remove_m2(thr); |
| 17795 | return ret; |
| 17796 | } |
| 17797 | |
| 17798 | |
| 17799 | DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) { |
| 17800 | duk_bool_t ret; |
| 17801 | |
| 17802 | DUK_ASSERT_API_ENTRY(thr); |
| 17803 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17804 | |
| 17805 | /* XXX: direct implementation */ |
| 17806 | |
| 17807 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17808 | duk_insert(thr, -2); |
| 17809 | ret = duk_put_prop_string(thr, -2, key); /* [ ... global val ] -> [ ... global ] */ |
| 17810 | duk_pop(thr); |
| 17811 | return ret; |
| 17812 | } |
| 17813 | |
| 17814 | DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) { |
| 17815 | duk_bool_t ret; |
| 17816 | |
| 17817 | DUK_ASSERT_API_ENTRY(thr); |
| 17818 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17819 | |
| 17820 | /* XXX: direct implementation */ |
| 17821 | |
| 17822 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17823 | duk_insert(thr, -2); |
| 17824 | ret = duk_put_prop_lstring(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */ |
| 17825 | duk_pop(thr); |
| 17826 | return ret; |
| 17827 | } |
| 17828 | |
| 17829 | #if !defined(DUK_USE_PREFER_SIZE) |
| 17830 | DUK_EXTERNAL duk_bool_t duk_put_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) { |
| 17831 | duk_bool_t ret; |
| 17832 | |
| 17833 | DUK_ASSERT_API_ENTRY(thr); |
| 17834 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17835 | DUK_ASSERT(key[key_len] == (char) 0); |
| 17836 | |
| 17837 | /* XXX: direct implementation */ |
| 17838 | |
| 17839 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17840 | duk_insert(thr, -2); |
| 17841 | ret = duk_put_prop_literal_raw(thr, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */ |
| 17842 | duk_pop(thr); |
| 17843 | return ret; |
| 17844 | } |
| 17845 | #endif |
| 17846 | |
| 17847 | DUK_EXTERNAL duk_bool_t duk_put_global_heapptr(duk_hthread *thr, void *ptr) { |
| 17848 | duk_bool_t ret; |
| 17849 | |
| 17850 | DUK_ASSERT_API_ENTRY(thr); |
| 17851 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 17852 | |
| 17853 | /* XXX: direct implementation */ |
| 17854 | |
| 17855 | duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]); |
| 17856 | duk_insert(thr, -2); |
| 17857 | ret = duk_put_prop_heapptr(thr, -2, ptr); /* [ ... global val ] -> [ ... global ] */ |
| 17858 | duk_pop(thr); |
| 17859 | return ret; |
| 17860 | } |
| 17861 | |
| 17862 | /* |
| 17863 | * ES2015 GetMethod() |
| 17864 | */ |
| 17865 | |
| 17866 | DUK_INTERNAL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx) { |
| 17867 | (void) duk_get_prop_stridx(thr, idx, stridx); |
| 17868 | if (duk_is_null_or_undefined(thr, -1)) { |
| 17869 | duk_pop_nodecref_unsafe(thr); |
| 17870 | return 0; |
| 17871 | } |
| 17872 | if (!duk_is_callable(thr, -1)) { |
| 17873 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); |
| 17874 | DUK_WO_NORETURN(return 0;); |
| 17875 | } |
| 17876 | return 1; |
| 17877 | } |
| 17878 | |
| 17879 | /* |
| 17880 | * Object prototype |
| 17881 | */ |
| 17882 | |
| 17883 | DUK_EXTERNAL void duk_get_prototype(duk_hthread *thr, duk_idx_t idx) { |
| 17884 | duk_hobject *obj; |
| 17885 | duk_hobject *proto; |
| 17886 | |
| 17887 | DUK_ASSERT_API_ENTRY(thr); |
| 17888 | |
| 17889 | obj = duk_require_hobject(thr, idx); |
| 17890 | DUK_ASSERT(obj != NULL); |
| 17891 | |
| 17892 | /* XXX: shared helper for duk_push_hobject_or_undefined()? */ |
| 17893 | proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj); |
| 17894 | if (proto) { |
| 17895 | duk_push_hobject(thr, proto); |
| 17896 | } else { |
| 17897 | duk_push_undefined(thr); |
| 17898 | } |
| 17899 | } |
| 17900 | |
| 17901 | DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) { |
| 17902 | duk_hobject *obj; |
| 17903 | duk_hobject *proto; |
| 17904 | |
| 17905 | DUK_ASSERT_API_ENTRY(thr); |
| 17906 | |
| 17907 | obj = duk_require_hobject(thr, idx); |
| 17908 | DUK_ASSERT(obj != NULL); |
| 17909 | duk_require_type_mask(thr, -1, DUK_TYPE_MASK_UNDEFINED | |
| 17910 | DUK_TYPE_MASK_OBJECT); |
| 17911 | proto = duk_get_hobject(thr, -1); |
| 17912 | /* proto can also be NULL here (allowed explicitly) */ |
| 17913 | |
| 17914 | #if defined(DUK_USE_ROM_OBJECTS) |
| 17915 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { |
| 17916 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */ |
| 17917 | DUK_WO_NORETURN(return;); |
| 17918 | } |
| 17919 | #endif |
| 17920 | |
| 17921 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto); |
| 17922 | |
| 17923 | duk_pop(thr); |
| 17924 | } |
| 17925 | |
| 17926 | DUK_INTERNAL void duk_clear_prototype(duk_hthread *thr, duk_idx_t idx) { |
| 17927 | duk_hobject *obj; |
| 17928 | |
| 17929 | DUK_ASSERT_API_ENTRY(thr); |
| 17930 | |
| 17931 | obj = duk_require_hobject(thr, idx); |
| 17932 | DUK_ASSERT(obj != NULL); |
| 17933 | |
| 17934 | #if defined(DUK_USE_ROM_OBJECTS) |
| 17935 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { |
| 17936 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */ |
| 17937 | DUK_WO_NORETURN(return;); |
| 17938 | } |
| 17939 | #endif |
| 17940 | |
| 17941 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, NULL); |
| 17942 | } |
| 17943 | |
| 17944 | DUK_INTERNAL duk_bool_t duk_is_bare_object(duk_hthread *thr, duk_idx_t idx) { |
| 17945 | duk_hobject *obj; |
| 17946 | duk_hobject *proto; |
| 17947 | |
| 17948 | DUK_ASSERT_API_ENTRY(thr); |
| 17949 | |
| 17950 | obj = duk_require_hobject(thr, idx); |
| 17951 | DUK_ASSERT(obj != NULL); |
| 17952 | |
| 17953 | proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj); |
| 17954 | return (proto == NULL); |
| 17955 | } |
| 17956 | |
| 17957 | /* |
| 17958 | * Object finalizer |
| 17959 | */ |
| 17960 | |
| 17961 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 17962 | /* XXX: these could be implemented as macros calling an internal function |
| 17963 | * directly. |
| 17964 | * XXX: same issue as with Duktape.fin: there's no way to delete the property |
| 17965 | * now (just set it to undefined). |
| 17966 | */ |
| 17967 | DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) { |
| 17968 | DUK_ASSERT_API_ENTRY(thr); |
| 17969 | |
| 17970 | /* This get intentionally walks the inheritance chain at present, |
| 17971 | * which matches how the effective finalizer property is also |
| 17972 | * looked up in GC. |
| 17973 | */ |
| 17974 | duk_get_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER); |
| 17975 | } |
| 17976 | |
| 17977 | DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) { |
| 17978 | duk_hobject *h; |
| 17979 | duk_bool_t callable; |
| 17980 | |
| 17981 | DUK_ASSERT_API_ENTRY(thr); |
| 17982 | |
| 17983 | h = duk_require_hobject(thr, idx); /* Get before 'put' so that 'idx' is correct. */ |
| 17984 | callable = duk_is_callable(thr, -1); |
| 17985 | |
| 17986 | /* At present finalizer is stored as a hidden Symbol, with normal |
| 17987 | * inheritance and access control. As a result, finalizer cannot |
| 17988 | * currently be set on a non-extensible (sealed or frozen) object. |
| 17989 | * It might be useful to allow it. |
| 17990 | */ |
| 17991 | duk_put_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER); |
| 17992 | |
| 17993 | /* In addition to setting the finalizer property, keep a "have |
| 17994 | * finalizer" flag in duk_hobject in sync so that refzero can do |
| 17995 | * a very quick finalizer check by walking the prototype chain |
| 17996 | * and checking the flag alone. (Note that this means that just |
| 17997 | * setting _Finalizer on an object won't affect finalizer checks.) |
| 17998 | * |
| 17999 | * NOTE: if the argument is a Proxy object, this flag will be set |
| 18000 | * on the Proxy, not the target. As a result, the target won't get |
| 18001 | * a finalizer flag and the Proxy also won't be finalized as there's |
| 18002 | * an explicit Proxy check in finalization now. |
| 18003 | */ |
| 18004 | if (callable) { |
| 18005 | DUK_HOBJECT_SET_HAVE_FINALIZER(h); |
| 18006 | } else { |
| 18007 | DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h); |
| 18008 | } |
| 18009 | } |
| 18010 | #else /* DUK_USE_FINALIZER_SUPPORT */ |
| 18011 | DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) { |
| 18012 | DUK_ASSERT_API_ENTRY(thr); |
| 18013 | DUK_UNREF(idx); |
| 18014 | DUK_ERROR_UNSUPPORTED(thr); |
| 18015 | DUK_WO_NORETURN(return;); |
| 18016 | } |
| 18017 | |
| 18018 | DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) { |
| 18019 | DUK_ASSERT_API_ENTRY(thr); |
| 18020 | DUK_UNREF(idx); |
| 18021 | DUK_ERROR_UNSUPPORTED(thr); |
| 18022 | DUK_WO_NORETURN(return;); |
| 18023 | } |
| 18024 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 18025 | #line 1 "duk_api_random.c" |
| 18026 | /* |
| 18027 | * Random numbers |
| 18028 | */ |
| 18029 | |
| 18030 | /* #include duk_internal.h -> already included */ |
| 18031 | |
| 18032 | DUK_EXTERNAL duk_double_t duk_random(duk_hthread *thr) { |
| 18033 | return (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr); |
| 18034 | } |
| 18035 | #line 1 "duk_api_stack.c" |
| 18036 | /* |
| 18037 | * API calls related to general value stack manipulation: resizing the value |
| 18038 | * stack, pushing and popping values, type checking and reading values, |
| 18039 | * coercing values, etc. |
| 18040 | * |
| 18041 | * Also contains internal functions (such as duk_get_tval()), defined |
| 18042 | * in duk_api_internal.h, with semantics similar to the public API. |
| 18043 | */ |
| 18044 | |
| 18045 | /* XXX: repetition of stack pre-checks -> helper or macro or inline */ |
| 18046 | /* XXX: shared api error strings, and perhaps even throw code for rare cases? */ |
| 18047 | |
| 18048 | /* #include duk_internal.h -> already included */ |
| 18049 | |
| 18050 | /* |
| 18051 | * Forward declarations |
| 18052 | */ |
| 18053 | |
| 18054 | DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx); |
| 18055 | |
| 18056 | /* |
| 18057 | * Global state for working around missing variadic macros |
| 18058 | */ |
| 18059 | |
| 18060 | #if !defined(DUK_USE_VARIADIC_MACROS) |
| 18061 | DUK_EXTERNAL const char *duk_api_global_filename = NULL; |
| 18062 | DUK_EXTERNAL duk_int_t duk_api_global_line = 0; |
| 18063 | #endif |
| 18064 | |
| 18065 | /* |
| 18066 | * Misc helpers |
| 18067 | */ |
| 18068 | |
| 18069 | DUK_LOCAL const char * const duk__symbol_type_strings[4] = { |
| 18070 | "hidden" , "global" , "local" , "wellknown" |
| 18071 | }; |
| 18072 | |
| 18073 | #if !defined(DUK_USE_PACKED_TVAL) |
| 18074 | DUK_LOCAL const duk_uint_t duk__type_from_tag[] = { |
| 18075 | DUK_TYPE_NUMBER, |
| 18076 | DUK_TYPE_NUMBER, /* fastint */ |
| 18077 | DUK_TYPE_UNDEFINED, |
| 18078 | DUK_TYPE_NULL, |
| 18079 | DUK_TYPE_BOOLEAN, |
| 18080 | DUK_TYPE_POINTER, |
| 18081 | DUK_TYPE_LIGHTFUNC, |
| 18082 | DUK_TYPE_NONE, |
| 18083 | DUK_TYPE_STRING, |
| 18084 | DUK_TYPE_OBJECT, |
| 18085 | DUK_TYPE_BUFFER, |
| 18086 | }; |
| 18087 | DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = { |
| 18088 | DUK_TYPE_MASK_NUMBER, |
| 18089 | DUK_TYPE_MASK_NUMBER, /* fastint */ |
| 18090 | DUK_TYPE_MASK_UNDEFINED, |
| 18091 | DUK_TYPE_MASK_NULL, |
| 18092 | DUK_TYPE_MASK_BOOLEAN, |
| 18093 | DUK_TYPE_MASK_POINTER, |
| 18094 | DUK_TYPE_MASK_LIGHTFUNC, |
| 18095 | DUK_TYPE_MASK_NONE, |
| 18096 | DUK_TYPE_MASK_STRING, |
| 18097 | DUK_TYPE_MASK_OBJECT, |
| 18098 | DUK_TYPE_MASK_BUFFER, |
| 18099 | }; |
| 18100 | #endif /* !DUK_USE_PACKED_TVAL */ |
| 18101 | |
| 18102 | /* Assert that there's room for one value. */ |
| 18103 | #define DUK__ASSERT_SPACE() do { \ |
| 18104 | DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \ |
| 18105 | } while (0) |
| 18106 | |
| 18107 | /* Check that there's room to push one value. */ |
| 18108 | #if defined(DUK_USE_VALSTACK_UNSAFE) |
| 18109 | /* Faster but value stack overruns are memory unsafe. */ |
| 18110 | #define DUK__CHECK_SPACE() DUK__ASSERT_SPACE() |
| 18111 | #else |
| 18112 | #define DUK__CHECK_SPACE() do { \ |
| 18113 | if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \ |
| 18114 | DUK_ERROR_RANGE_PUSH_BEYOND(thr); \ |
| 18115 | } \ |
| 18116 | } while (0) |
| 18117 | #endif |
| 18118 | |
| 18119 | DUK_LOCAL duk_small_uint_t duk__get_symbol_type(duk_hstring *h) { |
| 18120 | const duk_uint8_t *data; |
| 18121 | duk_size_t len; |
| 18122 | |
| 18123 | DUK_ASSERT(h != NULL); |
| 18124 | DUK_ASSERT(DUK_HSTRING_HAS_SYMBOL(h)); |
| 18125 | DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h) >= 1); /* always true, symbol prefix */ |
| 18126 | |
| 18127 | data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); |
| 18128 | len = DUK_HSTRING_GET_BYTELEN(h); |
| 18129 | DUK_ASSERT(len >= 1); |
| 18130 | |
| 18131 | /* XXX: differentiate between 0x82 and 0xff (hidden vs. internal?)? */ |
| 18132 | |
| 18133 | if (data[0] == 0xffU) { |
| 18134 | return DUK_SYMBOL_TYPE_HIDDEN; |
| 18135 | } else if (data[0] == 0x82U) { |
| 18136 | return DUK_SYMBOL_TYPE_HIDDEN; |
| 18137 | } else if (data[0] == 0x80U) { |
| 18138 | return DUK_SYMBOL_TYPE_GLOBAL; |
| 18139 | } else if (data[len - 1] != 0xffU) { |
| 18140 | return DUK_SYMBOL_TYPE_LOCAL; |
| 18141 | } else { |
| 18142 | return DUK_SYMBOL_TYPE_WELLKNOWN; |
| 18143 | } |
| 18144 | } |
| 18145 | |
| 18146 | DUK_LOCAL const char *duk__get_symbol_type_string(duk_hstring *h) { |
| 18147 | duk_small_uint_t idx; |
| 18148 | idx = duk__get_symbol_type(h); |
| 18149 | DUK_ASSERT(idx < sizeof(duk__symbol_type_strings)); |
| 18150 | return duk__symbol_type_strings[idx]; |
| 18151 | } |
| 18152 | |
| 18153 | DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag); |
| 18154 | |
| 18155 | DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) { |
| 18156 | duk_tval *tv; |
| 18157 | duk_small_int_t c; |
| 18158 | duk_double_t d; |
| 18159 | |
| 18160 | tv = duk_get_tval_or_unused(thr, idx); |
| 18161 | DUK_ASSERT(tv != NULL); |
| 18162 | |
| 18163 | /* |
| 18164 | * Special cases like NaN and +/- Infinity are handled explicitly |
| 18165 | * because a plain C coercion from double to int handles these cases |
| 18166 | * in undesirable ways. For instance, NaN may coerce to INT_MIN |
| 18167 | * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX). |
| 18168 | * |
| 18169 | * This double-to-int coercion differs from ToInteger() because it |
| 18170 | * has a finite range (ToInteger() allows e.g. +/- Infinity). It |
| 18171 | * also differs from ToInt32() because the INT_MIN/INT_MAX clamping |
| 18172 | * depends on the size of the int type on the platform. In particular, |
| 18173 | * on platforms with a 64-bit int type, the full range is allowed. |
| 18174 | */ |
| 18175 | |
| 18176 | #if defined(DUK_USE_FASTINT) |
| 18177 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 18178 | duk_int64_t t = DUK_TVAL_GET_FASTINT(tv); |
| 18179 | #if (DUK_INT_MAX <= 0x7fffffffL) |
| 18180 | /* Clamping only necessary for 32-bit ints. */ |
| 18181 | if (t < DUK_INT_MIN) { |
| 18182 | t = DUK_INT_MIN; |
| 18183 | } else if (t > DUK_INT_MAX) { |
| 18184 | t = DUK_INT_MAX; |
| 18185 | } |
| 18186 | #endif |
| 18187 | return (duk_int_t) t; |
| 18188 | } |
| 18189 | #endif |
| 18190 | |
| 18191 | if (DUK_TVAL_IS_NUMBER(tv)) { |
| 18192 | d = DUK_TVAL_GET_NUMBER(tv); |
| 18193 | c = (duk_small_int_t) DUK_FPCLASSIFY(d); |
| 18194 | if (c == DUK_FP_NAN) { |
| 18195 | return 0; |
| 18196 | } else if (d < (duk_double_t) DUK_INT_MIN) { |
| 18197 | /* covers -Infinity */ |
| 18198 | return DUK_INT_MIN; |
| 18199 | } else if (d > (duk_double_t) DUK_INT_MAX) { |
| 18200 | /* covers +Infinity */ |
| 18201 | return DUK_INT_MAX; |
| 18202 | } else { |
| 18203 | /* coerce towards zero */ |
| 18204 | return (duk_int_t) d; |
| 18205 | } |
| 18206 | } |
| 18207 | |
| 18208 | if (require) { |
| 18209 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number" , DUK_STR_NOT_NUMBER); |
| 18210 | DUK_WO_NORETURN(return 0;); |
| 18211 | } |
| 18212 | |
| 18213 | return def_value; |
| 18214 | } |
| 18215 | |
| 18216 | DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) { |
| 18217 | duk_tval *tv; |
| 18218 | duk_small_int_t c; |
| 18219 | duk_double_t d; |
| 18220 | |
| 18221 | /* Same as above but for unsigned int range. */ |
| 18222 | |
| 18223 | tv = duk_get_tval_or_unused(thr, idx); |
| 18224 | DUK_ASSERT(tv != NULL); |
| 18225 | |
| 18226 | #if defined(DUK_USE_FASTINT) |
| 18227 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 18228 | duk_int64_t t = DUK_TVAL_GET_FASTINT(tv); |
| 18229 | if (t < 0) { |
| 18230 | t = 0; |
| 18231 | } |
| 18232 | #if (DUK_UINT_MAX <= 0xffffffffUL) |
| 18233 | /* Clamping only necessary for 32-bit ints. */ |
| 18234 | else if (t > DUK_UINT_MAX) { |
| 18235 | t = DUK_UINT_MAX; |
| 18236 | } |
| 18237 | #endif |
| 18238 | return (duk_uint_t) t; |
| 18239 | } |
| 18240 | #endif |
| 18241 | |
| 18242 | if (DUK_TVAL_IS_NUMBER(tv)) { |
| 18243 | d = DUK_TVAL_GET_NUMBER(tv); |
| 18244 | c = (duk_small_int_t) DUK_FPCLASSIFY(d); |
| 18245 | if (c == DUK_FP_NAN) { |
| 18246 | return 0; |
| 18247 | } else if (d < 0.0) { |
| 18248 | /* covers -Infinity */ |
| 18249 | return (duk_uint_t) 0; |
| 18250 | } else if (d > (duk_double_t) DUK_UINT_MAX) { |
| 18251 | /* covers +Infinity */ |
| 18252 | return (duk_uint_t) DUK_UINT_MAX; |
| 18253 | } else { |
| 18254 | /* coerce towards zero */ |
| 18255 | return (duk_uint_t) d; |
| 18256 | } |
| 18257 | } |
| 18258 | |
| 18259 | if (require) { |
| 18260 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number" , DUK_STR_NOT_NUMBER); |
| 18261 | DUK_WO_NORETURN(return 0;); |
| 18262 | } |
| 18263 | |
| 18264 | return def_value; |
| 18265 | } |
| 18266 | |
| 18267 | /* |
| 18268 | * Stack index validation/normalization and getting a stack duk_tval ptr. |
| 18269 | * |
| 18270 | * These are called by many API entrypoints so the implementations must be |
| 18271 | * fast and "inlined". |
| 18272 | * |
| 18273 | * There's some repetition because of this; keep the functions in sync. |
| 18274 | */ |
| 18275 | |
| 18276 | DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_hthread *thr, duk_idx_t idx) { |
| 18277 | duk_uidx_t vs_size; |
| 18278 | duk_uidx_t uidx; |
| 18279 | |
| 18280 | DUK_ASSERT_API_ENTRY(thr); |
| 18281 | DUK_ASSERT(DUK_INVALID_INDEX < 0); |
| 18282 | |
| 18283 | /* Care must be taken to avoid pointer wrapping in the index |
| 18284 | * validation. For instance, on a 32-bit platform with 8-byte |
| 18285 | * duk_tval the index 0x20000000UL would wrap the memory space |
| 18286 | * once. |
| 18287 | */ |
| 18288 | |
| 18289 | /* Assume value stack sizes (in elements) fits into duk_idx_t. */ |
| 18290 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18291 | vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18292 | DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ |
| 18293 | |
| 18294 | if (idx < 0) { |
| 18295 | uidx = vs_size + (duk_uidx_t) idx; |
| 18296 | } else { |
| 18297 | /* since index non-negative */ |
| 18298 | DUK_ASSERT(idx != DUK_INVALID_INDEX); |
| 18299 | uidx = (duk_uidx_t) idx; |
| 18300 | } |
| 18301 | |
| 18302 | /* DUK_INVALID_INDEX won't be accepted as a valid index. */ |
| 18303 | DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); |
| 18304 | |
| 18305 | if (DUK_LIKELY(uidx < vs_size)) { |
| 18306 | return (duk_idx_t) uidx; |
| 18307 | } |
| 18308 | return DUK_INVALID_INDEX; |
| 18309 | } |
| 18310 | |
| 18311 | DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t idx) { |
| 18312 | duk_uidx_t vs_size; |
| 18313 | duk_uidx_t uidx; |
| 18314 | |
| 18315 | DUK_ASSERT_API_ENTRY(thr); |
| 18316 | DUK_ASSERT(DUK_INVALID_INDEX < 0); |
| 18317 | |
| 18318 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18319 | vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18320 | DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ |
| 18321 | |
| 18322 | if (idx < 0) { |
| 18323 | uidx = vs_size + (duk_uidx_t) idx; |
| 18324 | } else { |
| 18325 | DUK_ASSERT(idx != DUK_INVALID_INDEX); |
| 18326 | uidx = (duk_uidx_t) idx; |
| 18327 | } |
| 18328 | |
| 18329 | /* DUK_INVALID_INDEX won't be accepted as a valid index. */ |
| 18330 | DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); |
| 18331 | |
| 18332 | if (DUK_LIKELY(uidx < vs_size)) { |
| 18333 | return (duk_idx_t) uidx; |
| 18334 | } |
| 18335 | DUK_ERROR_RANGE_INDEX(thr, idx); |
| 18336 | DUK_WO_NORETURN(return 0;); |
| 18337 | } |
| 18338 | |
| 18339 | DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) { |
| 18340 | duk_uidx_t vs_size; |
| 18341 | duk_uidx_t uidx; |
| 18342 | |
| 18343 | DUK_ASSERT_API_ENTRY(thr); |
| 18344 | DUK_ASSERT(DUK_INVALID_INDEX < 0); |
| 18345 | |
| 18346 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18347 | vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18348 | DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ |
| 18349 | |
| 18350 | if (idx < 0) { |
| 18351 | uidx = vs_size + (duk_uidx_t) idx; |
| 18352 | } else { |
| 18353 | DUK_ASSERT(idx != DUK_INVALID_INDEX); |
| 18354 | uidx = (duk_uidx_t) idx; |
| 18355 | } |
| 18356 | |
| 18357 | /* DUK_INVALID_INDEX won't be accepted as a valid index. */ |
| 18358 | DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); |
| 18359 | |
| 18360 | if (DUK_LIKELY(uidx < vs_size)) { |
| 18361 | return thr->valstack_bottom + uidx; |
| 18362 | } |
| 18363 | return NULL; |
| 18364 | } |
| 18365 | |
| 18366 | /* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval |
| 18367 | * pointer. When duk_get_tval() would return NULL, this variant returns a |
| 18368 | * pointer to a duk_tval with tag DUK_TAG_UNUSED. This allows the call site |
| 18369 | * to avoid an unnecessary NULL check which sometimes leads to better code. |
| 18370 | * The return duk_tval is read only (at least for the UNUSED value). |
| 18371 | */ |
| 18372 | DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER(); |
| 18373 | |
| 18374 | DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx) { |
| 18375 | duk_tval *tv; |
| 18376 | |
| 18377 | DUK_ASSERT_API_ENTRY(thr); |
| 18378 | |
| 18379 | tv = duk_get_tval(thr, idx); |
| 18380 | if (tv != NULL) { |
| 18381 | return tv; |
| 18382 | } |
| 18383 | return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused); |
| 18384 | } |
| 18385 | |
| 18386 | DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) { |
| 18387 | duk_uidx_t vs_size; |
| 18388 | duk_uidx_t uidx; |
| 18389 | |
| 18390 | DUK_ASSERT_API_ENTRY(thr); |
| 18391 | DUK_ASSERT(DUK_INVALID_INDEX < 0); |
| 18392 | |
| 18393 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18394 | vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18395 | DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */ |
| 18396 | |
| 18397 | /* Use unsigned arithmetic to optimize comparison. */ |
| 18398 | if (idx < 0) { |
| 18399 | uidx = vs_size + (duk_uidx_t) idx; |
| 18400 | } else { |
| 18401 | DUK_ASSERT(idx != DUK_INVALID_INDEX); |
| 18402 | uidx = (duk_uidx_t) idx; |
| 18403 | } |
| 18404 | |
| 18405 | /* DUK_INVALID_INDEX won't be accepted as a valid index. */ |
| 18406 | DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); |
| 18407 | |
| 18408 | if (DUK_LIKELY(uidx < vs_size)) { |
| 18409 | return thr->valstack_bottom + uidx; |
| 18410 | } |
| 18411 | DUK_ERROR_RANGE_INDEX(thr, idx); |
| 18412 | DUK_WO_NORETURN(return NULL;); |
| 18413 | } |
| 18414 | |
| 18415 | /* Non-critical. */ |
| 18416 | DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_hthread *thr, duk_idx_t idx) { |
| 18417 | DUK_ASSERT_API_ENTRY(thr); |
| 18418 | DUK_ASSERT(DUK_INVALID_INDEX < 0); |
| 18419 | |
| 18420 | return (duk_normalize_index(thr, idx) >= 0); |
| 18421 | } |
| 18422 | |
| 18423 | /* Non-critical. */ |
| 18424 | DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) { |
| 18425 | DUK_ASSERT_API_ENTRY(thr); |
| 18426 | DUK_ASSERT(DUK_INVALID_INDEX < 0); |
| 18427 | |
| 18428 | if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) { |
| 18429 | DUK_ERROR_RANGE_INDEX(thr, idx); |
| 18430 | DUK_WO_NORETURN(return;); |
| 18431 | } |
| 18432 | } |
| 18433 | |
| 18434 | /* |
| 18435 | * Value stack top handling |
| 18436 | */ |
| 18437 | |
| 18438 | DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr) { |
| 18439 | DUK_ASSERT_API_ENTRY(thr); |
| 18440 | |
| 18441 | return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18442 | } |
| 18443 | |
| 18444 | /* Internal helper to get current top but to require a minimum top value |
| 18445 | * (TypeError if not met). |
| 18446 | */ |
| 18447 | DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top) { |
| 18448 | duk_idx_t ret; |
| 18449 | |
| 18450 | DUK_ASSERT_API_ENTRY(thr); |
| 18451 | |
| 18452 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18453 | if (DUK_UNLIKELY(ret < min_top)) { |
| 18454 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 18455 | DUK_WO_NORETURN(return 0;); |
| 18456 | } |
| 18457 | return ret; |
| 18458 | } |
| 18459 | |
| 18460 | /* Set stack top within currently allocated range, but don't reallocate. |
| 18461 | * This is performance critical especially for call handling, so whenever |
| 18462 | * changing, profile and look at generated code. |
| 18463 | */ |
| 18464 | DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) { |
| 18465 | duk_uidx_t vs_size; |
| 18466 | duk_uidx_t vs_limit; |
| 18467 | duk_uidx_t uidx; |
| 18468 | duk_tval *tv; |
| 18469 | |
| 18470 | DUK_ASSERT_API_ENTRY(thr); |
| 18471 | DUK_ASSERT(DUK_INVALID_INDEX < 0); |
| 18472 | |
| 18473 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18474 | DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom); |
| 18475 | vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18476 | vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom); |
| 18477 | |
| 18478 | if (idx < 0) { |
| 18479 | /* Negative indices are always within allocated stack but |
| 18480 | * must not go below zero index. |
| 18481 | */ |
| 18482 | uidx = vs_size + (duk_uidx_t) idx; |
| 18483 | } else { |
| 18484 | /* Positive index can be higher than valstack top but must |
| 18485 | * not go above allocated stack (equality is OK). |
| 18486 | */ |
| 18487 | uidx = (duk_uidx_t) idx; |
| 18488 | } |
| 18489 | |
| 18490 | /* DUK_INVALID_INDEX won't be accepted as a valid index. */ |
| 18491 | DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size); |
| 18492 | DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit); |
| 18493 | |
| 18494 | #if defined(DUK_USE_VALSTACK_UNSAFE) |
| 18495 | DUK_ASSERT(uidx <= vs_limit); |
| 18496 | DUK_UNREF(vs_limit); |
| 18497 | #else |
| 18498 | if (DUK_UNLIKELY(uidx > vs_limit)) { |
| 18499 | DUK_ERROR_RANGE_INDEX(thr, idx); |
| 18500 | DUK_WO_NORETURN(return;); |
| 18501 | } |
| 18502 | #endif |
| 18503 | DUK_ASSERT(uidx <= vs_limit); |
| 18504 | |
| 18505 | /* Handle change in value stack top. Respect value stack |
| 18506 | * initialization policy: 'undefined' above top. Note that |
| 18507 | * DECREF may cause a side effect that reallocates valstack, |
| 18508 | * so must relookup after DECREF. |
| 18509 | */ |
| 18510 | |
| 18511 | if (uidx >= vs_size) { |
| 18512 | /* Stack size increases or stays the same. */ |
| 18513 | #if defined(DUK_USE_ASSERTIONS) |
| 18514 | duk_uidx_t count; |
| 18515 | |
| 18516 | count = uidx - vs_size; |
| 18517 | while (count != 0) { |
| 18518 | count--; |
| 18519 | tv = thr->valstack_top + count; |
| 18520 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); |
| 18521 | } |
| 18522 | #endif |
| 18523 | thr->valstack_top = thr->valstack_bottom + uidx; |
| 18524 | } else { |
| 18525 | /* Stack size decreases. */ |
| 18526 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 18527 | duk_uidx_t count; |
| 18528 | duk_tval *tv_end; |
| 18529 | |
| 18530 | count = vs_size - uidx; |
| 18531 | DUK_ASSERT(count > 0); |
| 18532 | tv = thr->valstack_top; |
| 18533 | tv_end = tv - count; |
| 18534 | DUK_ASSERT(tv > tv_end); /* Because count > 0. */ |
| 18535 | do { |
| 18536 | tv--; |
| 18537 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 18538 | DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); |
| 18539 | } while (tv != tv_end); |
| 18540 | thr->valstack_top = tv_end; |
| 18541 | DUK_REFZERO_CHECK_FAST(thr); |
| 18542 | #else /* DUK_USE_REFERENCE_COUNTING */ |
| 18543 | duk_uidx_t count; |
| 18544 | duk_tval *tv_end; |
| 18545 | |
| 18546 | count = vs_size - uidx; |
| 18547 | tv = thr->valstack_top; |
| 18548 | tv_end = tv - count; |
| 18549 | DUK_ASSERT(tv > tv_end); |
| 18550 | do { |
| 18551 | tv--; |
| 18552 | DUK_TVAL_SET_UNDEFINED(tv); |
| 18553 | } while (tv != tv_end); |
| 18554 | thr->valstack_top = tv_end; |
| 18555 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 18556 | } |
| 18557 | } |
| 18558 | |
| 18559 | /* Internal variant with a non-negative index and no runtime size checks. */ |
| 18560 | #if defined(DUK_USE_PREFER_SIZE) |
| 18561 | DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) { |
| 18562 | DUK_ASSERT_API_ENTRY(thr); |
| 18563 | |
| 18564 | duk_set_top(thr, idx); |
| 18565 | } |
| 18566 | #else /* DUK_USE_PREFER_SIZE */ |
| 18567 | DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) { |
| 18568 | duk_uidx_t uidx; |
| 18569 | duk_uidx_t vs_size; |
| 18570 | duk_tval *tv; |
| 18571 | |
| 18572 | DUK_ASSERT_API_ENTRY(thr); |
| 18573 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18574 | DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom); |
| 18575 | DUK_ASSERT(idx >= 0); |
| 18576 | DUK_ASSERT(idx <= (duk_idx_t) (thr->valstack_end - thr->valstack_bottom)); |
| 18577 | |
| 18578 | /* XXX: byte arithmetic */ |
| 18579 | uidx = (duk_uidx_t) idx; |
| 18580 | vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom); |
| 18581 | |
| 18582 | if (uidx >= vs_size) { |
| 18583 | /* Stack size increases or stays the same. */ |
| 18584 | #if defined(DUK_USE_ASSERTIONS) |
| 18585 | duk_uidx_t count; |
| 18586 | |
| 18587 | count = uidx - vs_size; |
| 18588 | while (count != 0) { |
| 18589 | count--; |
| 18590 | tv = thr->valstack_top + count; |
| 18591 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); |
| 18592 | } |
| 18593 | #endif |
| 18594 | thr->valstack_top = thr->valstack_bottom + uidx; |
| 18595 | } else { |
| 18596 | /* Stack size decreases. */ |
| 18597 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 18598 | duk_uidx_t count; |
| 18599 | duk_tval *tv_end; |
| 18600 | |
| 18601 | count = vs_size - uidx; |
| 18602 | DUK_ASSERT(count > 0); |
| 18603 | tv = thr->valstack_top; |
| 18604 | tv_end = tv - count; |
| 18605 | DUK_ASSERT(tv > tv_end); /* Because count > 0. */ |
| 18606 | do { |
| 18607 | tv--; |
| 18608 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 18609 | DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); |
| 18610 | } while (tv != tv_end); |
| 18611 | thr->valstack_top = tv_end; |
| 18612 | DUK_REFZERO_CHECK_FAST(thr); |
| 18613 | #else /* DUK_USE_REFERENCE_COUNTING */ |
| 18614 | duk_uidx_t count; |
| 18615 | duk_tval *tv_end; |
| 18616 | |
| 18617 | count = vs_size - uidx; |
| 18618 | tv = thr->valstack_top; |
| 18619 | tv_end = tv - count; |
| 18620 | DUK_ASSERT(tv > tv_end); |
| 18621 | do { |
| 18622 | tv--; |
| 18623 | DUK_TVAL_SET_UNDEFINED(tv); |
| 18624 | } while (tv != tv_end); |
| 18625 | thr->valstack_top = tv_end; |
| 18626 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 18627 | } |
| 18628 | } |
| 18629 | #endif /* DUK_USE_PREFER_SIZE */ |
| 18630 | |
| 18631 | /* Internal helper: set top to 'top', and set [idx_wipe_start,top[ to |
| 18632 | * 'undefined' (doing nothing if idx_wipe_start == top). Indices are |
| 18633 | * positive and within value stack reserve. This is used by call handling. |
| 18634 | */ |
| 18635 | DUK_INTERNAL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start) { |
| 18636 | DUK_ASSERT_API_ENTRY(thr); |
| 18637 | DUK_ASSERT(top >= 0); |
| 18638 | DUK_ASSERT(idx_wipe_start >= 0); |
| 18639 | DUK_ASSERT(idx_wipe_start <= top); |
| 18640 | DUK_ASSERT(thr->valstack_bottom + top <= thr->valstack_end); |
| 18641 | DUK_ASSERT(thr->valstack_bottom + idx_wipe_start <= thr->valstack_end); |
| 18642 | |
| 18643 | duk_set_top_unsafe(thr, idx_wipe_start); |
| 18644 | duk_set_top_unsafe(thr, top); |
| 18645 | } |
| 18646 | |
| 18647 | DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_hthread *thr) { |
| 18648 | duk_idx_t ret; |
| 18649 | |
| 18650 | DUK_ASSERT_API_ENTRY(thr); |
| 18651 | |
| 18652 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; |
| 18653 | if (DUK_UNLIKELY(ret < 0)) { |
| 18654 | /* Return invalid index; if caller uses this without checking |
| 18655 | * in another API call, the index won't map to a valid stack |
| 18656 | * entry. |
| 18657 | */ |
| 18658 | return DUK_INVALID_INDEX; |
| 18659 | } |
| 18660 | return ret; |
| 18661 | } |
| 18662 | |
| 18663 | /* Internal variant: call assumes there is at least one element on the value |
| 18664 | * stack frame; this is only asserted for. |
| 18665 | */ |
| 18666 | DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr) { |
| 18667 | duk_idx_t ret; |
| 18668 | |
| 18669 | DUK_ASSERT_API_ENTRY(thr); |
| 18670 | |
| 18671 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; |
| 18672 | return ret; |
| 18673 | } |
| 18674 | |
| 18675 | DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) { |
| 18676 | duk_idx_t ret; |
| 18677 | |
| 18678 | DUK_ASSERT_API_ENTRY(thr); |
| 18679 | |
| 18680 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1; |
| 18681 | if (DUK_UNLIKELY(ret < 0)) { |
| 18682 | DUK_ERROR_RANGE_INDEX(thr, -1); |
| 18683 | DUK_WO_NORETURN(return 0;); |
| 18684 | } |
| 18685 | return ret; |
| 18686 | } |
| 18687 | |
| 18688 | /* |
| 18689 | * Value stack resizing. |
| 18690 | * |
| 18691 | * This resizing happens above the current "top": the value stack can be |
| 18692 | * grown or shrunk, but the "top" is not affected. The value stack cannot |
| 18693 | * be resized to a size below the current reserve. |
| 18694 | * |
| 18695 | * The low level reallocation primitive must carefully recompute all value |
| 18696 | * stack pointers, and must also work if ALL pointers are NULL. The resize |
| 18697 | * is quite tricky because the valstack realloc may cause a mark-and-sweep, |
| 18698 | * which may run finalizers. Running finalizers may resize the valstack |
| 18699 | * recursively (the same value stack we're working on). So, after realloc |
| 18700 | * returns, we know that the valstack bottom, top, and reserve should still |
| 18701 | * be the same (there should not be live values above the "top"), but its |
| 18702 | * underlying size, alloc_end, and base pointer may have changed. |
| 18703 | * |
| 18704 | * 'new_size' is known to be <= DUK_USE_VALSTACK_LIMIT, which ensures that |
| 18705 | * size_t and pointer arithmetic won't wrap in duk__resize_valstack(). |
| 18706 | */ |
| 18707 | |
| 18708 | /* Low level valstack resize primitive, used for both grow and shrink. All |
| 18709 | * adjustments for slack etc have already been done. Doesn't throw but does |
| 18710 | * have allocation side effects. |
| 18711 | */ |
| 18712 | DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__resize_valstack(duk_hthread *thr, duk_size_t new_size) { |
| 18713 | duk_tval *pre_valstack; |
| 18714 | duk_tval *pre_bottom; |
| 18715 | duk_tval *pre_top; |
| 18716 | duk_tval *pre_end; |
| 18717 | duk_tval *pre_alloc_end; |
| 18718 | duk_ptrdiff_t ptr_diff; |
| 18719 | duk_tval *new_valstack; |
| 18720 | duk_size_t new_alloc_size; |
| 18721 | duk_tval *tv_prev_alloc_end; |
| 18722 | duk_tval *p; |
| 18723 | |
| 18724 | DUK_HTHREAD_ASSERT_VALID(thr); |
| 18725 | DUK_ASSERT(thr->valstack_bottom >= thr->valstack); |
| 18726 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18727 | DUK_ASSERT(thr->valstack_end >= thr->valstack_top); |
| 18728 | DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); |
| 18729 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */ |
| 18730 | DUK_ASSERT(new_size <= DUK_USE_VALSTACK_LIMIT); /* valstack limit caller has check, prevents wrapping */ |
| 18731 | DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */ |
| 18732 | |
| 18733 | /* Pre-realloc pointer copies for asserts and debug logs. */ |
| 18734 | pre_valstack = thr->valstack; |
| 18735 | pre_bottom = thr->valstack_bottom; |
| 18736 | pre_top = thr->valstack_top; |
| 18737 | pre_end = thr->valstack_end; |
| 18738 | pre_alloc_end = thr->valstack_alloc_end; |
| 18739 | |
| 18740 | DUK_UNREF(pre_valstack); |
| 18741 | DUK_UNREF(pre_bottom); |
| 18742 | DUK_UNREF(pre_top); |
| 18743 | DUK_UNREF(pre_end); |
| 18744 | DUK_UNREF(pre_alloc_end); |
| 18745 | |
| 18746 | /* If finalizer torture enabled, force base pointer change every time |
| 18747 | * when it would be allowed. |
| 18748 | */ |
| 18749 | #if defined(DUK_USE_FINALIZER_TORTURE) |
| 18750 | if (thr->heap->pf_prevent_count == 0) { |
| 18751 | duk_hthread_valstack_torture_realloc(thr); |
| 18752 | } |
| 18753 | #endif |
| 18754 | |
| 18755 | /* Allocate a new valstack using DUK_REALLOC_DIRECT() to deal with |
| 18756 | * a side effect changing the base pointer. |
| 18757 | */ |
| 18758 | new_alloc_size = sizeof(duk_tval) * new_size; |
| 18759 | new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size); |
| 18760 | if (DUK_UNLIKELY(new_valstack == NULL)) { |
| 18761 | /* Because new_size != 0, if condition doesn't need to be |
| 18762 | * (new_valstack != NULL || new_size == 0). |
| 18763 | */ |
| 18764 | DUK_ASSERT(new_size != 0); |
| 18765 | DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)" , |
| 18766 | (unsigned long) new_size, (unsigned long) new_alloc_size)); |
| 18767 | return 0; |
| 18768 | } |
| 18769 | |
| 18770 | /* Debug log any changes in pointer(s) by side effects. These don't |
| 18771 | * necessarily imply any incorrect behavior, but should be rare in |
| 18772 | * practice. |
| 18773 | */ |
| 18774 | #if defined(DUK_USE_DEBUG) |
| 18775 | if (thr->valstack != pre_valstack) { |
| 18776 | DUK_D(DUK_DPRINT("valstack base pointer changed during valstack resize: %p -> %p" , |
| 18777 | (void *) pre_valstack, (void *) thr->valstack)); |
| 18778 | } |
| 18779 | if (thr->valstack_bottom != pre_bottom) { |
| 18780 | DUK_D(DUK_DPRINT("valstack bottom pointer changed during valstack resize: %p -> %p" , |
| 18781 | (void *) pre_bottom, (void *) thr->valstack_bottom)); |
| 18782 | } |
| 18783 | if (thr->valstack_top != pre_top) { |
| 18784 | DUK_D(DUK_DPRINT("valstack top pointer changed during valstack resize: %p -> %p" , |
| 18785 | (void *) pre_top, (void *) thr->valstack_top)); |
| 18786 | } |
| 18787 | if (thr->valstack_end != pre_end) { |
| 18788 | DUK_D(DUK_DPRINT("valstack end pointer changed during valstack resize: %p -> %p" , |
| 18789 | (void *) pre_end, (void *) thr->valstack_end)); |
| 18790 | } |
| 18791 | if (thr->valstack_alloc_end != pre_alloc_end) { |
| 18792 | DUK_D(DUK_DPRINT("valstack alloc_end pointer changed during valstack resize: %p -> %p" , |
| 18793 | (void *) pre_alloc_end, (void *) thr->valstack_alloc_end)); |
| 18794 | } |
| 18795 | #endif |
| 18796 | |
| 18797 | /* Assertions: offsets for bottom, top, and end (reserve) must not |
| 18798 | * have changed even with side effects because they are always |
| 18799 | * restored in unwind. For alloc_end there's no guarantee: it may |
| 18800 | * have grown or shrunk (but remain above 'end'). |
| 18801 | */ |
| 18802 | DUK_ASSERT(thr->valstack_bottom - thr->valstack == pre_bottom - pre_valstack); |
| 18803 | DUK_ASSERT(thr->valstack_top - thr->valstack == pre_top - pre_valstack); |
| 18804 | DUK_ASSERT(thr->valstack_end - thr->valstack == pre_end - pre_valstack); |
| 18805 | DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); |
| 18806 | |
| 18807 | /* Write new pointers. Most pointers can be handled as a pointer |
| 18808 | * difference. |
| 18809 | */ |
| 18810 | ptr_diff = (duk_ptrdiff_t) ((duk_uint8_t *) new_valstack - (duk_uint8_t *) thr->valstack); |
| 18811 | tv_prev_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_alloc_end + ptr_diff); |
| 18812 | thr->valstack = new_valstack; |
| 18813 | thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + ptr_diff); |
| 18814 | thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + ptr_diff); |
| 18815 | thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_end + ptr_diff); |
| 18816 | thr->valstack_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + new_alloc_size); |
| 18817 | |
| 18818 | /* Assertions: pointer sanity after pointer updates. */ |
| 18819 | DUK_ASSERT(thr->valstack_bottom >= thr->valstack); |
| 18820 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 18821 | DUK_ASSERT(thr->valstack_end >= thr->valstack_top); |
| 18822 | DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); |
| 18823 | |
| 18824 | DUK_D(DUK_DPRINT("resized valstack %lu -> %lu elements (%lu -> %lu bytes): " |
| 18825 | "base=%p -> %p, bottom=%p -> %p (%ld), top=%p -> %p (%ld), " |
| 18826 | "end=%p -> %p (%ld), alloc_end=%p -> %p (%ld);" |
| 18827 | " tv_prev_alloc_end=%p (-> %ld inits; <0 means shrink)" , |
| 18828 | (unsigned long) (pre_alloc_end - pre_valstack), |
| 18829 | (unsigned long) new_size, |
| 18830 | (unsigned long) ((duk_uint8_t *) pre_alloc_end - (duk_uint8_t *) pre_valstack), |
| 18831 | (unsigned long) new_alloc_size, |
| 18832 | (void *) pre_valstack, (void *) thr->valstack, |
| 18833 | (void *) pre_bottom, (void *) thr->valstack_bottom, (long) (thr->valstack_bottom - thr->valstack), |
| 18834 | (void *) pre_top, (void *) thr->valstack_top, (long) (thr->valstack_top - thr->valstack), |
| 18835 | (void *) pre_end, (void *) thr->valstack_end, (long) (thr->valstack_end - thr->valstack), |
| 18836 | (void *) pre_alloc_end, (void *) thr->valstack_alloc_end, (long) (thr->valstack_alloc_end - thr->valstack), |
| 18837 | (void *) tv_prev_alloc_end, (long) (thr->valstack_alloc_end - tv_prev_alloc_end))); |
| 18838 | |
| 18839 | /* If allocation grew, init any new slots to 'undefined'. */ |
| 18840 | p = tv_prev_alloc_end; |
| 18841 | while (p < thr->valstack_alloc_end) { |
| 18842 | /* Never executed if new size is smaller. */ |
| 18843 | DUK_TVAL_SET_UNDEFINED(p); |
| 18844 | p++; |
| 18845 | } |
| 18846 | |
| 18847 | /* Assert for value stack initialization policy. */ |
| 18848 | #if defined(DUK_USE_ASSERTIONS) |
| 18849 | p = thr->valstack_top; |
| 18850 | while (p < thr->valstack_alloc_end) { |
| 18851 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p)); |
| 18852 | p++; |
| 18853 | } |
| 18854 | #endif |
| 18855 | |
| 18856 | return 1; |
| 18857 | } |
| 18858 | |
| 18859 | DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__valstack_grow(duk_hthread *thr, duk_size_t min_bytes, duk_bool_t throw_on_error) { |
| 18860 | duk_size_t min_size; |
| 18861 | duk_size_t new_size; |
| 18862 | |
| 18863 | DUK_ASSERT(min_bytes / sizeof(duk_tval) * sizeof(duk_tval) == min_bytes); |
| 18864 | min_size = min_bytes / sizeof(duk_tval); /* from bytes to slots */ |
| 18865 | |
| 18866 | #if defined(DUK_USE_VALSTACK_GROW_SHIFT) |
| 18867 | /* New size is minimum size plus a proportional slack, e.g. shift of |
| 18868 | * 2 means a 25% slack. |
| 18869 | */ |
| 18870 | new_size = min_size + (min_size >> DUK_USE_VALSTACK_GROW_SHIFT); |
| 18871 | #else |
| 18872 | /* New size is tight with no slack. This is sometimes preferred in |
| 18873 | * low memory environments. |
| 18874 | */ |
| 18875 | new_size = min_size; |
| 18876 | #endif |
| 18877 | |
| 18878 | if (DUK_UNLIKELY(new_size > DUK_USE_VALSTACK_LIMIT || new_size < min_size /*wrap*/)) { |
| 18879 | /* Note: may be triggered even if minimal new_size would not reach the limit, |
| 18880 | * plan limit accordingly. |
| 18881 | */ |
| 18882 | if (throw_on_error) { |
| 18883 | DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT); |
| 18884 | DUK_WO_NORETURN(return 0;); |
| 18885 | } |
| 18886 | return 0; |
| 18887 | } |
| 18888 | |
| 18889 | if (duk__resize_valstack(thr, new_size) == 0) { |
| 18890 | if (throw_on_error) { |
| 18891 | DUK_ERROR_ALLOC_FAILED(thr); |
| 18892 | DUK_WO_NORETURN(return 0;); |
| 18893 | } |
| 18894 | return 0; |
| 18895 | } |
| 18896 | |
| 18897 | thr->valstack_end = thr->valstack + min_size; |
| 18898 | DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); |
| 18899 | |
| 18900 | return 1; |
| 18901 | } |
| 18902 | |
| 18903 | /* Hot, inlined value stack grow check. Because value stack almost never |
| 18904 | * grows, the actual resize call is in a NOINLINE helper. |
| 18905 | */ |
| 18906 | DUK_INTERNAL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes) { |
| 18907 | duk_tval *tv; |
| 18908 | |
| 18909 | tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes); |
| 18910 | if (DUK_LIKELY(thr->valstack_end >= tv)) { |
| 18911 | return; |
| 18912 | } |
| 18913 | if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) { |
| 18914 | /* Values in [valstack_top,valstack_alloc_end[ are initialized |
| 18915 | * to 'undefined' so we can just move the end pointer. |
| 18916 | */ |
| 18917 | thr->valstack_end = tv; |
| 18918 | return; |
| 18919 | } |
| 18920 | (void) duk__valstack_grow(thr, min_bytes, 1 /*throw_on_error*/); |
| 18921 | } |
| 18922 | |
| 18923 | /* Hot, inlined value stack grow check which doesn't throw. */ |
| 18924 | DUK_INTERNAL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes) { |
| 18925 | duk_tval *tv; |
| 18926 | |
| 18927 | tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes); |
| 18928 | if (DUK_LIKELY(thr->valstack_end >= tv)) { |
| 18929 | return 1; |
| 18930 | } |
| 18931 | if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) { |
| 18932 | thr->valstack_end = tv; |
| 18933 | return 1; |
| 18934 | } |
| 18935 | return duk__valstack_grow(thr, min_bytes, 0 /*throw_on_error*/); |
| 18936 | } |
| 18937 | |
| 18938 | /* Value stack shrink check, called from mark-and-sweep. */ |
| 18939 | DUK_INTERNAL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug) { |
| 18940 | duk_size_t alloc_bytes; |
| 18941 | duk_size_t reserve_bytes; |
| 18942 | duk_size_t shrink_bytes; |
| 18943 | |
| 18944 | alloc_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack); |
| 18945 | reserve_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); |
| 18946 | DUK_ASSERT(alloc_bytes >= reserve_bytes); |
| 18947 | |
| 18948 | /* We're free to shrink the value stack allocation down to |
| 18949 | * reserve_bytes but not more. If 'snug' (emergency GC) |
| 18950 | * shrink whatever we can. Otherwise only shrink if the new |
| 18951 | * size would be considerably smaller. |
| 18952 | */ |
| 18953 | |
| 18954 | #if defined(DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT) |
| 18955 | if (snug) { |
| 18956 | shrink_bytes = reserve_bytes; |
| 18957 | } else { |
| 18958 | duk_size_t proportion, slack; |
| 18959 | |
| 18960 | /* Require that value stack shrinks by at least X% of its |
| 18961 | * current size. For example, shift of 2 means at least |
| 18962 | * 25%. The proportion is computed as bytes and may not |
| 18963 | * be a multiple of sizeof(duk_tval); that's OK here. |
| 18964 | */ |
| 18965 | proportion = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT; |
| 18966 | if (alloc_bytes - reserve_bytes < proportion) { |
| 18967 | /* Too little would be freed, do nothing. */ |
| 18968 | return; |
| 18969 | } |
| 18970 | |
| 18971 | /* Keep a slack after shrinking. The slack is again a |
| 18972 | * proportion of the current size (the proportion should |
| 18973 | * of course be smaller than the check proportion above). |
| 18974 | */ |
| 18975 | #if defined(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT) |
| 18976 | DUK_ASSERT(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT > DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT); |
| 18977 | slack = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT; |
| 18978 | #else |
| 18979 | slack = 0; |
| 18980 | #endif |
| 18981 | shrink_bytes = reserve_bytes + |
| 18982 | slack / sizeof(duk_tval) * sizeof(duk_tval); /* multiple of duk_tval */ |
| 18983 | } |
| 18984 | #else /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */ |
| 18985 | /* Always snug, useful in some low memory environments. */ |
| 18986 | DUK_UNREF(snug); |
| 18987 | shrink_bytes = reserve_bytes; |
| 18988 | #endif /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */ |
| 18989 | |
| 18990 | DUK_D(DUK_DPRINT("valstack shrink check: alloc_bytes=%ld, reserve_bytes=%ld, shrink_bytes=%ld (unvalidated)" , |
| 18991 | (long) alloc_bytes, (long) reserve_bytes, (long) shrink_bytes)); |
| 18992 | DUK_ASSERT(shrink_bytes >= reserve_bytes); |
| 18993 | if (shrink_bytes >= alloc_bytes) { |
| 18994 | /* Skip if shrink target is same as current one (or higher, |
| 18995 | * though that shouldn't happen in practice). |
| 18996 | */ |
| 18997 | return; |
| 18998 | } |
| 18999 | DUK_ASSERT(shrink_bytes / sizeof(duk_tval) * sizeof(duk_tval) == shrink_bytes); |
| 19000 | |
| 19001 | DUK_D(DUK_DPRINT("valstack shrink check: decided to shrink, snug: %ld" , (long) snug)); |
| 19002 | |
| 19003 | duk__resize_valstack(thr, shrink_bytes / sizeof(duk_tval)); |
| 19004 | } |
| 19005 | |
| 19006 | DUK_EXTERNAL duk_bool_t duk_check_stack(duk_hthread *thr, duk_idx_t ) { |
| 19007 | duk_size_t min_new_bytes; |
| 19008 | |
| 19009 | DUK_ASSERT_API_ENTRY(thr); |
| 19010 | DUK_ASSERT(thr != NULL); |
| 19011 | |
| 19012 | if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) { |
| 19013 | if (extra < 0) { |
| 19014 | /* Clamping to zero makes the API more robust to calling code |
| 19015 | * calculation errors. |
| 19016 | */ |
| 19017 | extra = 0; |
| 19018 | } else { |
| 19019 | /* Cause grow check to fail without wrapping arithmetic. */ |
| 19020 | extra = DUK_USE_VALSTACK_LIMIT; |
| 19021 | } |
| 19022 | } |
| 19023 | |
| 19024 | min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) + |
| 19025 | sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA); |
| 19026 | return duk_valstack_grow_check_nothrow(thr, min_new_bytes); |
| 19027 | } |
| 19028 | |
| 19029 | DUK_EXTERNAL void duk_require_stack(duk_hthread *thr, duk_idx_t ) { |
| 19030 | duk_size_t min_new_bytes; |
| 19031 | |
| 19032 | DUK_ASSERT_API_ENTRY(thr); |
| 19033 | DUK_ASSERT(thr != NULL); |
| 19034 | |
| 19035 | if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) { |
| 19036 | if (extra < 0) { |
| 19037 | /* Clamping to zero makes the API more robust to calling code |
| 19038 | * calculation errors. |
| 19039 | */ |
| 19040 | extra = 0; |
| 19041 | } else { |
| 19042 | /* Cause grow check to fail without wrapping arithmetic. */ |
| 19043 | extra = DUK_USE_VALSTACK_LIMIT; |
| 19044 | } |
| 19045 | } |
| 19046 | |
| 19047 | min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) + |
| 19048 | sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA); |
| 19049 | duk_valstack_grow_check_throw(thr, min_new_bytes); |
| 19050 | } |
| 19051 | |
| 19052 | DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_hthread *thr, duk_idx_t top) { |
| 19053 | duk_size_t min_new_bytes; |
| 19054 | |
| 19055 | DUK_ASSERT_API_ENTRY(thr); |
| 19056 | |
| 19057 | if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) { |
| 19058 | if (top < 0) { |
| 19059 | /* Clamping to zero makes the API more robust to calling code |
| 19060 | * calculation errors. |
| 19061 | */ |
| 19062 | top = 0; |
| 19063 | } else { |
| 19064 | /* Cause grow check to fail without wrapping arithmetic. */ |
| 19065 | top = DUK_USE_VALSTACK_LIMIT; |
| 19066 | } |
| 19067 | } |
| 19068 | |
| 19069 | DUK_ASSERT(top >= 0); |
| 19070 | min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) + |
| 19071 | sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA); |
| 19072 | return duk_valstack_grow_check_nothrow(thr, min_new_bytes); |
| 19073 | } |
| 19074 | |
| 19075 | DUK_EXTERNAL void duk_require_stack_top(duk_hthread *thr, duk_idx_t top) { |
| 19076 | duk_size_t min_new_bytes; |
| 19077 | |
| 19078 | DUK_ASSERT_API_ENTRY(thr); |
| 19079 | |
| 19080 | if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) { |
| 19081 | if (top < 0) { |
| 19082 | /* Clamping to zero makes the API more robust to calling code |
| 19083 | * calculation errors. |
| 19084 | */ |
| 19085 | top = 0; |
| 19086 | } else { |
| 19087 | /* Cause grow check to fail without wrapping arithmetic. */ |
| 19088 | top = DUK_USE_VALSTACK_LIMIT; |
| 19089 | } |
| 19090 | } |
| 19091 | |
| 19092 | DUK_ASSERT(top >= 0); |
| 19093 | min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) + |
| 19094 | sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA); |
| 19095 | duk_valstack_grow_check_throw(thr, min_new_bytes); |
| 19096 | } |
| 19097 | |
| 19098 | /* |
| 19099 | * Basic stack manipulation: swap, dup, insert, replace, etc |
| 19100 | */ |
| 19101 | |
| 19102 | DUK_EXTERNAL void duk_swap(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { |
| 19103 | duk_tval *tv1; |
| 19104 | duk_tval *tv2; |
| 19105 | duk_tval tv_tmp; |
| 19106 | |
| 19107 | DUK_ASSERT_API_ENTRY(thr); |
| 19108 | |
| 19109 | tv1 = duk_require_tval(thr, idx1); |
| 19110 | DUK_ASSERT(tv1 != NULL); |
| 19111 | tv2 = duk_require_tval(thr, idx2); |
| 19112 | DUK_ASSERT(tv2 != NULL); |
| 19113 | |
| 19114 | /* If tv1==tv2 this is a NOP, no check is needed */ |
| 19115 | DUK_TVAL_SET_TVAL(&tv_tmp, tv1); |
| 19116 | DUK_TVAL_SET_TVAL(tv1, tv2); |
| 19117 | DUK_TVAL_SET_TVAL(tv2, &tv_tmp); |
| 19118 | } |
| 19119 | |
| 19120 | DUK_EXTERNAL void duk_swap_top(duk_hthread *thr, duk_idx_t idx) { |
| 19121 | DUK_ASSERT_API_ENTRY(thr); |
| 19122 | |
| 19123 | duk_swap(thr, idx, -1); |
| 19124 | } |
| 19125 | |
| 19126 | DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx) { |
| 19127 | duk_tval *tv_from; |
| 19128 | duk_tval *tv_to; |
| 19129 | |
| 19130 | DUK_ASSERT_API_ENTRY(thr); |
| 19131 | DUK__CHECK_SPACE(); |
| 19132 | |
| 19133 | tv_from = duk_require_tval(thr, from_idx); |
| 19134 | tv_to = thr->valstack_top++; |
| 19135 | DUK_ASSERT(tv_from != NULL); |
| 19136 | DUK_ASSERT(tv_to != NULL); |
| 19137 | DUK_TVAL_SET_TVAL(tv_to, tv_from); |
| 19138 | DUK_TVAL_INCREF(thr, tv_to); /* no side effects */ |
| 19139 | } |
| 19140 | |
| 19141 | DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) { |
| 19142 | #if defined(DUK_USE_PREFER_SIZE) |
| 19143 | duk_dup(thr, -1); |
| 19144 | #else |
| 19145 | duk_tval *tv_from; |
| 19146 | duk_tval *tv_to; |
| 19147 | |
| 19148 | DUK_ASSERT_API_ENTRY(thr); |
| 19149 | DUK__CHECK_SPACE(); |
| 19150 | |
| 19151 | if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) { |
| 19152 | DUK_ERROR_RANGE_INDEX(thr, -1); |
| 19153 | DUK_WO_NORETURN(return;); |
| 19154 | } |
| 19155 | tv_from = thr->valstack_top - 1; |
| 19156 | tv_to = thr->valstack_top++; |
| 19157 | DUK_ASSERT(tv_from != NULL); |
| 19158 | DUK_ASSERT(tv_to != NULL); |
| 19159 | DUK_TVAL_SET_TVAL(tv_to, tv_from); |
| 19160 | DUK_TVAL_INCREF(thr, tv_to); /* no side effects */ |
| 19161 | #endif |
| 19162 | } |
| 19163 | |
| 19164 | DUK_INTERNAL void duk_dup_0(duk_hthread *thr) { |
| 19165 | DUK_ASSERT_API_ENTRY(thr); |
| 19166 | duk_dup(thr, 0); |
| 19167 | } |
| 19168 | DUK_INTERNAL void duk_dup_1(duk_hthread *thr) { |
| 19169 | DUK_ASSERT_API_ENTRY(thr); |
| 19170 | duk_dup(thr, 1); |
| 19171 | } |
| 19172 | DUK_INTERNAL void duk_dup_2(duk_hthread *thr) { |
| 19173 | DUK_ASSERT_API_ENTRY(thr); |
| 19174 | duk_dup(thr, 2); |
| 19175 | } |
| 19176 | DUK_INTERNAL void duk_dup_m2(duk_hthread *thr) { |
| 19177 | DUK_ASSERT_API_ENTRY(thr); |
| 19178 | duk_dup(thr, -2); |
| 19179 | } |
| 19180 | DUK_INTERNAL void duk_dup_m3(duk_hthread *thr) { |
| 19181 | DUK_ASSERT_API_ENTRY(thr); |
| 19182 | duk_dup(thr, -3); |
| 19183 | } |
| 19184 | DUK_INTERNAL void duk_dup_m4(duk_hthread *thr) { |
| 19185 | DUK_ASSERT_API_ENTRY(thr); |
| 19186 | duk_dup(thr, -4); |
| 19187 | } |
| 19188 | |
| 19189 | DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) { |
| 19190 | duk_tval *p; |
| 19191 | duk_tval *q; |
| 19192 | duk_tval tv_tmp; |
| 19193 | duk_size_t nbytes; |
| 19194 | |
| 19195 | DUK_ASSERT_API_ENTRY(thr); |
| 19196 | |
| 19197 | p = duk_require_tval(thr, to_idx); |
| 19198 | DUK_ASSERT(p != NULL); |
| 19199 | q = duk_require_tval(thr, -1); |
| 19200 | DUK_ASSERT(q != NULL); |
| 19201 | |
| 19202 | DUK_ASSERT(q >= p); |
| 19203 | |
| 19204 | /* nbytes |
| 19205 | * <---------> |
| 19206 | * [ ... | p | x | x | q ] |
| 19207 | * => [ ... | q | p | x | x ] |
| 19208 | */ |
| 19209 | |
| 19210 | nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); |
| 19211 | |
| 19212 | DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu" , |
| 19213 | (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes)); |
| 19214 | |
| 19215 | /* No net refcount changes. No need to special case nbytes == 0 |
| 19216 | * (p == q). |
| 19217 | */ |
| 19218 | DUK_TVAL_SET_TVAL(&tv_tmp, q); |
| 19219 | duk_memmove((void *) (p + 1), (const void *) p, (size_t) nbytes); |
| 19220 | DUK_TVAL_SET_TVAL(p, &tv_tmp); |
| 19221 | } |
| 19222 | |
| 19223 | DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) { |
| 19224 | DUK_ASSERT_API_ENTRY(thr); |
| 19225 | DUK_ASSERT(idx >= 0); /* Doesn't support negative indices. */ |
| 19226 | |
| 19227 | duk_push_undefined(thr); |
| 19228 | duk_insert(thr, idx); |
| 19229 | } |
| 19230 | |
| 19231 | DUK_INTERNAL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) { |
| 19232 | duk_tval *tv, *tv_end; |
| 19233 | |
| 19234 | DUK_ASSERT_API_ENTRY(thr); |
| 19235 | DUK_ASSERT(idx >= 0); /* Doesn't support negative indices or count. */ |
| 19236 | DUK_ASSERT(count >= 0); |
| 19237 | |
| 19238 | tv = duk_reserve_gap(thr, idx, count); |
| 19239 | tv_end = tv + count; |
| 19240 | while (tv != tv_end) { |
| 19241 | DUK_TVAL_SET_UNDEFINED(tv); |
| 19242 | tv++; |
| 19243 | } |
| 19244 | } |
| 19245 | |
| 19246 | DUK_EXTERNAL void duk_pull(duk_hthread *thr, duk_idx_t from_idx) { |
| 19247 | duk_tval *p; |
| 19248 | duk_tval *q; |
| 19249 | duk_tval tv_tmp; |
| 19250 | duk_size_t nbytes; |
| 19251 | |
| 19252 | DUK_ASSERT_API_ENTRY(thr); |
| 19253 | |
| 19254 | /* nbytes |
| 19255 | * <---------> |
| 19256 | * [ ... | x | x | p | y | y | q ] |
| 19257 | * => [ ... | x | x | y | y | q | p ] |
| 19258 | */ |
| 19259 | |
| 19260 | p = duk_require_tval(thr, from_idx); |
| 19261 | DUK_ASSERT(p != NULL); |
| 19262 | q = duk_require_tval(thr, -1); |
| 19263 | DUK_ASSERT(q != NULL); |
| 19264 | |
| 19265 | DUK_ASSERT(q >= p); |
| 19266 | |
| 19267 | nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); |
| 19268 | |
| 19269 | DUK_DDD(DUK_DDDPRINT("duk_pull: from_idx=%ld, p=%p, q=%p, nbytes=%lu" , |
| 19270 | (long) from_idx, (void *) p, (void *) q, (unsigned long) nbytes)); |
| 19271 | |
| 19272 | /* No net refcount changes. No need to special case nbytes == 0 |
| 19273 | * (p == q). |
| 19274 | */ |
| 19275 | DUK_TVAL_SET_TVAL(&tv_tmp, p); |
| 19276 | duk_memmove((void *) p, (const void *) (p + 1), (size_t) nbytes); |
| 19277 | DUK_TVAL_SET_TVAL(q, &tv_tmp); |
| 19278 | } |
| 19279 | |
| 19280 | DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx) { |
| 19281 | duk_tval *tv1; |
| 19282 | duk_tval *tv2; |
| 19283 | duk_tval tv_tmp; |
| 19284 | |
| 19285 | DUK_ASSERT_API_ENTRY(thr); |
| 19286 | |
| 19287 | tv1 = duk_require_tval(thr, -1); |
| 19288 | DUK_ASSERT(tv1 != NULL); |
| 19289 | tv2 = duk_require_tval(thr, to_idx); |
| 19290 | DUK_ASSERT(tv2 != NULL); |
| 19291 | |
| 19292 | /* For tv1 == tv2, both pointing to stack top, the end result |
| 19293 | * is same as duk_pop(thr). |
| 19294 | */ |
| 19295 | DUK_TVAL_SET_TVAL(&tv_tmp, tv2); |
| 19296 | DUK_TVAL_SET_TVAL(tv2, tv1); |
| 19297 | DUK_TVAL_SET_UNDEFINED(tv1); |
| 19298 | thr->valstack_top--; |
| 19299 | DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ |
| 19300 | } |
| 19301 | |
| 19302 | DUK_EXTERNAL void duk_copy(duk_hthread *thr, duk_idx_t from_idx, duk_idx_t to_idx) { |
| 19303 | duk_tval *tv1; |
| 19304 | duk_tval *tv2; |
| 19305 | |
| 19306 | DUK_ASSERT_API_ENTRY(thr); |
| 19307 | |
| 19308 | tv1 = duk_require_tval(thr, from_idx); |
| 19309 | DUK_ASSERT(tv1 != NULL); |
| 19310 | tv2 = duk_require_tval(thr, to_idx); |
| 19311 | DUK_ASSERT(tv2 != NULL); |
| 19312 | |
| 19313 | /* For tv1 == tv2, this is a no-op (no explicit check needed). */ |
| 19314 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */ |
| 19315 | } |
| 19316 | |
| 19317 | DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) { |
| 19318 | duk_tval *p; |
| 19319 | duk_tval *q; |
| 19320 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 19321 | duk_tval tv_tmp; |
| 19322 | #endif |
| 19323 | duk_size_t nbytes; |
| 19324 | |
| 19325 | DUK_ASSERT_API_ENTRY(thr); |
| 19326 | |
| 19327 | p = duk_require_tval(thr, idx); |
| 19328 | DUK_ASSERT(p != NULL); |
| 19329 | q = duk_require_tval(thr, -1); |
| 19330 | DUK_ASSERT(q != NULL); |
| 19331 | |
| 19332 | DUK_ASSERT(q >= p); |
| 19333 | |
| 19334 | /* nbytes zero size case |
| 19335 | * <---------> |
| 19336 | * [ ... | p | x | x | q ] [ ... | p==q ] |
| 19337 | * => [ ... | x | x | q ] [ ... ] |
| 19338 | */ |
| 19339 | |
| 19340 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 19341 | /* use a temp: decref only when valstack reachable values are correct */ |
| 19342 | DUK_TVAL_SET_TVAL(&tv_tmp, p); |
| 19343 | #endif |
| 19344 | |
| 19345 | nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */ |
| 19346 | duk_memmove((void *) p, (const void *) (p + 1), (size_t) nbytes); |
| 19347 | |
| 19348 | DUK_TVAL_SET_UNDEFINED(q); |
| 19349 | thr->valstack_top--; |
| 19350 | |
| 19351 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 19352 | DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ |
| 19353 | #endif |
| 19354 | } |
| 19355 | |
| 19356 | DUK_INTERNAL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx) { |
| 19357 | DUK_ASSERT_API_ENTRY(thr); |
| 19358 | |
| 19359 | duk_remove(thr, idx); /* XXX: no optimization for now */ |
| 19360 | } |
| 19361 | |
| 19362 | DUK_INTERNAL void duk_remove_m2(duk_hthread *thr) { |
| 19363 | DUK_ASSERT_API_ENTRY(thr); |
| 19364 | |
| 19365 | duk_remove(thr, -2); |
| 19366 | } |
| 19367 | |
| 19368 | DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) { |
| 19369 | #if defined(DUK_USE_PREFER_SIZE) |
| 19370 | /* XXX: maybe too slow even when preferring size? */ |
| 19371 | DUK_ASSERT_API_ENTRY(thr); |
| 19372 | DUK_ASSERT(count >= 0); |
| 19373 | DUK_ASSERT(idx >= 0); |
| 19374 | |
| 19375 | while (count-- > 0) { |
| 19376 | duk_remove(thr, idx); |
| 19377 | } |
| 19378 | #else /* DUK_USE_PREFER_SIZE */ |
| 19379 | duk_tval *tv_src; |
| 19380 | duk_tval *tv_dst; |
| 19381 | duk_tval *tv_newtop; |
| 19382 | duk_tval *tv; |
| 19383 | duk_size_t bytes; |
| 19384 | |
| 19385 | DUK_ASSERT_API_ENTRY(thr); |
| 19386 | DUK_ASSERT(count >= 0); |
| 19387 | DUK_ASSERT(idx >= 0); |
| 19388 | |
| 19389 | tv_dst = thr->valstack_bottom + idx; |
| 19390 | DUK_ASSERT(tv_dst <= thr->valstack_top); |
| 19391 | tv_src = tv_dst + count; |
| 19392 | DUK_ASSERT(tv_src <= thr->valstack_top); |
| 19393 | bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src); |
| 19394 | |
| 19395 | for (tv = tv_dst; tv < tv_src; tv++) { |
| 19396 | DUK_TVAL_DECREF_NORZ(thr, tv); |
| 19397 | } |
| 19398 | |
| 19399 | duk_memmove((void *) tv_dst, (const void *) tv_src, bytes); |
| 19400 | |
| 19401 | tv_newtop = thr->valstack_top - count; |
| 19402 | for (tv = tv_newtop; tv < thr->valstack_top; tv++) { |
| 19403 | DUK_TVAL_SET_UNDEFINED(tv); |
| 19404 | } |
| 19405 | thr->valstack_top = tv_newtop; |
| 19406 | |
| 19407 | /* When not preferring size, only NORZ macros are used; caller |
| 19408 | * is expected to DUK_REFZERO_CHECK(). |
| 19409 | */ |
| 19410 | #endif /* DUK_USE_PREFER_SIZE */ |
| 19411 | } |
| 19412 | |
| 19413 | DUK_INTERNAL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) { |
| 19414 | DUK_ASSERT_API_ENTRY(thr); |
| 19415 | |
| 19416 | duk_remove_n(thr, idx, count); /* XXX: no optimization for now */ |
| 19417 | } |
| 19418 | |
| 19419 | /* |
| 19420 | * Stack slice primitives |
| 19421 | */ |
| 19422 | |
| 19423 | DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, duk_idx_t count, duk_bool_t is_copy) { |
| 19424 | void *src; |
| 19425 | duk_size_t nbytes; |
| 19426 | duk_tval *p; |
| 19427 | duk_tval *q; |
| 19428 | |
| 19429 | /* XXX: several pointer comparison issues here */ |
| 19430 | |
| 19431 | DUK_ASSERT_API_ENTRY(to_thr); |
| 19432 | DUK_CTX_ASSERT_VALID(to_thr); |
| 19433 | DUK_CTX_ASSERT_VALID(from_thr); |
| 19434 | DUK_ASSERT(to_thr->heap == from_thr->heap); |
| 19435 | |
| 19436 | if (DUK_UNLIKELY(to_thr == from_thr)) { |
| 19437 | DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT); |
| 19438 | DUK_WO_NORETURN(return;); |
| 19439 | } |
| 19440 | if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) { |
| 19441 | /* Maximum value check ensures 'nbytes' won't wrap below. |
| 19442 | * Also handles negative count. |
| 19443 | */ |
| 19444 | DUK_ERROR_RANGE_INVALID_COUNT(to_thr); |
| 19445 | DUK_WO_NORETURN(return;); |
| 19446 | } |
| 19447 | DUK_ASSERT(count >= 0); |
| 19448 | |
| 19449 | nbytes = sizeof(duk_tval) * (duk_size_t) count; |
| 19450 | if (DUK_UNLIKELY(nbytes == 0)) { |
| 19451 | return; |
| 19452 | } |
| 19453 | DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end); |
| 19454 | if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) { |
| 19455 | DUK_ERROR_RANGE_PUSH_BEYOND(to_thr); |
| 19456 | DUK_WO_NORETURN(return;); |
| 19457 | } |
| 19458 | src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes); |
| 19459 | if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) { |
| 19460 | DUK_ERROR_RANGE_INVALID_COUNT(to_thr); |
| 19461 | DUK_WO_NORETURN(return;); |
| 19462 | } |
| 19463 | |
| 19464 | /* Copy values (no overlap even if to_thr == from_thr; that's not |
| 19465 | * allowed now anyway). |
| 19466 | */ |
| 19467 | DUK_ASSERT(nbytes > 0); |
| 19468 | duk_memcpy((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes); |
| 19469 | |
| 19470 | p = to_thr->valstack_top; |
| 19471 | to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes); |
| 19472 | |
| 19473 | if (is_copy) { |
| 19474 | /* Incref copies, keep originals. */ |
| 19475 | q = to_thr->valstack_top; |
| 19476 | while (p < q) { |
| 19477 | DUK_TVAL_INCREF(to_thr, p); /* no side effects */ |
| 19478 | p++; |
| 19479 | } |
| 19480 | } else { |
| 19481 | /* No net refcount change. */ |
| 19482 | p = from_thr->valstack_top; |
| 19483 | q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes); |
| 19484 | from_thr->valstack_top = q; |
| 19485 | |
| 19486 | while (p > q) { |
| 19487 | p--; |
| 19488 | DUK_TVAL_SET_UNDEFINED(p); |
| 19489 | /* XXX: fast primitive to set a bunch of values to UNDEFINED */ |
| 19490 | } |
| 19491 | } |
| 19492 | } |
| 19493 | |
| 19494 | /* Internal helper: reserve a gap of 'count' elements at 'idx_base' and return a |
| 19495 | * pointer to the gap. Values in the gap are garbage and MUST be initialized by |
| 19496 | * the caller before any side effects may occur. The caller must ensure there's |
| 19497 | * enough stack reserve for 'count' values. |
| 19498 | */ |
| 19499 | DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count) { |
| 19500 | duk_tval *tv_src; |
| 19501 | duk_tval *tv_dst; |
| 19502 | duk_size_t gap_bytes; |
| 19503 | duk_size_t copy_bytes; |
| 19504 | |
| 19505 | /* Caller is responsible for ensuring there's enough preallocated |
| 19506 | * value stack. |
| 19507 | */ |
| 19508 | DUK_ASSERT_API_ENTRY(thr); |
| 19509 | DUK_ASSERT(count >= 0); |
| 19510 | DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack_top) >= (duk_size_t) count); |
| 19511 | |
| 19512 | tv_src = thr->valstack_bottom + idx_base; |
| 19513 | gap_bytes = (duk_size_t) count * sizeof(duk_tval); |
| 19514 | tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes); |
| 19515 | copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src); |
| 19516 | thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes); |
| 19517 | duk_memmove((void *) tv_dst, (const void *) tv_src, copy_bytes); |
| 19518 | |
| 19519 | /* Values in the gap are left as garbage: caller must fill them in |
| 19520 | * and INCREF them before any side effects. |
| 19521 | */ |
| 19522 | return tv_src; |
| 19523 | } |
| 19524 | |
| 19525 | /* |
| 19526 | * Get/opt/require |
| 19527 | */ |
| 19528 | |
| 19529 | DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) { |
| 19530 | duk_tval *tv; |
| 19531 | |
| 19532 | DUK_ASSERT_API_ENTRY(thr); |
| 19533 | |
| 19534 | tv = duk_get_tval_or_unused(thr, idx); |
| 19535 | DUK_ASSERT(tv != NULL); |
| 19536 | if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) { |
| 19537 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined" , DUK_STR_NOT_UNDEFINED); |
| 19538 | DUK_WO_NORETURN(return;); |
| 19539 | } |
| 19540 | } |
| 19541 | |
| 19542 | DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) { |
| 19543 | duk_tval *tv; |
| 19544 | |
| 19545 | DUK_ASSERT_API_ENTRY(thr); |
| 19546 | |
| 19547 | tv = duk_get_tval_or_unused(thr, idx); |
| 19548 | DUK_ASSERT(tv != NULL); |
| 19549 | if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) { |
| 19550 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null" , DUK_STR_NOT_NULL); |
| 19551 | DUK_WO_NORETURN(return;); |
| 19552 | } |
| 19553 | } |
| 19554 | |
| 19555 | DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) { |
| 19556 | duk_bool_t ret; |
| 19557 | duk_tval *tv; |
| 19558 | |
| 19559 | DUK_CTX_ASSERT_VALID(thr); |
| 19560 | |
| 19561 | tv = duk_get_tval_or_unused(thr, idx); |
| 19562 | DUK_ASSERT(tv != NULL); |
| 19563 | if (DUK_TVAL_IS_BOOLEAN(tv)) { |
| 19564 | ret = DUK_TVAL_GET_BOOLEAN(tv); |
| 19565 | DUK_ASSERT(ret == 0 || ret == 1); |
| 19566 | } else { |
| 19567 | ret = def_value; |
| 19568 | /* Not guaranteed to be 0 or 1. */ |
| 19569 | } |
| 19570 | |
| 19571 | return ret; |
| 19572 | } |
| 19573 | |
| 19574 | DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx) { |
| 19575 | DUK_ASSERT_API_ENTRY(thr); |
| 19576 | |
| 19577 | return duk__get_boolean_raw(thr, idx, 0); /* default: false */ |
| 19578 | } |
| 19579 | |
| 19580 | DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) { |
| 19581 | DUK_ASSERT_API_ENTRY(thr); |
| 19582 | |
| 19583 | return duk__get_boolean_raw(thr, idx, def_value); |
| 19584 | } |
| 19585 | |
| 19586 | DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) { |
| 19587 | duk_tval *tv; |
| 19588 | duk_bool_t ret; |
| 19589 | |
| 19590 | DUK_ASSERT_API_ENTRY(thr); |
| 19591 | |
| 19592 | tv = duk_get_tval_or_unused(thr, idx); |
| 19593 | DUK_ASSERT(tv != NULL); |
| 19594 | if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) { |
| 19595 | ret = DUK_TVAL_GET_BOOLEAN(tv); |
| 19596 | DUK_ASSERT(ret == 0 || ret == 1); |
| 19597 | return ret; |
| 19598 | } else { |
| 19599 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean" , DUK_STR_NOT_BOOLEAN); |
| 19600 | DUK_WO_NORETURN(return 0;); |
| 19601 | } |
| 19602 | } |
| 19603 | |
| 19604 | DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) { |
| 19605 | DUK_ASSERT_API_ENTRY(thr); |
| 19606 | |
| 19607 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 19608 | return def_value; |
| 19609 | } |
| 19610 | return duk_require_boolean(thr, idx); |
| 19611 | } |
| 19612 | |
| 19613 | DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) { |
| 19614 | duk_double_union ret; |
| 19615 | duk_tval *tv; |
| 19616 | |
| 19617 | DUK_CTX_ASSERT_VALID(thr); |
| 19618 | |
| 19619 | tv = duk_get_tval_or_unused(thr, idx); |
| 19620 | DUK_ASSERT(tv != NULL); |
| 19621 | #if defined(DUK_USE_FASTINT) |
| 19622 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 19623 | ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv); /* XXX: cast trick */ |
| 19624 | } |
| 19625 | else |
| 19626 | #endif |
| 19627 | if (DUK_TVAL_IS_DOUBLE(tv)) { |
| 19628 | /* When using packed duk_tval, number must be in NaN-normalized form |
| 19629 | * for it to be a duk_tval, so no need to normalize. NOP for unpacked |
| 19630 | * duk_tval. |
| 19631 | */ |
| 19632 | ret.d = DUK_TVAL_GET_DOUBLE(tv); |
| 19633 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); |
| 19634 | } else { |
| 19635 | ret.d = def_value; |
| 19636 | /* Default value (including NaN) may not be normalized. */ |
| 19637 | } |
| 19638 | |
| 19639 | return ret.d; |
| 19640 | } |
| 19641 | |
| 19642 | DUK_EXTERNAL duk_double_t duk_get_number(duk_hthread *thr, duk_idx_t idx) { |
| 19643 | DUK_ASSERT_API_ENTRY(thr); |
| 19644 | return duk__get_number_raw(thr, idx, DUK_DOUBLE_NAN); /* default: NaN */ |
| 19645 | } |
| 19646 | |
| 19647 | DUK_EXTERNAL duk_double_t duk_get_number_default(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) { |
| 19648 | DUK_ASSERT_API_ENTRY(thr); |
| 19649 | return duk__get_number_raw(thr, idx, def_value); |
| 19650 | } |
| 19651 | |
| 19652 | DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) { |
| 19653 | duk_tval *tv; |
| 19654 | duk_double_union ret; |
| 19655 | |
| 19656 | DUK_ASSERT_API_ENTRY(thr); |
| 19657 | |
| 19658 | tv = duk_get_tval_or_unused(thr, idx); |
| 19659 | DUK_ASSERT(tv != NULL); |
| 19660 | if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) { |
| 19661 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number" , DUK_STR_NOT_NUMBER); |
| 19662 | DUK_WO_NORETURN(return 0.0;); |
| 19663 | } |
| 19664 | |
| 19665 | ret.d = DUK_TVAL_GET_NUMBER(tv); |
| 19666 | |
| 19667 | /* When using packed duk_tval, number must be in NaN-normalized form |
| 19668 | * for it to be a duk_tval, so no need to normalize. NOP for unpacked |
| 19669 | * duk_tval. |
| 19670 | */ |
| 19671 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret)); |
| 19672 | return ret.d; |
| 19673 | } |
| 19674 | |
| 19675 | DUK_EXTERNAL duk_double_t duk_opt_number(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) { |
| 19676 | DUK_ASSERT_API_ENTRY(thr); |
| 19677 | |
| 19678 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 19679 | /* User provided default is not NaN normalized. */ |
| 19680 | return def_value; |
| 19681 | } |
| 19682 | return duk_require_number(thr, idx); |
| 19683 | } |
| 19684 | |
| 19685 | DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx) { |
| 19686 | DUK_ASSERT_API_ENTRY(thr); |
| 19687 | |
| 19688 | return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/); |
| 19689 | } |
| 19690 | |
| 19691 | DUK_EXTERNAL duk_uint_t duk_get_uint(duk_hthread *thr, duk_idx_t idx) { |
| 19692 | DUK_ASSERT_API_ENTRY(thr); |
| 19693 | |
| 19694 | return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/); |
| 19695 | } |
| 19696 | |
| 19697 | DUK_EXTERNAL duk_int_t duk_get_int_default(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) { |
| 19698 | DUK_ASSERT_API_ENTRY(thr); |
| 19699 | |
| 19700 | return (duk_int_t) duk__api_coerce_d2i(thr, idx, def_value, 0 /*require*/); |
| 19701 | } |
| 19702 | |
| 19703 | DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) { |
| 19704 | DUK_ASSERT_API_ENTRY(thr); |
| 19705 | |
| 19706 | return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, def_value, 0 /*require*/); |
| 19707 | } |
| 19708 | |
| 19709 | DUK_EXTERNAL duk_int_t duk_require_int(duk_hthread *thr, duk_idx_t idx) { |
| 19710 | DUK_ASSERT_API_ENTRY(thr); |
| 19711 | |
| 19712 | return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 1 /*require*/); |
| 19713 | } |
| 19714 | |
| 19715 | DUK_EXTERNAL duk_uint_t duk_require_uint(duk_hthread *thr, duk_idx_t idx) { |
| 19716 | DUK_ASSERT_API_ENTRY(thr); |
| 19717 | |
| 19718 | return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 1 /*require*/); |
| 19719 | } |
| 19720 | |
| 19721 | DUK_EXTERNAL duk_int_t duk_opt_int(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) { |
| 19722 | DUK_ASSERT_API_ENTRY(thr); |
| 19723 | |
| 19724 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 19725 | return def_value; |
| 19726 | } |
| 19727 | return duk_require_int(thr, idx); |
| 19728 | } |
| 19729 | |
| 19730 | DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) { |
| 19731 | DUK_ASSERT_API_ENTRY(thr); |
| 19732 | |
| 19733 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 19734 | return def_value; |
| 19735 | } |
| 19736 | return duk_require_uint(thr, idx); |
| 19737 | } |
| 19738 | |
| 19739 | DUK_EXTERNAL const char *duk_get_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { |
| 19740 | duk_hstring *h; |
| 19741 | const char *ret; |
| 19742 | duk_size_t len; |
| 19743 | |
| 19744 | DUK_ASSERT_API_ENTRY(thr); |
| 19745 | |
| 19746 | h = duk_get_hstring(thr, idx); |
| 19747 | if (h != NULL) { |
| 19748 | len = DUK_HSTRING_GET_BYTELEN(h); |
| 19749 | ret = (const char *) DUK_HSTRING_GET_DATA(h); |
| 19750 | } else { |
| 19751 | len = 0; |
| 19752 | ret = NULL; |
| 19753 | } |
| 19754 | |
| 19755 | if (out_len != NULL) { |
| 19756 | *out_len = len; |
| 19757 | } |
| 19758 | return ret; |
| 19759 | } |
| 19760 | |
| 19761 | DUK_EXTERNAL const char *duk_require_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { |
| 19762 | duk_hstring *h; |
| 19763 | |
| 19764 | DUK_ASSERT_API_ENTRY(thr); |
| 19765 | |
| 19766 | h = duk_require_hstring(thr, idx); |
| 19767 | DUK_ASSERT(h != NULL); |
| 19768 | if (out_len) { |
| 19769 | *out_len = DUK_HSTRING_GET_BYTELEN(h); |
| 19770 | } |
| 19771 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 19772 | } |
| 19773 | |
| 19774 | DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { |
| 19775 | duk_hstring *h; |
| 19776 | |
| 19777 | DUK_ASSERT_API_ENTRY(thr); |
| 19778 | |
| 19779 | h = duk_require_hstring_notsymbol(thr, idx); |
| 19780 | DUK_ASSERT(h != NULL); |
| 19781 | if (out_len) { |
| 19782 | *out_len = DUK_HSTRING_GET_BYTELEN(h); |
| 19783 | } |
| 19784 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 19785 | } |
| 19786 | |
| 19787 | DUK_EXTERNAL const char *duk_get_string(duk_hthread *thr, duk_idx_t idx) { |
| 19788 | duk_hstring *h; |
| 19789 | |
| 19790 | DUK_ASSERT_API_ENTRY(thr); |
| 19791 | |
| 19792 | h = duk_get_hstring(thr, idx); |
| 19793 | if (h != NULL) { |
| 19794 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 19795 | } else { |
| 19796 | return NULL; |
| 19797 | } |
| 19798 | } |
| 19799 | |
| 19800 | DUK_EXTERNAL const char *duk_opt_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { |
| 19801 | DUK_ASSERT_API_ENTRY(thr); |
| 19802 | |
| 19803 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 19804 | if (out_len != NULL) { |
| 19805 | *out_len = def_len; |
| 19806 | } |
| 19807 | return def_ptr; |
| 19808 | } |
| 19809 | return duk_require_lstring(thr, idx, out_len); |
| 19810 | } |
| 19811 | |
| 19812 | DUK_EXTERNAL const char *duk_opt_string(duk_hthread *thr, duk_idx_t idx, const char *def_ptr) { |
| 19813 | DUK_ASSERT_API_ENTRY(thr); |
| 19814 | |
| 19815 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 19816 | return def_ptr; |
| 19817 | } |
| 19818 | return duk_require_string(thr, idx); |
| 19819 | } |
| 19820 | |
| 19821 | DUK_EXTERNAL const char *duk_get_lstring_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len, const char *def_ptr, duk_size_t def_len) { |
| 19822 | duk_hstring *h; |
| 19823 | const char *ret; |
| 19824 | duk_size_t len; |
| 19825 | |
| 19826 | DUK_ASSERT_API_ENTRY(thr); |
| 19827 | |
| 19828 | h = duk_get_hstring(thr, idx); |
| 19829 | if (h != NULL) { |
| 19830 | len = DUK_HSTRING_GET_BYTELEN(h); |
| 19831 | ret = (const char *) DUK_HSTRING_GET_DATA(h); |
| 19832 | } else { |
| 19833 | len = def_len; |
| 19834 | ret = def_ptr; |
| 19835 | } |
| 19836 | |
| 19837 | if (out_len != NULL) { |
| 19838 | *out_len = len; |
| 19839 | } |
| 19840 | return ret; |
| 19841 | } |
| 19842 | |
| 19843 | DUK_EXTERNAL const char *duk_get_string_default(duk_hthread *thr, duk_idx_t idx, const char *def_value) { |
| 19844 | duk_hstring *h; |
| 19845 | |
| 19846 | DUK_ASSERT_API_ENTRY(thr); |
| 19847 | |
| 19848 | h = duk_get_hstring(thr, idx); |
| 19849 | if (h != NULL) { |
| 19850 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 19851 | } else { |
| 19852 | return def_value; |
| 19853 | } |
| 19854 | } |
| 19855 | |
| 19856 | DUK_INTERNAL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx) { |
| 19857 | duk_hstring *h; |
| 19858 | |
| 19859 | DUK_ASSERT_API_ENTRY(thr); |
| 19860 | |
| 19861 | h = duk_get_hstring_notsymbol(thr, idx); |
| 19862 | if (h) { |
| 19863 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 19864 | } else { |
| 19865 | return NULL; |
| 19866 | } |
| 19867 | } |
| 19868 | |
| 19869 | DUK_EXTERNAL const char *duk_require_string(duk_hthread *thr, duk_idx_t idx) { |
| 19870 | DUK_ASSERT_API_ENTRY(thr); |
| 19871 | |
| 19872 | return duk_require_lstring(thr, idx, NULL); |
| 19873 | } |
| 19874 | |
| 19875 | DUK_INTERNAL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx) { |
| 19876 | duk_hstring *h; |
| 19877 | |
| 19878 | DUK_ASSERT_API_ENTRY(thr); |
| 19879 | |
| 19880 | h = duk_require_hstring_notsymbol(thr, idx); |
| 19881 | DUK_ASSERT(h != NULL); |
| 19882 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 19883 | } |
| 19884 | |
| 19885 | DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) { |
| 19886 | duk_tval *tv; |
| 19887 | |
| 19888 | DUK_ASSERT_API_ENTRY(thr); |
| 19889 | |
| 19890 | tv = duk_get_tval_or_unused(thr, idx); |
| 19891 | DUK_ASSERT(tv != NULL); |
| 19892 | if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { |
| 19893 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object" , DUK_STR_NOT_OBJECT); |
| 19894 | DUK_WO_NORETURN(return;); |
| 19895 | } |
| 19896 | } |
| 19897 | |
| 19898 | DUK_LOCAL void *duk__get_pointer_raw(duk_hthread *thr, duk_idx_t idx, void *def_value) { |
| 19899 | duk_tval *tv; |
| 19900 | void *p; |
| 19901 | |
| 19902 | DUK_CTX_ASSERT_VALID(thr); |
| 19903 | |
| 19904 | tv = duk_get_tval_or_unused(thr, idx); |
| 19905 | DUK_ASSERT(tv != NULL); |
| 19906 | if (!DUK_TVAL_IS_POINTER(tv)) { |
| 19907 | return def_value; |
| 19908 | } |
| 19909 | |
| 19910 | p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ |
| 19911 | return p; |
| 19912 | } |
| 19913 | |
| 19914 | DUK_EXTERNAL void *duk_get_pointer(duk_hthread *thr, duk_idx_t idx) { |
| 19915 | DUK_ASSERT_API_ENTRY(thr); |
| 19916 | return duk__get_pointer_raw(thr, idx, NULL /*def_value*/); |
| 19917 | } |
| 19918 | |
| 19919 | DUK_EXTERNAL void *duk_opt_pointer(duk_hthread *thr, duk_idx_t idx, void *def_value) { |
| 19920 | DUK_ASSERT_API_ENTRY(thr); |
| 19921 | |
| 19922 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 19923 | return def_value; |
| 19924 | } |
| 19925 | return duk_require_pointer(thr, idx); |
| 19926 | } |
| 19927 | |
| 19928 | DUK_EXTERNAL void *duk_get_pointer_default(duk_hthread *thr, duk_idx_t idx, void *def_value) { |
| 19929 | DUK_ASSERT_API_ENTRY(thr); |
| 19930 | return duk__get_pointer_raw(thr, idx, def_value); |
| 19931 | } |
| 19932 | |
| 19933 | DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) { |
| 19934 | duk_tval *tv; |
| 19935 | void *p; |
| 19936 | |
| 19937 | DUK_ASSERT_API_ENTRY(thr); |
| 19938 | |
| 19939 | /* Note: here we must be wary of the fact that a pointer may be |
| 19940 | * valid and be a NULL. |
| 19941 | */ |
| 19942 | tv = duk_get_tval_or_unused(thr, idx); |
| 19943 | DUK_ASSERT(tv != NULL); |
| 19944 | if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) { |
| 19945 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer" , DUK_STR_NOT_POINTER); |
| 19946 | DUK_WO_NORETURN(return NULL;); |
| 19947 | } |
| 19948 | p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */ |
| 19949 | return p; |
| 19950 | } |
| 19951 | |
| 19952 | #if 0 /*unused*/ |
| 19953 | DUK_INTERNAL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx) { |
| 19954 | duk_tval *tv; |
| 19955 | duk_heaphdr *h; |
| 19956 | |
| 19957 | DUK_ASSERT_API_ENTRY(thr); |
| 19958 | |
| 19959 | tv = duk_get_tval_or_unused(thr, idx); |
| 19960 | DUK_ASSERT(tv != NULL); |
| 19961 | if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { |
| 19962 | return NULL; |
| 19963 | } |
| 19964 | |
| 19965 | h = DUK_TVAL_GET_HEAPHDR(tv); |
| 19966 | DUK_ASSERT(h != NULL); |
| 19967 | return (void *) h; |
| 19968 | } |
| 19969 | #endif |
| 19970 | |
| 19971 | DUK_LOCAL void *duk__get_buffer_helper(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag) { |
| 19972 | duk_hbuffer *h; |
| 19973 | void *ret; |
| 19974 | duk_size_t len; |
| 19975 | duk_tval *tv; |
| 19976 | |
| 19977 | DUK_CTX_ASSERT_VALID(thr); |
| 19978 | |
| 19979 | if (out_size != NULL) { |
| 19980 | *out_size = 0; |
| 19981 | } |
| 19982 | |
| 19983 | tv = duk_get_tval_or_unused(thr, idx); |
| 19984 | DUK_ASSERT(tv != NULL); |
| 19985 | if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) { |
| 19986 | h = DUK_TVAL_GET_BUFFER(tv); |
| 19987 | DUK_ASSERT(h != NULL); |
| 19988 | |
| 19989 | len = DUK_HBUFFER_GET_SIZE(h); |
| 19990 | ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); |
| 19991 | } else { |
| 19992 | if (throw_flag) { |
| 19993 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer" , DUK_STR_NOT_BUFFER); |
| 19994 | DUK_WO_NORETURN(return NULL;); |
| 19995 | } |
| 19996 | len = def_size; |
| 19997 | ret = def_ptr; |
| 19998 | } |
| 19999 | |
| 20000 | if (out_size != NULL) { |
| 20001 | *out_size = len; |
| 20002 | } |
| 20003 | return ret; |
| 20004 | } |
| 20005 | |
| 20006 | DUK_EXTERNAL void *duk_get_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { |
| 20007 | DUK_ASSERT_API_ENTRY(thr); |
| 20008 | |
| 20009 | return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/); |
| 20010 | } |
| 20011 | |
| 20012 | DUK_EXTERNAL void *duk_opt_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { |
| 20013 | DUK_ASSERT_API_ENTRY(thr); |
| 20014 | |
| 20015 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 20016 | if (out_size != NULL) { |
| 20017 | *out_size = def_size; |
| 20018 | } |
| 20019 | return def_ptr; |
| 20020 | } |
| 20021 | return duk_require_buffer(thr, idx, out_size); |
| 20022 | } |
| 20023 | |
| 20024 | DUK_EXTERNAL void *duk_get_buffer_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_len) { |
| 20025 | DUK_ASSERT_API_ENTRY(thr); |
| 20026 | |
| 20027 | return duk__get_buffer_helper(thr, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/); |
| 20028 | } |
| 20029 | |
| 20030 | DUK_EXTERNAL void *duk_require_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { |
| 20031 | DUK_ASSERT_API_ENTRY(thr); |
| 20032 | |
| 20033 | return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/); |
| 20034 | } |
| 20035 | |
| 20036 | /* Get the active buffer data area for a plain buffer or a buffer object. |
| 20037 | * Return NULL if the the value is not a buffer. Note that a buffer may |
| 20038 | * have a NULL data pointer when its size is zero, the optional 'out_isbuffer' |
| 20039 | * argument allows caller to detect this reliably. |
| 20040 | */ |
| 20041 | DUK_INTERNAL void *duk_get_buffer_data_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) { |
| 20042 | duk_tval *tv; |
| 20043 | |
| 20044 | DUK_ASSERT_API_ENTRY(thr); |
| 20045 | |
| 20046 | if (out_isbuffer != NULL) { |
| 20047 | *out_isbuffer = 0; |
| 20048 | } |
| 20049 | if (out_size != NULL) { |
| 20050 | *out_size = def_size; |
| 20051 | } |
| 20052 | |
| 20053 | tv = duk_get_tval_or_unused(thr, idx); |
| 20054 | DUK_ASSERT(tv != NULL); |
| 20055 | |
| 20056 | if (DUK_TVAL_IS_BUFFER(tv)) { |
| 20057 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); |
| 20058 | DUK_ASSERT(h != NULL); |
| 20059 | if (out_size != NULL) { |
| 20060 | *out_size = DUK_HBUFFER_GET_SIZE(h); |
| 20061 | } |
| 20062 | if (out_isbuffer != NULL) { |
| 20063 | *out_isbuffer = 1; |
| 20064 | } |
| 20065 | return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */ |
| 20066 | } |
| 20067 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 20068 | else if (DUK_TVAL_IS_OBJECT(tv)) { |
| 20069 | duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); |
| 20070 | DUK_ASSERT(h != NULL); |
| 20071 | if (DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 20072 | /* XXX: this is probably a useful shared helper: for a |
| 20073 | * duk_hbufobj, get a validated buffer pointer/length. |
| 20074 | */ |
| 20075 | duk_hbufobj *h_bufobj = (duk_hbufobj *) h; |
| 20076 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 20077 | |
| 20078 | if (h_bufobj->buf != NULL && |
| 20079 | DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { |
| 20080 | duk_uint8_t *p; |
| 20081 | |
| 20082 | p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf); |
| 20083 | if (out_size != NULL) { |
| 20084 | *out_size = (duk_size_t) h_bufobj->length; |
| 20085 | } |
| 20086 | if (out_isbuffer != NULL) { |
| 20087 | *out_isbuffer = 1; |
| 20088 | } |
| 20089 | return (void *) (p + h_bufobj->offset); |
| 20090 | } |
| 20091 | /* if slice not fully valid, treat as error */ |
| 20092 | } |
| 20093 | } |
| 20094 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 20095 | |
| 20096 | if (throw_flag) { |
| 20097 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer" , DUK_STR_NOT_BUFFER); |
| 20098 | DUK_WO_NORETURN(return NULL;); |
| 20099 | } |
| 20100 | return def_ptr; |
| 20101 | } |
| 20102 | |
| 20103 | DUK_EXTERNAL void *duk_get_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { |
| 20104 | DUK_ASSERT_API_ENTRY(thr); |
| 20105 | return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL); |
| 20106 | } |
| 20107 | |
| 20108 | DUK_EXTERNAL void *duk_get_buffer_data_default(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { |
| 20109 | DUK_ASSERT_API_ENTRY(thr); |
| 20110 | return duk_get_buffer_data_raw(thr, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL); |
| 20111 | } |
| 20112 | |
| 20113 | DUK_EXTERNAL void *duk_opt_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, void *def_ptr, duk_size_t def_size) { |
| 20114 | DUK_ASSERT_API_ENTRY(thr); |
| 20115 | |
| 20116 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 20117 | if (out_size != NULL) { |
| 20118 | *out_size = def_size; |
| 20119 | } |
| 20120 | return def_ptr; |
| 20121 | } |
| 20122 | return duk_require_buffer_data(thr, idx, out_size); |
| 20123 | } |
| 20124 | |
| 20125 | DUK_EXTERNAL void *duk_require_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) { |
| 20126 | DUK_ASSERT_API_ENTRY(thr); |
| 20127 | return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL); |
| 20128 | } |
| 20129 | |
| 20130 | /* Raw helper for getting a value from the stack, checking its tag. |
| 20131 | * The tag cannot be a number because numbers don't have an internal |
| 20132 | * tag in the packed representation. |
| 20133 | */ |
| 20134 | |
| 20135 | DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag) { |
| 20136 | duk_tval *tv; |
| 20137 | duk_heaphdr *ret; |
| 20138 | |
| 20139 | DUK_CTX_ASSERT_VALID(thr); |
| 20140 | |
| 20141 | tv = duk_get_tval_or_unused(thr, idx); |
| 20142 | DUK_ASSERT(tv != NULL); |
| 20143 | if (DUK_TVAL_GET_TAG(tv) != tag) { |
| 20144 | return (duk_heaphdr *) NULL; |
| 20145 | } |
| 20146 | |
| 20147 | ret = DUK_TVAL_GET_HEAPHDR(tv); |
| 20148 | DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */ |
| 20149 | return ret; |
| 20150 | |
| 20151 | } |
| 20152 | |
| 20153 | DUK_INTERNAL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx) { |
| 20154 | DUK_ASSERT_API_ENTRY(thr); |
| 20155 | return (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); |
| 20156 | } |
| 20157 | |
| 20158 | DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) { |
| 20159 | duk_hstring *h; |
| 20160 | |
| 20161 | DUK_ASSERT_API_ENTRY(thr); |
| 20162 | |
| 20163 | h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); |
| 20164 | if (DUK_UNLIKELY(h && DUK_HSTRING_HAS_SYMBOL(h))) { |
| 20165 | return NULL; |
| 20166 | } |
| 20167 | return h; |
| 20168 | } |
| 20169 | |
| 20170 | DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) { |
| 20171 | duk_hstring *h; |
| 20172 | |
| 20173 | DUK_ASSERT_API_ENTRY(thr); |
| 20174 | |
| 20175 | h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); |
| 20176 | if (DUK_UNLIKELY(h == NULL)) { |
| 20177 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string" , DUK_STR_NOT_STRING); |
| 20178 | DUK_WO_NORETURN(return NULL;); |
| 20179 | } |
| 20180 | return h; |
| 20181 | } |
| 20182 | |
| 20183 | DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) { |
| 20184 | duk_hstring *h; |
| 20185 | |
| 20186 | DUK_ASSERT_API_ENTRY(thr); |
| 20187 | |
| 20188 | h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING); |
| 20189 | if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) { |
| 20190 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string" , DUK_STR_NOT_STRING); |
| 20191 | DUK_WO_NORETURN(return NULL;); |
| 20192 | } |
| 20193 | return h; |
| 20194 | } |
| 20195 | |
| 20196 | DUK_INTERNAL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx) { |
| 20197 | DUK_ASSERT_API_ENTRY(thr); |
| 20198 | return (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20199 | } |
| 20200 | |
| 20201 | DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) { |
| 20202 | duk_hobject *h; |
| 20203 | |
| 20204 | DUK_ASSERT_API_ENTRY(thr); |
| 20205 | |
| 20206 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20207 | if (DUK_UNLIKELY(h == NULL)) { |
| 20208 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object" , DUK_STR_NOT_OBJECT); |
| 20209 | DUK_WO_NORETURN(return NULL;); |
| 20210 | } |
| 20211 | return h; |
| 20212 | } |
| 20213 | |
| 20214 | DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx) { |
| 20215 | DUK_ASSERT_API_ENTRY(thr); |
| 20216 | return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER); |
| 20217 | } |
| 20218 | |
| 20219 | DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) { |
| 20220 | duk_hbuffer *h; |
| 20221 | |
| 20222 | DUK_ASSERT_API_ENTRY(thr); |
| 20223 | |
| 20224 | h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER); |
| 20225 | if (DUK_UNLIKELY(h == NULL)) { |
| 20226 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer" , DUK_STR_NOT_BUFFER); |
| 20227 | DUK_WO_NORETURN(return NULL;); |
| 20228 | } |
| 20229 | return h; |
| 20230 | } |
| 20231 | |
| 20232 | DUK_INTERNAL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx) { |
| 20233 | duk_hobject *h; |
| 20234 | |
| 20235 | DUK_ASSERT_API_ENTRY(thr); |
| 20236 | |
| 20237 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20238 | if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) { |
| 20239 | h = NULL; |
| 20240 | } |
| 20241 | return (duk_hthread *) h; |
| 20242 | } |
| 20243 | |
| 20244 | DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) { |
| 20245 | duk_hobject *h; |
| 20246 | |
| 20247 | DUK_ASSERT_API_ENTRY(thr); |
| 20248 | |
| 20249 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20250 | if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) { |
| 20251 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread" , DUK_STR_NOT_THREAD); |
| 20252 | DUK_WO_NORETURN(return NULL;); |
| 20253 | } |
| 20254 | return (duk_hthread *) h; |
| 20255 | } |
| 20256 | |
| 20257 | DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx) { |
| 20258 | duk_hobject *h; |
| 20259 | |
| 20260 | DUK_ASSERT_API_ENTRY(thr); |
| 20261 | |
| 20262 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20263 | if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) { |
| 20264 | h = NULL; |
| 20265 | } |
| 20266 | return (duk_hcompfunc *) h; |
| 20267 | } |
| 20268 | |
| 20269 | DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx) { |
| 20270 | duk_hobject *h; |
| 20271 | |
| 20272 | DUK_ASSERT_API_ENTRY(thr); |
| 20273 | |
| 20274 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20275 | if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) { |
| 20276 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction" , DUK_STR_NOT_COMPFUNC); |
| 20277 | DUK_WO_NORETURN(return NULL;); |
| 20278 | } |
| 20279 | return (duk_hcompfunc *) h; |
| 20280 | } |
| 20281 | |
| 20282 | DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx) { |
| 20283 | duk_hobject *h; |
| 20284 | |
| 20285 | DUK_ASSERT_API_ENTRY(thr); |
| 20286 | |
| 20287 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20288 | if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) { |
| 20289 | h = NULL; |
| 20290 | } |
| 20291 | return (duk_hnatfunc *) h; |
| 20292 | } |
| 20293 | |
| 20294 | DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) { |
| 20295 | duk_hobject *h; |
| 20296 | |
| 20297 | DUK_ASSERT_API_ENTRY(thr); |
| 20298 | |
| 20299 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20300 | if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) { |
| 20301 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction" , DUK_STR_NOT_NATFUNC); |
| 20302 | DUK_WO_NORETURN(return NULL;); |
| 20303 | } |
| 20304 | return (duk_hnatfunc *) h; |
| 20305 | } |
| 20306 | |
| 20307 | DUK_EXTERNAL duk_c_function duk_get_c_function(duk_hthread *thr, duk_idx_t idx) { |
| 20308 | duk_tval *tv; |
| 20309 | duk_hobject *h; |
| 20310 | duk_hnatfunc *f; |
| 20311 | |
| 20312 | DUK_ASSERT_API_ENTRY(thr); |
| 20313 | |
| 20314 | tv = duk_get_tval_or_unused(thr, idx); |
| 20315 | DUK_ASSERT(tv != NULL); |
| 20316 | if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) { |
| 20317 | return NULL; |
| 20318 | } |
| 20319 | h = DUK_TVAL_GET_OBJECT(tv); |
| 20320 | DUK_ASSERT(h != NULL); |
| 20321 | |
| 20322 | if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) { |
| 20323 | return NULL; |
| 20324 | } |
| 20325 | DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h)); |
| 20326 | f = (duk_hnatfunc *) h; |
| 20327 | |
| 20328 | return f->func; |
| 20329 | } |
| 20330 | |
| 20331 | DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) { |
| 20332 | DUK_ASSERT_API_ENTRY(thr); |
| 20333 | |
| 20334 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 20335 | return def_value; |
| 20336 | } |
| 20337 | return duk_require_c_function(thr, idx); |
| 20338 | } |
| 20339 | |
| 20340 | DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) { |
| 20341 | duk_c_function ret; |
| 20342 | |
| 20343 | DUK_ASSERT_API_ENTRY(thr); |
| 20344 | |
| 20345 | ret = duk_get_c_function(thr, idx); |
| 20346 | if (ret != NULL) { |
| 20347 | return ret; |
| 20348 | } |
| 20349 | |
| 20350 | return def_value; |
| 20351 | } |
| 20352 | |
| 20353 | DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t idx) { |
| 20354 | duk_c_function ret; |
| 20355 | |
| 20356 | DUK_ASSERT_API_ENTRY(thr); |
| 20357 | |
| 20358 | ret = duk_get_c_function(thr, idx); |
| 20359 | if (DUK_UNLIKELY(!ret)) { |
| 20360 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction" , DUK_STR_NOT_NATFUNC); |
| 20361 | DUK_WO_NORETURN(return ret;); |
| 20362 | } |
| 20363 | return ret; |
| 20364 | } |
| 20365 | |
| 20366 | DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) { |
| 20367 | DUK_ASSERT_API_ENTRY(thr); |
| 20368 | if (DUK_UNLIKELY(!duk_is_function(thr, idx))) { |
| 20369 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function" , DUK_STR_NOT_FUNCTION); |
| 20370 | DUK_WO_NORETURN(return;); |
| 20371 | } |
| 20372 | } |
| 20373 | |
| 20374 | DUK_EXTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) { |
| 20375 | duk_hobject *h; |
| 20376 | |
| 20377 | DUK_ASSERT_API_ENTRY(thr); |
| 20378 | |
| 20379 | h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC); |
| 20380 | if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) { |
| 20381 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable" , DUK_STR_NOT_CONSTRUCTABLE); |
| 20382 | DUK_WO_NORETURN(return;); |
| 20383 | } |
| 20384 | /* Lightfuncs (h == NULL) are constructable. */ |
| 20385 | } |
| 20386 | |
| 20387 | DUK_EXTERNAL duk_hthread *duk_get_context(duk_hthread *thr, duk_idx_t idx) { |
| 20388 | DUK_ASSERT_API_ENTRY(thr); |
| 20389 | |
| 20390 | return duk_get_hthread(thr, idx); |
| 20391 | } |
| 20392 | |
| 20393 | DUK_EXTERNAL duk_hthread *duk_require_context(duk_hthread *thr, duk_idx_t idx) { |
| 20394 | DUK_ASSERT_API_ENTRY(thr); |
| 20395 | |
| 20396 | return duk_require_hthread(thr, idx); |
| 20397 | } |
| 20398 | |
| 20399 | DUK_EXTERNAL duk_hthread *duk_opt_context(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) { |
| 20400 | DUK_ASSERT_API_ENTRY(thr); |
| 20401 | |
| 20402 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 20403 | return def_value; |
| 20404 | } |
| 20405 | return duk_require_context(thr, idx); |
| 20406 | } |
| 20407 | |
| 20408 | DUK_EXTERNAL duk_hthread *duk_get_context_default(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) { |
| 20409 | duk_hthread *ret; |
| 20410 | |
| 20411 | DUK_ASSERT_API_ENTRY(thr); |
| 20412 | |
| 20413 | ret = duk_get_context(thr, idx); |
| 20414 | if (ret != NULL) { |
| 20415 | return ret; |
| 20416 | } |
| 20417 | |
| 20418 | return def_value; |
| 20419 | } |
| 20420 | |
| 20421 | DUK_EXTERNAL void *duk_get_heapptr(duk_hthread *thr, duk_idx_t idx) { |
| 20422 | duk_tval *tv; |
| 20423 | void *ret; |
| 20424 | |
| 20425 | DUK_ASSERT_API_ENTRY(thr); |
| 20426 | |
| 20427 | tv = duk_get_tval_or_unused(thr, idx); |
| 20428 | DUK_ASSERT(tv != NULL); |
| 20429 | if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { |
| 20430 | return (void *) NULL; |
| 20431 | } |
| 20432 | |
| 20433 | ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); |
| 20434 | DUK_ASSERT(ret != NULL); |
| 20435 | return ret; |
| 20436 | } |
| 20437 | |
| 20438 | DUK_EXTERNAL void *duk_opt_heapptr(duk_hthread *thr, duk_idx_t idx, void *def_value) { |
| 20439 | DUK_ASSERT_API_ENTRY(thr); |
| 20440 | |
| 20441 | if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) { |
| 20442 | return def_value; |
| 20443 | } |
| 20444 | return duk_require_heapptr(thr, idx); |
| 20445 | } |
| 20446 | |
| 20447 | DUK_EXTERNAL void *duk_get_heapptr_default(duk_hthread *thr, duk_idx_t idx, void *def_value) { |
| 20448 | void *ret; |
| 20449 | |
| 20450 | DUK_ASSERT_API_ENTRY(thr); |
| 20451 | |
| 20452 | ret = duk_get_heapptr(thr, idx); |
| 20453 | if (ret != NULL) { |
| 20454 | return ret; |
| 20455 | } |
| 20456 | |
| 20457 | return def_value; |
| 20458 | } |
| 20459 | |
| 20460 | DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) { |
| 20461 | duk_tval *tv; |
| 20462 | void *ret; |
| 20463 | |
| 20464 | DUK_ASSERT_API_ENTRY(thr); |
| 20465 | |
| 20466 | tv = duk_get_tval_or_unused(thr, idx); |
| 20467 | DUK_ASSERT(tv != NULL); |
| 20468 | if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) { |
| 20469 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject" , DUK_STR_UNEXPECTED_TYPE); |
| 20470 | DUK_WO_NORETURN(return NULL;); |
| 20471 | } |
| 20472 | |
| 20473 | ret = (void *) DUK_TVAL_GET_HEAPHDR(tv); |
| 20474 | DUK_ASSERT(ret != NULL); |
| 20475 | return ret; |
| 20476 | } |
| 20477 | |
| 20478 | /* Internal helper for getting/requiring a duk_hobject with possible promotion. */ |
| 20479 | DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { |
| 20480 | duk_uint_t val_mask; |
| 20481 | duk_hobject *res; |
| 20482 | |
| 20483 | DUK_CTX_ASSERT_VALID(thr); |
| 20484 | |
| 20485 | res = duk_get_hobject(thr, idx); /* common case, not promoted */ |
| 20486 | if (DUK_LIKELY(res != NULL)) { |
| 20487 | DUK_ASSERT(res != NULL); |
| 20488 | return res; |
| 20489 | } |
| 20490 | |
| 20491 | val_mask = duk_get_type_mask(thr, idx); |
| 20492 | if (val_mask & type_mask) { |
| 20493 | if (type_mask & DUK_TYPE_MASK_PROMOTE) { |
| 20494 | res = duk_to_hobject(thr, idx); |
| 20495 | DUK_ASSERT(res != NULL); |
| 20496 | return res; |
| 20497 | } else { |
| 20498 | return NULL; /* accept without promoting */ |
| 20499 | } |
| 20500 | } |
| 20501 | |
| 20502 | if (type_mask & DUK_TYPE_MASK_THROW) { |
| 20503 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object" , DUK_STR_NOT_OBJECT); |
| 20504 | DUK_WO_NORETURN(return NULL;); |
| 20505 | } |
| 20506 | return NULL; |
| 20507 | } |
| 20508 | |
| 20509 | /* Get a duk_hobject * at 'idx'; if the value is not an object but matches the |
| 20510 | * supplied 'type_mask', promote it to an object and return the duk_hobject *. |
| 20511 | * This is useful for call sites which want an object but also accept a plain |
| 20512 | * buffer and/or a lightfunc which gets automatically promoted to an object. |
| 20513 | * Return value is NULL if value is neither an object nor a plain type allowed |
| 20514 | * by the mask. |
| 20515 | */ |
| 20516 | DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { |
| 20517 | DUK_ASSERT_API_ENTRY(thr); |
| 20518 | return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_PROMOTE); |
| 20519 | } |
| 20520 | |
| 20521 | /* Like duk_get_hobject_promote_mask() but throw a TypeError instead of |
| 20522 | * returning a NULL. |
| 20523 | */ |
| 20524 | DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { |
| 20525 | DUK_ASSERT_API_ENTRY(thr); |
| 20526 | return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE); |
| 20527 | } |
| 20528 | |
| 20529 | /* Require a duk_hobject * at 'idx'; if the value is not an object but matches the |
| 20530 | * supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError. |
| 20531 | */ |
| 20532 | DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) { |
| 20533 | DUK_ASSERT_API_ENTRY(thr); |
| 20534 | return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW); |
| 20535 | } |
| 20536 | |
| 20537 | DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) { |
| 20538 | duk_hobject *h; |
| 20539 | |
| 20540 | DUK_ASSERT_API_ENTRY(thr); |
| 20541 | DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ |
| 20542 | DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); |
| 20543 | |
| 20544 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20545 | if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) { |
| 20546 | h = NULL; |
| 20547 | } |
| 20548 | return h; |
| 20549 | } |
| 20550 | |
| 20551 | DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) { |
| 20552 | duk_hobject *h; |
| 20553 | |
| 20554 | DUK_ASSERT_API_ENTRY(thr); |
| 20555 | DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */ |
| 20556 | DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX); |
| 20557 | |
| 20558 | h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT); |
| 20559 | if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) { |
| 20560 | duk_hstring *h_class; |
| 20561 | h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum)); |
| 20562 | DUK_UNREF(h_class); |
| 20563 | |
| 20564 | DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE); |
| 20565 | DUK_WO_NORETURN(return NULL;); |
| 20566 | } |
| 20567 | return h; |
| 20568 | } |
| 20569 | |
| 20570 | DUK_EXTERNAL duk_size_t duk_get_length(duk_hthread *thr, duk_idx_t idx) { |
| 20571 | duk_tval *tv; |
| 20572 | |
| 20573 | DUK_ASSERT_API_ENTRY(thr); |
| 20574 | |
| 20575 | tv = duk_get_tval_or_unused(thr, idx); |
| 20576 | DUK_ASSERT(tv != NULL); |
| 20577 | |
| 20578 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 20579 | case DUK_TAG_UNDEFINED: |
| 20580 | case DUK_TAG_NULL: |
| 20581 | case DUK_TAG_BOOLEAN: |
| 20582 | case DUK_TAG_POINTER: |
| 20583 | return 0; |
| 20584 | #if defined(DUK_USE_PREFER_SIZE) |
| 20585 | /* String and buffer have a virtual non-configurable .length property |
| 20586 | * which is within size_t range so it can be looked up without specific |
| 20587 | * type checks. Lightfuncs inherit from %NativeFunctionPrototype% |
| 20588 | * which provides an inherited .length accessor; it could be overwritten |
| 20589 | * to produce unexpected types or values, but just number convert and |
| 20590 | * duk_size_t cast for now. |
| 20591 | */ |
| 20592 | case DUK_TAG_STRING: |
| 20593 | case DUK_TAG_BUFFER: |
| 20594 | case DUK_TAG_LIGHTFUNC: { |
| 20595 | duk_size_t ret; |
| 20596 | duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); |
| 20597 | ret = (duk_size_t) duk_to_number_m1(thr); |
| 20598 | duk_pop_unsafe(thr); |
| 20599 | return ret; |
| 20600 | } |
| 20601 | #else /* DUK_USE_PREFER_SIZE */ |
| 20602 | case DUK_TAG_STRING: { |
| 20603 | duk_hstring *h = DUK_TVAL_GET_STRING(tv); |
| 20604 | DUK_ASSERT(h != NULL); |
| 20605 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 20606 | return 0; |
| 20607 | } |
| 20608 | return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h); |
| 20609 | } |
| 20610 | case DUK_TAG_BUFFER: { |
| 20611 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); |
| 20612 | DUK_ASSERT(h != NULL); |
| 20613 | return (duk_size_t) DUK_HBUFFER_GET_SIZE(h); |
| 20614 | } |
| 20615 | case DUK_TAG_LIGHTFUNC: { |
| 20616 | /* We could look up the length from the lightfunc duk_tval, |
| 20617 | * but since Duktape 2.2 lightfunc .length comes from |
| 20618 | * %NativeFunctionPrototype% which can be overridden, so |
| 20619 | * look up the property explicitly. |
| 20620 | */ |
| 20621 | duk_size_t ret; |
| 20622 | duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); |
| 20623 | ret = (duk_size_t) duk_to_number_m1(thr); |
| 20624 | duk_pop_unsafe(thr); |
| 20625 | return ret; |
| 20626 | } |
| 20627 | #endif /* DUK_USE_PREFER_SIZE */ |
| 20628 | case DUK_TAG_OBJECT: { |
| 20629 | duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); |
| 20630 | DUK_ASSERT(h != NULL); |
| 20631 | return (duk_size_t) duk_hobject_get_length(thr, h); |
| 20632 | } |
| 20633 | #if defined(DUK_USE_FASTINT) |
| 20634 | case DUK_TAG_FASTINT: |
| 20635 | #endif |
| 20636 | default: |
| 20637 | /* number or 'unused' */ |
| 20638 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv)); |
| 20639 | return 0; |
| 20640 | } |
| 20641 | |
| 20642 | DUK_UNREACHABLE(); |
| 20643 | } |
| 20644 | |
| 20645 | /* |
| 20646 | * duk_known_xxx() helpers |
| 20647 | * |
| 20648 | * Used internally when we're 100% sure that a certain index is valid and |
| 20649 | * contains an object of a certain type. For example, if we duk_push_object() |
| 20650 | * we can then safely duk_known_hobject(thr, -1). These helpers just assert |
| 20651 | * for the index and type, and if the assumptions are not valid, memory unsafe |
| 20652 | * behavior happens. |
| 20653 | */ |
| 20654 | |
| 20655 | DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_hthread *thr, duk_idx_t idx) { |
| 20656 | duk_tval *tv; |
| 20657 | duk_heaphdr *h; |
| 20658 | |
| 20659 | DUK_CTX_ASSERT_VALID(thr); |
| 20660 | if (idx < 0) { |
| 20661 | tv = thr->valstack_top + idx; |
| 20662 | } else { |
| 20663 | tv = thr->valstack_bottom + idx; |
| 20664 | } |
| 20665 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 20666 | DUK_ASSERT(tv < thr->valstack_top); |
| 20667 | h = DUK_TVAL_GET_HEAPHDR(tv); |
| 20668 | DUK_ASSERT(h != NULL); |
| 20669 | return h; |
| 20670 | } |
| 20671 | |
| 20672 | DUK_INTERNAL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx) { |
| 20673 | DUK_ASSERT_API_ENTRY(thr); |
| 20674 | DUK_ASSERT(duk_get_hstring(thr, idx) != NULL); |
| 20675 | return (duk_hstring *) duk__known_heaphdr(thr, idx); |
| 20676 | } |
| 20677 | |
| 20678 | DUK_INTERNAL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx) { |
| 20679 | DUK_ASSERT_API_ENTRY(thr); |
| 20680 | DUK_ASSERT(duk_get_hobject(thr, idx) != NULL); |
| 20681 | return (duk_hobject *) duk__known_heaphdr(thr, idx); |
| 20682 | } |
| 20683 | |
| 20684 | DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx) { |
| 20685 | DUK_ASSERT_API_ENTRY(thr); |
| 20686 | DUK_ASSERT(duk_get_hbuffer(thr, idx) != NULL); |
| 20687 | return (duk_hbuffer *) duk__known_heaphdr(thr, idx); |
| 20688 | } |
| 20689 | |
| 20690 | DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx) { |
| 20691 | DUK_ASSERT_API_ENTRY(thr); |
| 20692 | DUK_ASSERT(duk_get_hcompfunc(thr, idx) != NULL); |
| 20693 | return (duk_hcompfunc *) duk__known_heaphdr(thr, idx); |
| 20694 | } |
| 20695 | |
| 20696 | DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx) { |
| 20697 | DUK_ASSERT_API_ENTRY(thr); |
| 20698 | DUK_ASSERT(duk_get_hnatfunc(thr, idx) != NULL); |
| 20699 | return (duk_hnatfunc *) duk__known_heaphdr(thr, idx); |
| 20700 | } |
| 20701 | |
| 20702 | DUK_EXTERNAL void duk_set_length(duk_hthread *thr, duk_idx_t idx, duk_size_t len) { |
| 20703 | DUK_ASSERT_API_ENTRY(thr); |
| 20704 | |
| 20705 | idx = duk_normalize_index(thr, idx); |
| 20706 | duk_push_uint(thr, (duk_uint_t) len); |
| 20707 | duk_put_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); |
| 20708 | } |
| 20709 | |
| 20710 | /* |
| 20711 | * Conversions and coercions |
| 20712 | * |
| 20713 | * The conversion/coercions are in-place operations on the value stack. |
| 20714 | * Some operations are implemented here directly, while others call a |
| 20715 | * helper in duk_js_ops.c after validating arguments. |
| 20716 | */ |
| 20717 | |
| 20718 | /* E5 Section 8.12.8 */ |
| 20719 | |
| 20720 | DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t func_stridx) { |
| 20721 | if (duk_get_prop_stridx(thr, idx, func_stridx)) { |
| 20722 | /* [ ... func ] */ |
| 20723 | if (duk_is_callable(thr, -1)) { |
| 20724 | duk_dup(thr, idx); /* -> [ ... func this ] */ |
| 20725 | duk_call_method(thr, 0); /* -> [ ... retval ] */ |
| 20726 | if (duk_is_primitive(thr, -1)) { |
| 20727 | duk_replace(thr, idx); |
| 20728 | return 1; |
| 20729 | } |
| 20730 | /* [ ... retval ]; popped below */ |
| 20731 | } |
| 20732 | } |
| 20733 | duk_pop_unsafe(thr); /* [ ... func/retval ] -> [ ... ] */ |
| 20734 | return 0; |
| 20735 | } |
| 20736 | |
| 20737 | DUK_EXTERNAL void duk_to_undefined(duk_hthread *thr, duk_idx_t idx) { |
| 20738 | duk_tval *tv; |
| 20739 | |
| 20740 | DUK_ASSERT_API_ENTRY(thr); |
| 20741 | |
| 20742 | tv = duk_require_tval(thr, idx); |
| 20743 | DUK_ASSERT(tv != NULL); |
| 20744 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ |
| 20745 | } |
| 20746 | |
| 20747 | DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) { |
| 20748 | duk_tval *tv; |
| 20749 | |
| 20750 | DUK_ASSERT_API_ENTRY(thr); |
| 20751 | |
| 20752 | tv = duk_require_tval(thr, idx); |
| 20753 | DUK_ASSERT(tv != NULL); |
| 20754 | DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */ |
| 20755 | } |
| 20756 | |
| 20757 | /* E5 Section 9.1 */ |
| 20758 | DUK_LOCAL const char * const duk__toprim_hint_strings[3] = { |
| 20759 | "default" , "string" , "number" |
| 20760 | }; |
| 20761 | DUK_LOCAL void duk__to_primitive_helper(duk_hthread *thr, duk_idx_t idx, duk_int_t hint, duk_bool_t check_symbol) { |
| 20762 | /* Inline initializer for coercers[] is not allowed by old compilers like BCC. */ |
| 20763 | duk_small_uint_t coercers[2]; |
| 20764 | |
| 20765 | DUK_ASSERT_API_ENTRY(thr); |
| 20766 | DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING); |
| 20767 | |
| 20768 | idx = duk_require_normalize_index(thr, idx); |
| 20769 | |
| 20770 | /* If already primitive, return as is. */ |
| 20771 | if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT | |
| 20772 | DUK_TYPE_MASK_LIGHTFUNC | |
| 20773 | DUK_TYPE_MASK_BUFFER)) { |
| 20774 | DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */ |
| 20775 | return; |
| 20776 | } |
| 20777 | |
| 20778 | /* @@toPrimitive lookup. Also do for plain buffers and lightfuncs |
| 20779 | * which mimic objects. |
| 20780 | */ |
| 20781 | if (check_symbol && duk_get_method_stridx(thr, idx, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)) { |
| 20782 | DUK_ASSERT(hint >= 0 && (duk_size_t) hint < sizeof(duk__toprim_hint_strings) / sizeof(const char *)); |
| 20783 | duk_dup(thr, idx); |
| 20784 | duk_push_string(thr, duk__toprim_hint_strings[hint]); |
| 20785 | duk_call_method(thr, 1); /* [ ... method value hint ] -> [ ... res] */ |
| 20786 | if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | |
| 20787 | DUK_TYPE_MASK_LIGHTFUNC | |
| 20788 | DUK_TYPE_MASK_BUFFER)) { |
| 20789 | goto fail; |
| 20790 | } |
| 20791 | duk_replace(thr, idx); |
| 20792 | return; |
| 20793 | } |
| 20794 | |
| 20795 | /* Objects are coerced based on E5 specification. |
| 20796 | * Lightfuncs are coerced because they behave like |
| 20797 | * objects even if they're internally a primitive |
| 20798 | * type. Same applies to plain buffers, which behave |
| 20799 | * like ArrayBuffer objects since Duktape 2.x. |
| 20800 | */ |
| 20801 | |
| 20802 | /* Hint magic for Date is unnecessary in ES2015 because of |
| 20803 | * Date.prototype[@@toPrimitive]. However, it is needed if |
| 20804 | * symbol support is not enabled. |
| 20805 | */ |
| 20806 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 20807 | if (hint == DUK_HINT_NONE) { |
| 20808 | hint = DUK_HINT_NUMBER; |
| 20809 | } |
| 20810 | #else /* DUK_USE_SYMBOL_BUILTIN */ |
| 20811 | if (hint == DUK_HINT_NONE) { |
| 20812 | duk_small_uint_t class_number; |
| 20813 | |
| 20814 | class_number = duk_get_class_number(thr, idx); |
| 20815 | if (class_number == DUK_HOBJECT_CLASS_DATE) { |
| 20816 | hint = DUK_HINT_STRING; |
| 20817 | } else { |
| 20818 | hint = DUK_HINT_NUMBER; |
| 20819 | } |
| 20820 | } |
| 20821 | #endif /* DUK_USE_SYMBOL_BUILTIN */ |
| 20822 | |
| 20823 | coercers[0] = DUK_STRIDX_VALUE_OF; |
| 20824 | coercers[1] = DUK_STRIDX_TO_STRING; |
| 20825 | if (hint == DUK_HINT_STRING) { |
| 20826 | coercers[0] = DUK_STRIDX_TO_STRING; |
| 20827 | coercers[1] = DUK_STRIDX_VALUE_OF; |
| 20828 | } |
| 20829 | |
| 20830 | if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[0])) { |
| 20831 | DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */ |
| 20832 | return; |
| 20833 | } |
| 20834 | |
| 20835 | if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[1])) { |
| 20836 | DUK_ASSERT(!duk_is_buffer(thr, idx)); /* duk_to_string() relies on this behavior */ |
| 20837 | return; |
| 20838 | } |
| 20839 | |
| 20840 | fail: |
| 20841 | DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED); |
| 20842 | DUK_WO_NORETURN(return;); |
| 20843 | } |
| 20844 | |
| 20845 | DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) { |
| 20846 | duk__to_primitive_helper(thr, idx, hint, 1 /*check_symbol*/); |
| 20847 | } |
| 20848 | |
| 20849 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 20850 | DUK_INTERNAL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) { |
| 20851 | duk__to_primitive_helper(thr, idx, hint, 0 /*check_symbol*/); |
| 20852 | } |
| 20853 | #endif |
| 20854 | |
| 20855 | /* E5 Section 9.2 */ |
| 20856 | DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) { |
| 20857 | duk_tval *tv; |
| 20858 | duk_bool_t val; |
| 20859 | |
| 20860 | DUK_ASSERT_API_ENTRY(thr); |
| 20861 | |
| 20862 | idx = duk_require_normalize_index(thr, idx); |
| 20863 | tv = DUK_GET_TVAL_POSIDX(thr, idx); |
| 20864 | DUK_ASSERT(tv != NULL); |
| 20865 | |
| 20866 | val = duk_js_toboolean(tv); |
| 20867 | DUK_ASSERT(val == 0 || val == 1); |
| 20868 | |
| 20869 | /* Note: no need to re-lookup tv, conversion is side effect free. */ |
| 20870 | DUK_ASSERT(tv != NULL); |
| 20871 | DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */ |
| 20872 | return val; |
| 20873 | } |
| 20874 | |
| 20875 | DUK_INTERNAL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr) { |
| 20876 | duk_tval *tv; |
| 20877 | duk_bool_t val; |
| 20878 | |
| 20879 | DUK_ASSERT_API_ENTRY(thr); |
| 20880 | |
| 20881 | tv = duk_require_tval(thr, -1); |
| 20882 | DUK_ASSERT(tv != NULL); |
| 20883 | |
| 20884 | val = duk_js_toboolean(tv); |
| 20885 | DUK_ASSERT(val == 0 || val == 1); |
| 20886 | |
| 20887 | duk_pop_unsafe(thr); |
| 20888 | return val; |
| 20889 | } |
| 20890 | |
| 20891 | DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) { |
| 20892 | duk_tval *tv; |
| 20893 | duk_double_t d; |
| 20894 | |
| 20895 | DUK_ASSERT_API_ENTRY(thr); |
| 20896 | |
| 20897 | /* XXX: No need to normalize; the whole operation could be inlined here to |
| 20898 | * avoid 'tv' re-lookup. |
| 20899 | */ |
| 20900 | idx = duk_require_normalize_index(thr, idx); |
| 20901 | tv = DUK_GET_TVAL_POSIDX(thr, idx); |
| 20902 | DUK_ASSERT(tv != NULL); |
| 20903 | d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */ |
| 20904 | |
| 20905 | /* ToNumber() may have side effects so must relookup 'tv'. */ |
| 20906 | tv = DUK_GET_TVAL_POSIDX(thr, idx); |
| 20907 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ |
| 20908 | return d; |
| 20909 | } |
| 20910 | |
| 20911 | DUK_INTERNAL duk_double_t duk_to_number_m1(duk_hthread *thr) { |
| 20912 | DUK_ASSERT_API_ENTRY(thr); |
| 20913 | return duk_to_number(thr, -1); |
| 20914 | } |
| 20915 | DUK_INTERNAL duk_double_t duk_to_number_m2(duk_hthread *thr) { |
| 20916 | DUK_ASSERT_API_ENTRY(thr); |
| 20917 | return duk_to_number(thr, -2); |
| 20918 | } |
| 20919 | |
| 20920 | DUK_INTERNAL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv) { |
| 20921 | #if defined(DUK_USE_PREFER_SIZE) |
| 20922 | duk_double_t res; |
| 20923 | |
| 20924 | DUK_ASSERT_API_ENTRY(thr); |
| 20925 | |
| 20926 | duk_push_tval(thr, tv); |
| 20927 | res = duk_to_number_m1(thr); |
| 20928 | duk_pop_unsafe(thr); |
| 20929 | return res; |
| 20930 | #else |
| 20931 | duk_double_t res; |
| 20932 | duk_tval *tv_dst; |
| 20933 | |
| 20934 | DUK_ASSERT_API_ENTRY(thr); |
| 20935 | DUK__ASSERT_SPACE(); |
| 20936 | |
| 20937 | tv_dst = thr->valstack_top++; |
| 20938 | DUK_TVAL_SET_TVAL(tv_dst, tv); |
| 20939 | DUK_TVAL_INCREF(thr, tv_dst); /* decref not necessary */ |
| 20940 | res = duk_to_number_m1(thr); /* invalidates tv_dst */ |
| 20941 | |
| 20942 | tv_dst = --thr->valstack_top; |
| 20943 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_dst)); |
| 20944 | DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_dst)); /* plain number */ |
| 20945 | DUK_TVAL_SET_UNDEFINED(tv_dst); /* valstack init policy */ |
| 20946 | |
| 20947 | return res; |
| 20948 | #endif |
| 20949 | } |
| 20950 | |
| 20951 | /* XXX: combine all the integer conversions: they share everything |
| 20952 | * but the helper function for coercion. |
| 20953 | */ |
| 20954 | |
| 20955 | typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv); |
| 20956 | |
| 20957 | DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_hthread *thr, duk_idx_t idx, duk__toint_coercer coerce_func) { |
| 20958 | duk_tval *tv; |
| 20959 | duk_double_t d; |
| 20960 | |
| 20961 | DUK_CTX_ASSERT_VALID(thr); |
| 20962 | |
| 20963 | tv = duk_require_tval(thr, idx); |
| 20964 | DUK_ASSERT(tv != NULL); |
| 20965 | |
| 20966 | #if defined(DUK_USE_FASTINT) |
| 20967 | /* If argument is a fastint, guarantee that it remains one. |
| 20968 | * There's no downgrade check for other cases. |
| 20969 | */ |
| 20970 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 20971 | /* XXX: Unnecessary conversion back and forth. */ |
| 20972 | return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); |
| 20973 | } |
| 20974 | #endif |
| 20975 | d = coerce_func(thr, tv); |
| 20976 | |
| 20977 | /* XXX: fastint? */ |
| 20978 | |
| 20979 | /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ |
| 20980 | tv = duk_require_tval(thr, idx); |
| 20981 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */ |
| 20982 | return d; |
| 20983 | } |
| 20984 | |
| 20985 | DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx) { |
| 20986 | /* Value coercion (in stack): ToInteger(), E5 Section 9.4, |
| 20987 | * API return value coercion: custom. |
| 20988 | */ |
| 20989 | DUK_ASSERT_API_ENTRY(thr); |
| 20990 | (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger); |
| 20991 | return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/); |
| 20992 | } |
| 20993 | |
| 20994 | DUK_EXTERNAL duk_uint_t duk_to_uint(duk_hthread *thr, duk_idx_t idx) { |
| 20995 | /* Value coercion (in stack): ToInteger(), E5 Section 9.4, |
| 20996 | * API return value coercion: custom. |
| 20997 | */ |
| 20998 | DUK_ASSERT_API_ENTRY(thr); |
| 20999 | (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger); |
| 21000 | return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/); |
| 21001 | } |
| 21002 | |
| 21003 | DUK_EXTERNAL duk_int32_t duk_to_int32(duk_hthread *thr, duk_idx_t idx) { |
| 21004 | duk_tval *tv; |
| 21005 | duk_int32_t ret; |
| 21006 | |
| 21007 | DUK_ASSERT_API_ENTRY(thr); |
| 21008 | |
| 21009 | tv = duk_require_tval(thr, idx); |
| 21010 | DUK_ASSERT(tv != NULL); |
| 21011 | ret = duk_js_toint32(thr, tv); |
| 21012 | |
| 21013 | /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ |
| 21014 | tv = duk_require_tval(thr, idx); |
| 21015 | DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */ |
| 21016 | return ret; |
| 21017 | } |
| 21018 | |
| 21019 | DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_hthread *thr, duk_idx_t idx) { |
| 21020 | duk_tval *tv; |
| 21021 | duk_uint32_t ret; |
| 21022 | |
| 21023 | DUK_ASSERT_API_ENTRY(thr); |
| 21024 | |
| 21025 | tv = duk_require_tval(thr, idx); |
| 21026 | DUK_ASSERT(tv != NULL); |
| 21027 | ret = duk_js_touint32(thr, tv); |
| 21028 | |
| 21029 | /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ |
| 21030 | tv = duk_require_tval(thr, idx); |
| 21031 | DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */ |
| 21032 | return ret; |
| 21033 | } |
| 21034 | |
| 21035 | DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_hthread *thr, duk_idx_t idx) { |
| 21036 | duk_tval *tv; |
| 21037 | duk_uint16_t ret; |
| 21038 | |
| 21039 | DUK_ASSERT_API_ENTRY(thr); |
| 21040 | |
| 21041 | tv = duk_require_tval(thr, idx); |
| 21042 | DUK_ASSERT(tv != NULL); |
| 21043 | ret = duk_js_touint16(thr, tv); |
| 21044 | |
| 21045 | /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */ |
| 21046 | tv = duk_require_tval(thr, idx); |
| 21047 | DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */ |
| 21048 | return ret; |
| 21049 | } |
| 21050 | |
| 21051 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 21052 | /* Special coercion for Uint8ClampedArray. */ |
| 21053 | DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx) { |
| 21054 | duk_double_t d; |
| 21055 | duk_double_t t; |
| 21056 | duk_uint8_t ret; |
| 21057 | |
| 21058 | DUK_ASSERT_API_ENTRY(thr); |
| 21059 | |
| 21060 | /* XXX: Simplify this algorithm, should be possible to come up with |
| 21061 | * a shorter and faster algorithm by inspecting IEEE representation |
| 21062 | * directly. |
| 21063 | */ |
| 21064 | |
| 21065 | d = duk_to_number(thr, idx); |
| 21066 | if (d <= 0.0) { |
| 21067 | return 0; |
| 21068 | } else if (d >= 255) { |
| 21069 | return 255; |
| 21070 | } else if (DUK_ISNAN(d)) { |
| 21071 | /* Avoid NaN-to-integer coercion as it is compiler specific. */ |
| 21072 | return 0; |
| 21073 | } |
| 21074 | |
| 21075 | t = d - DUK_FLOOR(d); |
| 21076 | if (duk_double_equals(t, 0.5)) { |
| 21077 | /* Exact halfway, round to even. */ |
| 21078 | ret = (duk_uint8_t) d; |
| 21079 | ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4 |
| 21080 | * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4 |
| 21081 | */ |
| 21082 | } else { |
| 21083 | /* Not halfway, round to nearest. */ |
| 21084 | ret = (duk_uint8_t) (d + 0.5); |
| 21085 | } |
| 21086 | return ret; |
| 21087 | } |
| 21088 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 21089 | |
| 21090 | DUK_EXTERNAL const char *duk_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { |
| 21091 | DUK_ASSERT_API_ENTRY(thr); |
| 21092 | |
| 21093 | (void) duk_to_string(thr, idx); |
| 21094 | DUK_ASSERT(duk_is_string(thr, idx)); |
| 21095 | return duk_require_lstring(thr, idx, out_len); |
| 21096 | } |
| 21097 | |
| 21098 | DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_hthread *thr, void *udata) { |
| 21099 | DUK_CTX_ASSERT_VALID(thr); |
| 21100 | DUK_UNREF(udata); |
| 21101 | |
| 21102 | (void) duk_to_string(thr, -1); |
| 21103 | return 1; |
| 21104 | } |
| 21105 | |
| 21106 | DUK_EXTERNAL const char *duk_safe_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) { |
| 21107 | DUK_ASSERT_API_ENTRY(thr); |
| 21108 | |
| 21109 | idx = duk_require_normalize_index(thr, idx); |
| 21110 | |
| 21111 | /* We intentionally ignore the duk_safe_call() return value and only |
| 21112 | * check the output type. This way we don't also need to check that |
| 21113 | * the returned value is indeed a string in the success case. |
| 21114 | */ |
| 21115 | |
| 21116 | duk_dup(thr, idx); |
| 21117 | (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); |
| 21118 | if (!duk_is_string(thr, -1)) { |
| 21119 | /* Error: try coercing error to string once. */ |
| 21120 | (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); |
| 21121 | if (!duk_is_string(thr, -1)) { |
| 21122 | /* Double error */ |
| 21123 | duk_pop_unsafe(thr); |
| 21124 | duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR); |
| 21125 | } else { |
| 21126 | ; |
| 21127 | } |
| 21128 | } else { |
| 21129 | /* String; may be a symbol, accepted. */ |
| 21130 | ; |
| 21131 | } |
| 21132 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 21133 | |
| 21134 | duk_replace(thr, idx); |
| 21135 | DUK_ASSERT(duk_get_string(thr, idx) != NULL); |
| 21136 | return duk_get_lstring(thr, idx, out_len); |
| 21137 | } |
| 21138 | |
| 21139 | DUK_EXTERNAL const char *duk_to_stacktrace(duk_hthread *thr, duk_idx_t idx) { |
| 21140 | DUK_ASSERT_API_ENTRY(thr); |
| 21141 | idx = duk_require_normalize_index(thr, idx); |
| 21142 | |
| 21143 | /* The expected argument to the call is an Error object. The stack |
| 21144 | * trace is extracted without an inheritance-based instanceof check |
| 21145 | * so that one can also extract the stack trace of a foreign error |
| 21146 | * created in another Realm. Accept only a string .stack property. |
| 21147 | */ |
| 21148 | if (duk_is_object(thr, idx)) { |
| 21149 | (void) duk_get_prop_string(thr, idx, "stack" ); |
| 21150 | if (duk_is_string(thr, -1)) { |
| 21151 | duk_replace(thr, idx); |
| 21152 | } else { |
| 21153 | duk_pop(thr); |
| 21154 | } |
| 21155 | } |
| 21156 | |
| 21157 | return duk_to_string(thr, idx); |
| 21158 | } |
| 21159 | |
| 21160 | DUK_LOCAL duk_ret_t duk__safe_to_stacktrace_raw(duk_hthread *thr, void *udata) { |
| 21161 | DUK_CTX_ASSERT_VALID(thr); |
| 21162 | DUK_UNREF(udata); |
| 21163 | |
| 21164 | (void) duk_to_stacktrace(thr, -1); |
| 21165 | |
| 21166 | return 1; |
| 21167 | } |
| 21168 | |
| 21169 | DUK_EXTERNAL const char *duk_safe_to_stacktrace(duk_hthread *thr, duk_idx_t idx) { |
| 21170 | duk_int_t rc; |
| 21171 | |
| 21172 | DUK_ASSERT_API_ENTRY(thr); |
| 21173 | idx = duk_require_normalize_index(thr, idx); |
| 21174 | |
| 21175 | duk_dup(thr, idx); |
| 21176 | rc = duk_safe_call(thr, duk__safe_to_stacktrace_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); |
| 21177 | if (rc != 0) { |
| 21178 | /* Coercion failed. Try to coerce the coercion itself error |
| 21179 | * to a stack trace once. If that also fails, return a fixed, |
| 21180 | * preallocated 'Error' string to avoid potential infinite loop. |
| 21181 | */ |
| 21182 | rc = duk_safe_call(thr, duk__safe_to_stacktrace_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/); |
| 21183 | if (rc != 0) { |
| 21184 | duk_pop_unsafe(thr); |
| 21185 | duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR); |
| 21186 | } |
| 21187 | } |
| 21188 | duk_replace(thr, idx); |
| 21189 | |
| 21190 | return duk_get_string(thr, idx); |
| 21191 | } |
| 21192 | |
| 21193 | DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx) { |
| 21194 | duk_hstring *h; |
| 21195 | |
| 21196 | DUK_ASSERT_API_ENTRY(thr); |
| 21197 | |
| 21198 | duk_to_primitive(thr, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */ |
| 21199 | h = duk_get_hstring(thr, idx); |
| 21200 | if (h == NULL) { |
| 21201 | /* The "is string?" check may seem unnecessary, but as things |
| 21202 | * are duk_to_hstring() invokes ToString() which fails for |
| 21203 | * symbols. But since symbols are already strings for Duktape |
| 21204 | * C API, we check for that before doing the coercion. |
| 21205 | */ |
| 21206 | h = duk_to_hstring(thr, idx); |
| 21207 | } |
| 21208 | DUK_ASSERT(h != NULL); |
| 21209 | return h; |
| 21210 | } |
| 21211 | |
| 21212 | #if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */ |
| 21213 | DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) { |
| 21214 | DUK_ASSERT_API_ENTRY(thr); |
| 21215 | |
| 21216 | (void) duk_safe_to_string(thr, idx); |
| 21217 | DUK_ASSERT(duk_is_string(thr, idx)); |
| 21218 | DUK_ASSERT(duk_get_hstring(thr, idx) != NULL); |
| 21219 | return duk_known_hstring(thr, idx); |
| 21220 | } |
| 21221 | #endif |
| 21222 | |
| 21223 | /* Push Object.prototype.toString() output for 'tv'. */ |
| 21224 | DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) { |
| 21225 | duk_hobject *h_obj; |
| 21226 | duk_small_uint_t classnum; |
| 21227 | duk_small_uint_t stridx; |
| 21228 | duk_tval tv_tmp; |
| 21229 | |
| 21230 | DUK_ASSERT_API_ENTRY(thr); |
| 21231 | DUK_ASSERT(tv != NULL); |
| 21232 | |
| 21233 | /* Stabilize 'tv', duk_push_literal() may trigger side effects. */ |
| 21234 | DUK_TVAL_SET_TVAL(&tv_tmp, tv); |
| 21235 | tv = &tv_tmp; |
| 21236 | |
| 21237 | /* Conceptually for any non-undefined/null value we should do a |
| 21238 | * ToObject() coercion and look up @@toStringTag (from the object |
| 21239 | * prototype) to see if a custom result should be used, with the |
| 21240 | * exception of Arrays which are handled specially first. |
| 21241 | * |
| 21242 | * We'd like to avoid the actual conversion, but even for primitive |
| 21243 | * types the prototype may have @@toStringTag. What's worse, the |
| 21244 | * @@toStringTag property may be a getter that must get the object |
| 21245 | * coerced value (not the prototype) as its 'this' binding. |
| 21246 | * |
| 21247 | * For now, do an actual object coercion. This could be avoided by |
| 21248 | * doing a side effect free lookup to see if a getter would be invoked. |
| 21249 | * If not, the value can be read directly and the object coercion could |
| 21250 | * be avoided. This may not be worth it in practice, because |
| 21251 | * Object.prototype.toString() is usually not performance critical. |
| 21252 | */ |
| 21253 | |
| 21254 | duk_push_literal(thr, "[object " ); /* -> [ ... "[object" ] */ |
| 21255 | |
| 21256 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 21257 | case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */ |
| 21258 | case DUK_TAG_UNDEFINED: { |
| 21259 | duk_push_hstring_stridx(thr, DUK_STRIDX_UC_UNDEFINED); |
| 21260 | goto finish; |
| 21261 | } |
| 21262 | case DUK_TAG_NULL: { |
| 21263 | duk_push_hstring_stridx(thr, DUK_STRIDX_UC_NULL); |
| 21264 | goto finish; |
| 21265 | } |
| 21266 | } |
| 21267 | |
| 21268 | duk_push_tval(thr, tv); |
| 21269 | tv = NULL; /* Invalidated by ToObject(). */ |
| 21270 | h_obj = duk_to_hobject(thr, -1); |
| 21271 | DUK_ASSERT(h_obj != NULL); |
| 21272 | if (duk_js_isarray_hobject(h_obj)) { |
| 21273 | stridx = DUK_STRIDX_UC_ARRAY; |
| 21274 | } else { |
| 21275 | /* [ ... "[object" obj ] */ |
| 21276 | |
| 21277 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 21278 | /* XXX: better handling with avoid_side_effects == 1; lookup tval |
| 21279 | * without Proxy or getter side effects, and use it in sanitized |
| 21280 | * form if it's a string. |
| 21281 | */ |
| 21282 | if (!avoid_side_effects) { |
| 21283 | (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG); |
| 21284 | if (duk_is_string_notsymbol(thr, -1)) { |
| 21285 | duk_remove_m2(thr); |
| 21286 | goto finish; |
| 21287 | } |
| 21288 | duk_pop_unsafe(thr); |
| 21289 | } |
| 21290 | #else |
| 21291 | DUK_UNREF(avoid_side_effects); |
| 21292 | #endif |
| 21293 | |
| 21294 | classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj); |
| 21295 | stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum); |
| 21296 | } |
| 21297 | duk_pop_unsafe(thr); |
| 21298 | duk_push_hstring_stridx(thr, stridx); |
| 21299 | |
| 21300 | finish: |
| 21301 | /* [ ... "[object" tag ] */ |
| 21302 | duk_push_literal(thr, "]" ); |
| 21303 | duk_concat(thr, 3); /* [ ... "[object" tag "]" ] -> [ ... res ] */ |
| 21304 | } |
| 21305 | |
| 21306 | /* XXX: other variants like uint, u32 etc */ |
| 21307 | DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) { |
| 21308 | duk_tval *tv; |
| 21309 | duk_tval tv_tmp; |
| 21310 | duk_double_t d, dmin, dmax; |
| 21311 | duk_int_t res; |
| 21312 | duk_bool_t clamped = 0; |
| 21313 | |
| 21314 | DUK_ASSERT_API_ENTRY(thr); |
| 21315 | |
| 21316 | tv = duk_require_tval(thr, idx); |
| 21317 | DUK_ASSERT(tv != NULL); |
| 21318 | d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */ |
| 21319 | |
| 21320 | dmin = (duk_double_t) minval; |
| 21321 | dmax = (duk_double_t) maxval; |
| 21322 | |
| 21323 | if (d < dmin) { |
| 21324 | clamped = 1; |
| 21325 | res = minval; |
| 21326 | d = dmin; |
| 21327 | } else if (d > dmax) { |
| 21328 | clamped = 1; |
| 21329 | res = maxval; |
| 21330 | d = dmax; |
| 21331 | } else { |
| 21332 | res = (duk_int_t) d; |
| 21333 | } |
| 21334 | DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */ |
| 21335 | /* 'd' and 'res' agree here */ |
| 21336 | |
| 21337 | /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */ |
| 21338 | tv = duk_get_tval(thr, idx); |
| 21339 | DUK_ASSERT(tv != NULL); /* not popped by side effect */ |
| 21340 | DUK_TVAL_SET_TVAL(&tv_tmp, tv); |
| 21341 | #if defined(DUK_USE_FASTINT) |
| 21342 | #if (DUK_INT_MAX <= 0x7fffffffL) |
| 21343 | DUK_TVAL_SET_I32(tv, res); |
| 21344 | #else |
| 21345 | /* Clamping needed if duk_int_t is 64 bits. */ |
| 21346 | if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) { |
| 21347 | DUK_TVAL_SET_FASTINT(tv, res); |
| 21348 | } else { |
| 21349 | DUK_TVAL_SET_NUMBER(tv, d); |
| 21350 | } |
| 21351 | #endif |
| 21352 | #else |
| 21353 | DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */ |
| 21354 | #endif |
| 21355 | DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */ |
| 21356 | |
| 21357 | if (out_clamped) { |
| 21358 | *out_clamped = clamped; |
| 21359 | } else { |
| 21360 | /* coerced value is updated to value stack even when RangeError thrown */ |
| 21361 | if (clamped) { |
| 21362 | DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE); |
| 21363 | DUK_WO_NORETURN(return 0;); |
| 21364 | } |
| 21365 | } |
| 21366 | |
| 21367 | return res; |
| 21368 | } |
| 21369 | |
| 21370 | DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) { |
| 21371 | duk_bool_t dummy; |
| 21372 | |
| 21373 | DUK_ASSERT_API_ENTRY(thr); |
| 21374 | |
| 21375 | return duk_to_int_clamped_raw(thr, idx, minval, maxval, &dummy); |
| 21376 | } |
| 21377 | |
| 21378 | DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) { |
| 21379 | DUK_ASSERT_API_ENTRY(thr); |
| 21380 | return duk_to_int_clamped_raw(thr, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */ |
| 21381 | } |
| 21382 | |
| 21383 | DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) { |
| 21384 | duk_tval *tv; |
| 21385 | |
| 21386 | DUK_ASSERT_API_ENTRY(thr); |
| 21387 | |
| 21388 | idx = duk_require_normalize_index(thr, idx); |
| 21389 | tv = DUK_GET_TVAL_POSIDX(thr, idx); |
| 21390 | DUK_ASSERT(tv != NULL); |
| 21391 | |
| 21392 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 21393 | case DUK_TAG_UNDEFINED: { |
| 21394 | duk_push_hstring_stridx(thr, DUK_STRIDX_LC_UNDEFINED); |
| 21395 | break; |
| 21396 | } |
| 21397 | case DUK_TAG_NULL: { |
| 21398 | duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL); |
| 21399 | break; |
| 21400 | } |
| 21401 | case DUK_TAG_BOOLEAN: { |
| 21402 | if (DUK_TVAL_GET_BOOLEAN(tv)) { |
| 21403 | duk_push_hstring_stridx(thr, DUK_STRIDX_TRUE); |
| 21404 | } else { |
| 21405 | duk_push_hstring_stridx(thr, DUK_STRIDX_FALSE); |
| 21406 | } |
| 21407 | break; |
| 21408 | } |
| 21409 | case DUK_TAG_STRING: { |
| 21410 | /* Nop for actual strings, TypeError for Symbols. |
| 21411 | * Because various internals rely on ToString() coercion of |
| 21412 | * internal strings, -allow- (NOP) string coercion for hidden |
| 21413 | * symbols. |
| 21414 | */ |
| 21415 | #if 1 |
| 21416 | duk_hstring *h; |
| 21417 | h = DUK_TVAL_GET_STRING(tv); |
| 21418 | DUK_ASSERT(h != NULL); |
| 21419 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 21420 | DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL); |
| 21421 | DUK_WO_NORETURN(goto skip_replace;); |
| 21422 | } else { |
| 21423 | goto skip_replace; |
| 21424 | } |
| 21425 | #else |
| 21426 | goto skip_replace; |
| 21427 | #endif |
| 21428 | break; |
| 21429 | } |
| 21430 | case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */ |
| 21431 | case DUK_TAG_OBJECT: { |
| 21432 | /* Plain buffers: go through ArrayBuffer.prototype.toString() |
| 21433 | * for coercion. |
| 21434 | * |
| 21435 | * Symbol objects: duk_to_primitive() results in a plain symbol |
| 21436 | * value, and duk_to_string() then causes a TypeError. |
| 21437 | */ |
| 21438 | duk_to_primitive(thr, idx, DUK_HINT_STRING); |
| 21439 | DUK_ASSERT(!duk_is_buffer(thr, idx)); /* ToPrimitive() must guarantee */ |
| 21440 | DUK_ASSERT(!duk_is_object(thr, idx)); |
| 21441 | return duk_to_string(thr, idx); /* Note: recursive call */ |
| 21442 | } |
| 21443 | case DUK_TAG_POINTER: { |
| 21444 | void *ptr = DUK_TVAL_GET_POINTER(tv); |
| 21445 | if (ptr != NULL) { |
| 21446 | duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) ptr); |
| 21447 | } else { |
| 21448 | /* Represent a null pointer as 'null' to be consistent with |
| 21449 | * the JX format variant. Native '%p' format for a NULL |
| 21450 | * pointer may be e.g. '(nil)'. |
| 21451 | */ |
| 21452 | duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL); |
| 21453 | } |
| 21454 | break; |
| 21455 | } |
| 21456 | case DUK_TAG_LIGHTFUNC: { |
| 21457 | /* Should match Function.prototype.toString() */ |
| 21458 | duk_push_lightfunc_tostring(thr, tv); |
| 21459 | break; |
| 21460 | } |
| 21461 | #if defined(DUK_USE_FASTINT) |
| 21462 | case DUK_TAG_FASTINT: |
| 21463 | #endif |
| 21464 | default: { |
| 21465 | /* number */ |
| 21466 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 21467 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 21468 | duk_push_tval(thr, tv); |
| 21469 | duk_numconv_stringify(thr, |
| 21470 | 10 /*radix*/, |
| 21471 | 0 /*precision:shortest*/, |
| 21472 | 0 /*force_exponential*/); |
| 21473 | break; |
| 21474 | } |
| 21475 | } |
| 21476 | |
| 21477 | duk_replace(thr, idx); |
| 21478 | |
| 21479 | skip_replace: |
| 21480 | DUK_ASSERT(duk_is_string(thr, idx)); |
| 21481 | return duk_require_string(thr, idx); |
| 21482 | } |
| 21483 | |
| 21484 | DUK_INTERNAL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx) { |
| 21485 | duk_hstring *ret; |
| 21486 | |
| 21487 | DUK_ASSERT_API_ENTRY(thr); |
| 21488 | |
| 21489 | duk_to_string(thr, idx); |
| 21490 | ret = duk_get_hstring(thr, idx); |
| 21491 | DUK_ASSERT(ret != NULL); |
| 21492 | return ret; |
| 21493 | } |
| 21494 | |
| 21495 | DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_hthread *thr) { |
| 21496 | DUK_ASSERT_API_ENTRY(thr); |
| 21497 | return duk_to_hstring(thr, -1); |
| 21498 | } |
| 21499 | |
| 21500 | DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx) { |
| 21501 | duk_hstring *ret; |
| 21502 | |
| 21503 | DUK_ASSERT_API_ENTRY(thr); |
| 21504 | |
| 21505 | ret = duk_get_hstring(thr, idx); |
| 21506 | if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) { |
| 21507 | return ret; |
| 21508 | } |
| 21509 | return duk_to_hstring(thr, idx); |
| 21510 | } |
| 21511 | |
| 21512 | /* Convert a plain buffer or any buffer object into a string, using the buffer |
| 21513 | * bytes 1:1 in the internal string representation. For views the active byte |
| 21514 | * slice (not element slice interpreted as an initializer) is used. This is |
| 21515 | * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a |
| 21516 | * string with the same bytes as in the buffer but rather (usually) |
| 21517 | * '[object ArrayBuffer]'. |
| 21518 | */ |
| 21519 | DUK_EXTERNAL const char *duk_buffer_to_string(duk_hthread *thr, duk_idx_t idx) { |
| 21520 | void *ptr_src; |
| 21521 | duk_size_t len; |
| 21522 | const char *res; |
| 21523 | |
| 21524 | DUK_ASSERT_API_ENTRY(thr); |
| 21525 | |
| 21526 | idx = duk_require_normalize_index(thr, idx); |
| 21527 | |
| 21528 | ptr_src = duk_require_buffer_data(thr, idx, &len); |
| 21529 | DUK_ASSERT(ptr_src != NULL || len == 0); |
| 21530 | |
| 21531 | res = duk_push_lstring(thr, (const char *) ptr_src, len); |
| 21532 | duk_replace(thr, idx); |
| 21533 | return res; |
| 21534 | } |
| 21535 | |
| 21536 | DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) { |
| 21537 | duk_hbuffer *h_buf; |
| 21538 | const duk_uint8_t *src_data; |
| 21539 | duk_size_t src_size; |
| 21540 | duk_uint8_t *dst_data; |
| 21541 | |
| 21542 | DUK_ASSERT_API_ENTRY(thr); |
| 21543 | |
| 21544 | idx = duk_require_normalize_index(thr, idx); |
| 21545 | |
| 21546 | h_buf = duk_get_hbuffer(thr, idx); |
| 21547 | if (h_buf != NULL) { |
| 21548 | /* Buffer is kept as is, with the fixed/dynamic nature of the |
| 21549 | * buffer only changed if requested. An external buffer |
| 21550 | * is converted into a non-external dynamic buffer in a |
| 21551 | * duk_to_dynamic_buffer() call. |
| 21552 | */ |
| 21553 | duk_uint_t tmp; |
| 21554 | duk_uint8_t *tmp_ptr; |
| 21555 | |
| 21556 | tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf); |
| 21557 | src_data = (const duk_uint8_t *) tmp_ptr; |
| 21558 | src_size = DUK_HBUFFER_GET_SIZE(h_buf); |
| 21559 | |
| 21560 | tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED); |
| 21561 | if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) || |
| 21562 | mode == DUK_BUF_MODE_DONTCARE) { |
| 21563 | /* Note: src_data may be NULL if input is a zero-size |
| 21564 | * dynamic buffer. |
| 21565 | */ |
| 21566 | dst_data = tmp_ptr; |
| 21567 | goto skip_copy; |
| 21568 | } |
| 21569 | } else { |
| 21570 | /* Non-buffer value is first ToString() coerced, then converted |
| 21571 | * to a buffer (fixed buffer is used unless a dynamic buffer is |
| 21572 | * explicitly requested). Symbols are rejected with a TypeError. |
| 21573 | * XXX: C API could maybe allow symbol-to-buffer coercion? |
| 21574 | */ |
| 21575 | src_data = (const duk_uint8_t *) duk_to_lstring(thr, idx, &src_size); |
| 21576 | } |
| 21577 | |
| 21578 | dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/); |
| 21579 | /* dst_data may be NULL if size is zero. */ |
| 21580 | duk_memcpy_unsafe((void *) dst_data, (const void *) src_data, (size_t) src_size); |
| 21581 | |
| 21582 | duk_replace(thr, idx); |
| 21583 | skip_copy: |
| 21584 | |
| 21585 | if (out_size) { |
| 21586 | *out_size = src_size; |
| 21587 | } |
| 21588 | return dst_data; |
| 21589 | } |
| 21590 | |
| 21591 | DUK_EXTERNAL void *duk_to_pointer(duk_hthread *thr, duk_idx_t idx) { |
| 21592 | duk_tval *tv; |
| 21593 | void *res; |
| 21594 | |
| 21595 | DUK_ASSERT_API_ENTRY(thr); |
| 21596 | |
| 21597 | idx = duk_require_normalize_index(thr, idx); |
| 21598 | tv = DUK_GET_TVAL_POSIDX(thr, idx); |
| 21599 | DUK_ASSERT(tv != NULL); |
| 21600 | |
| 21601 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 21602 | case DUK_TAG_UNDEFINED: |
| 21603 | case DUK_TAG_NULL: |
| 21604 | case DUK_TAG_BOOLEAN: |
| 21605 | res = NULL; |
| 21606 | break; |
| 21607 | case DUK_TAG_POINTER: |
| 21608 | res = DUK_TVAL_GET_POINTER(tv); |
| 21609 | break; |
| 21610 | case DUK_TAG_STRING: |
| 21611 | case DUK_TAG_OBJECT: |
| 21612 | case DUK_TAG_BUFFER: |
| 21613 | /* Heap allocated: return heap pointer which is NOT useful |
| 21614 | * for the caller, except for debugging. |
| 21615 | */ |
| 21616 | res = (void *) DUK_TVAL_GET_HEAPHDR(tv); |
| 21617 | break; |
| 21618 | case DUK_TAG_LIGHTFUNC: |
| 21619 | /* Function pointers do not always cast correctly to void * |
| 21620 | * (depends on memory and segmentation model for instance), |
| 21621 | * so they coerce to NULL. |
| 21622 | */ |
| 21623 | res = NULL; |
| 21624 | break; |
| 21625 | #if defined(DUK_USE_FASTINT) |
| 21626 | case DUK_TAG_FASTINT: |
| 21627 | #endif |
| 21628 | default: |
| 21629 | /* number */ |
| 21630 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 21631 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 21632 | res = NULL; |
| 21633 | break; |
| 21634 | } |
| 21635 | |
| 21636 | duk_push_pointer(thr, res); |
| 21637 | duk_replace(thr, idx); |
| 21638 | return res; |
| 21639 | } |
| 21640 | |
| 21641 | DUK_LOCAL void duk__push_func_from_lightfunc(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) { |
| 21642 | duk_idx_t nargs; |
| 21643 | duk_uint_t flags = 0; /* shared flags for a subset of types */ |
| 21644 | duk_small_uint_t lf_len; |
| 21645 | duk_hnatfunc *nf; |
| 21646 | |
| 21647 | nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags); |
| 21648 | if (nargs == DUK_LFUNC_NARGS_VARARGS) { |
| 21649 | nargs = (duk_idx_t) DUK_VARARGS; |
| 21650 | } |
| 21651 | |
| 21652 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 21653 | DUK_HOBJECT_FLAG_CONSTRUCTABLE | |
| 21654 | DUK_HOBJECT_FLAG_CALLABLE | |
| 21655 | DUK_HOBJECT_FLAG_FASTREFS | |
| 21656 | DUK_HOBJECT_FLAG_NATFUNC | |
| 21657 | DUK_HOBJECT_FLAG_NEWENV | |
| 21658 | DUK_HOBJECT_FLAG_STRICT | |
| 21659 | DUK_HOBJECT_FLAG_NOTAIL | |
| 21660 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); |
| 21661 | (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE); |
| 21662 | |
| 21663 | lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); |
| 21664 | if ((duk_idx_t) lf_len != nargs) { |
| 21665 | /* Explicit length is only needed if it differs from 'nargs'. */ |
| 21666 | duk_push_int(thr, (duk_int_t) lf_len); |
| 21667 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); |
| 21668 | } |
| 21669 | |
| 21670 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 21671 | duk_push_lightfunc_name_raw(thr, func, lf_flags); |
| 21672 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); |
| 21673 | #endif |
| 21674 | |
| 21675 | nf = duk_known_hnatfunc(thr, -1); |
| 21676 | nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); |
| 21677 | } |
| 21678 | |
| 21679 | DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) { |
| 21680 | duk_tval *tv; |
| 21681 | duk_uint_t flags = 0; /* shared flags for a subset of types */ |
| 21682 | duk_small_int_t proto = 0; |
| 21683 | |
| 21684 | DUK_ASSERT_API_ENTRY(thr); |
| 21685 | |
| 21686 | idx = duk_require_normalize_index(thr, idx); |
| 21687 | tv = DUK_GET_TVAL_POSIDX(thr, idx); |
| 21688 | DUK_ASSERT(tv != NULL); |
| 21689 | |
| 21690 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 21691 | #if !defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 21692 | case DUK_TAG_BUFFER: /* With no bufferobject support, don't object coerce. */ |
| 21693 | #endif |
| 21694 | case DUK_TAG_UNDEFINED: |
| 21695 | case DUK_TAG_NULL: { |
| 21696 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); |
| 21697 | DUK_WO_NORETURN(return;); |
| 21698 | break; |
| 21699 | } |
| 21700 | case DUK_TAG_BOOLEAN: { |
| 21701 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 21702 | DUK_HOBJECT_FLAG_FASTREFS | |
| 21703 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN); |
| 21704 | proto = DUK_BIDX_BOOLEAN_PROTOTYPE; |
| 21705 | goto create_object; |
| 21706 | } |
| 21707 | case DUK_TAG_STRING: { |
| 21708 | duk_hstring *h; |
| 21709 | h = DUK_TVAL_GET_STRING(tv); |
| 21710 | DUK_ASSERT(h != NULL); |
| 21711 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 21712 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 21713 | DUK_HOBJECT_FLAG_FASTREFS | |
| 21714 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL); |
| 21715 | proto = DUK_BIDX_SYMBOL_PROTOTYPE; |
| 21716 | } else { |
| 21717 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 21718 | DUK_HOBJECT_FLAG_FASTREFS | |
| 21719 | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | |
| 21720 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); |
| 21721 | proto = DUK_BIDX_STRING_PROTOTYPE; |
| 21722 | } |
| 21723 | goto create_object; |
| 21724 | } |
| 21725 | case DUK_TAG_OBJECT: { |
| 21726 | /* nop */ |
| 21727 | break; |
| 21728 | } |
| 21729 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 21730 | case DUK_TAG_BUFFER: { |
| 21731 | /* A plain buffer object coerces to a full ArrayBuffer which |
| 21732 | * is not fully transparent behavior (ToObject() should be a |
| 21733 | * nop for an object). This behavior matches lightfuncs which |
| 21734 | * also coerce to an equivalent Function object. There are |
| 21735 | * also downsides to defining ToObject(plainBuffer) as a no-op; |
| 21736 | * for example duk_to_hobject() could result in a NULL pointer. |
| 21737 | */ |
| 21738 | duk_hbuffer *h_buf; |
| 21739 | |
| 21740 | h_buf = DUK_TVAL_GET_BUFFER(tv); |
| 21741 | DUK_ASSERT(h_buf != NULL); |
| 21742 | duk_hbufobj_push_uint8array_from_plain(thr, h_buf); |
| 21743 | goto replace_value; |
| 21744 | } |
| 21745 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 21746 | case DUK_TAG_POINTER: { |
| 21747 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 21748 | DUK_HOBJECT_FLAG_FASTREFS | |
| 21749 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER); |
| 21750 | proto = DUK_BIDX_POINTER_PROTOTYPE; |
| 21751 | goto create_object; |
| 21752 | } |
| 21753 | case DUK_TAG_LIGHTFUNC: { |
| 21754 | /* Lightfunc coerces to a Function instance with concrete |
| 21755 | * properties. Since 'length' is virtual for Duktape/C |
| 21756 | * functions, don't need to define that. The result is made |
| 21757 | * extensible to mimic what happens to strings in object |
| 21758 | * coercion: |
| 21759 | * |
| 21760 | * > Object.isExtensible(Object('foo')) |
| 21761 | * true |
| 21762 | */ |
| 21763 | duk_small_uint_t lf_flags; |
| 21764 | duk_c_function func; |
| 21765 | |
| 21766 | DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); |
| 21767 | duk__push_func_from_lightfunc(thr, func, lf_flags); |
| 21768 | goto replace_value; |
| 21769 | } |
| 21770 | #if defined(DUK_USE_FASTINT) |
| 21771 | case DUK_TAG_FASTINT: |
| 21772 | #endif |
| 21773 | default: { |
| 21774 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 21775 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 21776 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 21777 | DUK_HOBJECT_FLAG_FASTREFS | |
| 21778 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER); |
| 21779 | proto = DUK_BIDX_NUMBER_PROTOTYPE; |
| 21780 | goto create_object; |
| 21781 | } |
| 21782 | } |
| 21783 | DUK_ASSERT(duk_is_object(thr, idx)); |
| 21784 | return; |
| 21785 | |
| 21786 | create_object: |
| 21787 | (void) duk_push_object_helper(thr, flags, proto); |
| 21788 | |
| 21789 | /* Note: Boolean prototype's internal value property is not writable, |
| 21790 | * but duk_xdef_prop_stridx() disregards the write protection. Boolean |
| 21791 | * instances are immutable. |
| 21792 | * |
| 21793 | * String and buffer special behaviors are already enabled which is not |
| 21794 | * ideal, but a write to the internal value is not affected by them. |
| 21795 | */ |
| 21796 | duk_dup(thr, idx); |
| 21797 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); |
| 21798 | |
| 21799 | replace_value: |
| 21800 | duk_replace(thr, idx); |
| 21801 | DUK_ASSERT(duk_is_object(thr, idx)); |
| 21802 | } |
| 21803 | |
| 21804 | DUK_INTERNAL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx) { |
| 21805 | duk_hobject *ret; |
| 21806 | |
| 21807 | DUK_ASSERT_API_ENTRY(thr); |
| 21808 | |
| 21809 | duk_to_object(thr, idx); |
| 21810 | ret = duk_known_hobject(thr, idx); |
| 21811 | return ret; |
| 21812 | } |
| 21813 | |
| 21814 | /* |
| 21815 | * Type checking |
| 21816 | */ |
| 21817 | |
| 21818 | DUK_LOCAL duk_bool_t duk__tag_check(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t tag) { |
| 21819 | duk_tval *tv; |
| 21820 | |
| 21821 | tv = duk_get_tval_or_unused(thr, idx); |
| 21822 | DUK_ASSERT(tv != NULL); |
| 21823 | return (DUK_TVAL_GET_TAG(tv) == tag); |
| 21824 | } |
| 21825 | |
| 21826 | DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_hthread *thr, duk_idx_t idx, duk_uint_t flag_mask) { |
| 21827 | duk_hobject *obj; |
| 21828 | |
| 21829 | DUK_ASSERT_API_ENTRY(thr); |
| 21830 | |
| 21831 | obj = duk_get_hobject(thr, idx); |
| 21832 | if (obj) { |
| 21833 | return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0); |
| 21834 | } |
| 21835 | return 0; |
| 21836 | } |
| 21837 | |
| 21838 | DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) { |
| 21839 | DUK_ASSERT(tv != NULL); |
| 21840 | |
| 21841 | #if defined(DUK_USE_PACKED_TVAL) |
| 21842 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 21843 | case DUK_TAG_UNUSED: |
| 21844 | return DUK_TYPE_NONE; |
| 21845 | case DUK_TAG_UNDEFINED: |
| 21846 | return DUK_TYPE_UNDEFINED; |
| 21847 | case DUK_TAG_NULL: |
| 21848 | return DUK_TYPE_NULL; |
| 21849 | case DUK_TAG_BOOLEAN: |
| 21850 | return DUK_TYPE_BOOLEAN; |
| 21851 | case DUK_TAG_STRING: |
| 21852 | return DUK_TYPE_STRING; |
| 21853 | case DUK_TAG_OBJECT: |
| 21854 | return DUK_TYPE_OBJECT; |
| 21855 | case DUK_TAG_BUFFER: |
| 21856 | return DUK_TYPE_BUFFER; |
| 21857 | case DUK_TAG_POINTER: |
| 21858 | return DUK_TYPE_POINTER; |
| 21859 | case DUK_TAG_LIGHTFUNC: |
| 21860 | return DUK_TYPE_LIGHTFUNC; |
| 21861 | #if defined(DUK_USE_FASTINT) |
| 21862 | case DUK_TAG_FASTINT: |
| 21863 | #endif |
| 21864 | default: |
| 21865 | /* Note: number has no explicit tag (in 8-byte representation) */ |
| 21866 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 21867 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 21868 | return DUK_TYPE_NUMBER; |
| 21869 | } |
| 21870 | #else /* DUK_USE_PACKED_TVAL */ |
| 21871 | DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv)); |
| 21872 | DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1); |
| 21873 | return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN]; |
| 21874 | #endif /* DUK_USE_PACKED_TVAL */ |
| 21875 | } |
| 21876 | |
| 21877 | DUK_EXTERNAL duk_int_t duk_get_type(duk_hthread *thr, duk_idx_t idx) { |
| 21878 | duk_tval *tv; |
| 21879 | |
| 21880 | DUK_ASSERT_API_ENTRY(thr); |
| 21881 | |
| 21882 | tv = duk_get_tval_or_unused(thr, idx); |
| 21883 | DUK_ASSERT(tv != NULL); |
| 21884 | |
| 21885 | return duk_get_type_tval(tv); |
| 21886 | } |
| 21887 | |
| 21888 | #if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS) |
| 21889 | DUK_LOCAL const char * const duk__type_names[] = { |
| 21890 | "none" , |
| 21891 | "undefined" , |
| 21892 | "null" , |
| 21893 | "boolean" , |
| 21894 | "number" , |
| 21895 | "string" , |
| 21896 | "object" , |
| 21897 | "buffer" , |
| 21898 | "pointer" , |
| 21899 | "lightfunc" |
| 21900 | }; |
| 21901 | |
| 21902 | DUK_INTERNAL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx) { |
| 21903 | duk_int_t type_tag; |
| 21904 | |
| 21905 | DUK_ASSERT_API_ENTRY(thr); |
| 21906 | |
| 21907 | type_tag = duk_get_type(thr, idx); |
| 21908 | DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX); |
| 21909 | DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1); |
| 21910 | |
| 21911 | return duk__type_names[type_tag]; |
| 21912 | } |
| 21913 | #endif /* DUK_USE_VERBOSE_ERRORS && DUK_USE_PARANOID_ERRORS */ |
| 21914 | |
| 21915 | DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx) { |
| 21916 | duk_tval *tv; |
| 21917 | duk_hobject *obj; |
| 21918 | |
| 21919 | DUK_ASSERT_API_ENTRY(thr); |
| 21920 | |
| 21921 | tv = duk_get_tval_or_unused(thr, idx); |
| 21922 | DUK_ASSERT(tv != NULL); |
| 21923 | |
| 21924 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 21925 | case DUK_TAG_OBJECT: |
| 21926 | obj = DUK_TVAL_GET_OBJECT(tv); |
| 21927 | DUK_ASSERT(obj != NULL); |
| 21928 | return DUK_HOBJECT_GET_CLASS_NUMBER(obj); |
| 21929 | case DUK_TAG_BUFFER: |
| 21930 | /* Buffers behave like Uint8Array objects. */ |
| 21931 | return DUK_HOBJECT_CLASS_UINT8ARRAY; |
| 21932 | case DUK_TAG_LIGHTFUNC: |
| 21933 | /* Lightfuncs behave like Function objects. */ |
| 21934 | return DUK_HOBJECT_CLASS_FUNCTION; |
| 21935 | default: |
| 21936 | /* Primitive or UNUSED, no class number. */ |
| 21937 | return DUK_HOBJECT_CLASS_NONE; |
| 21938 | } |
| 21939 | } |
| 21940 | |
| 21941 | DUK_EXTERNAL duk_bool_t duk_check_type(duk_hthread *thr, duk_idx_t idx, duk_int_t type) { |
| 21942 | DUK_ASSERT_API_ENTRY(thr); |
| 21943 | |
| 21944 | return (duk_get_type(thr, idx) == type) ? 1 : 0; |
| 21945 | } |
| 21946 | |
| 21947 | DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) { |
| 21948 | DUK_ASSERT(tv != NULL); |
| 21949 | |
| 21950 | #if defined(DUK_USE_PACKED_TVAL) |
| 21951 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 21952 | case DUK_TAG_UNUSED: |
| 21953 | return DUK_TYPE_MASK_NONE; |
| 21954 | case DUK_TAG_UNDEFINED: |
| 21955 | return DUK_TYPE_MASK_UNDEFINED; |
| 21956 | case DUK_TAG_NULL: |
| 21957 | return DUK_TYPE_MASK_NULL; |
| 21958 | case DUK_TAG_BOOLEAN: |
| 21959 | return DUK_TYPE_MASK_BOOLEAN; |
| 21960 | case DUK_TAG_STRING: |
| 21961 | return DUK_TYPE_MASK_STRING; |
| 21962 | case DUK_TAG_OBJECT: |
| 21963 | return DUK_TYPE_MASK_OBJECT; |
| 21964 | case DUK_TAG_BUFFER: |
| 21965 | return DUK_TYPE_MASK_BUFFER; |
| 21966 | case DUK_TAG_POINTER: |
| 21967 | return DUK_TYPE_MASK_POINTER; |
| 21968 | case DUK_TAG_LIGHTFUNC: |
| 21969 | return DUK_TYPE_MASK_LIGHTFUNC; |
| 21970 | #if defined(DUK_USE_FASTINT) |
| 21971 | case DUK_TAG_FASTINT: |
| 21972 | #endif |
| 21973 | default: |
| 21974 | /* Note: number has no explicit tag (in 8-byte representation) */ |
| 21975 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 21976 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 21977 | return DUK_TYPE_MASK_NUMBER; |
| 21978 | } |
| 21979 | #else /* DUK_USE_PACKED_TVAL */ |
| 21980 | DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv)); |
| 21981 | DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1); |
| 21982 | return duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN]; |
| 21983 | #endif /* DUK_USE_PACKED_TVAL */ |
| 21984 | } |
| 21985 | |
| 21986 | DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_hthread *thr, duk_idx_t idx) { |
| 21987 | duk_tval *tv; |
| 21988 | |
| 21989 | DUK_ASSERT_API_ENTRY(thr); |
| 21990 | |
| 21991 | tv = duk_get_tval_or_unused(thr, idx); |
| 21992 | DUK_ASSERT(tv != NULL); |
| 21993 | |
| 21994 | return duk_get_type_mask_tval(tv); |
| 21995 | } |
| 21996 | |
| 21997 | DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t mask) { |
| 21998 | DUK_ASSERT_API_ENTRY(thr); |
| 21999 | |
| 22000 | if (DUK_LIKELY((duk_get_type_mask(thr, idx) & mask) != 0U)) { |
| 22001 | return 1; |
| 22002 | } |
| 22003 | if (mask & DUK_TYPE_MASK_THROW) { |
| 22004 | DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); |
| 22005 | DUK_WO_NORETURN(return 0;); |
| 22006 | } |
| 22007 | return 0; |
| 22008 | } |
| 22009 | |
| 22010 | DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx) { |
| 22011 | DUK_ASSERT_API_ENTRY(thr); |
| 22012 | return duk__tag_check(thr, idx, DUK_TAG_UNDEFINED); |
| 22013 | } |
| 22014 | |
| 22015 | DUK_EXTERNAL duk_bool_t duk_is_null(duk_hthread *thr, duk_idx_t idx) { |
| 22016 | DUK_ASSERT_API_ENTRY(thr); |
| 22017 | return duk__tag_check(thr, idx, DUK_TAG_NULL); |
| 22018 | } |
| 22019 | |
| 22020 | DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx) { |
| 22021 | DUK_ASSERT_API_ENTRY(thr); |
| 22022 | return duk__tag_check(thr, idx, DUK_TAG_BOOLEAN); |
| 22023 | } |
| 22024 | |
| 22025 | DUK_EXTERNAL duk_bool_t duk_is_number(duk_hthread *thr, duk_idx_t idx) { |
| 22026 | duk_tval *tv; |
| 22027 | |
| 22028 | DUK_ASSERT_API_ENTRY(thr); |
| 22029 | |
| 22030 | /* |
| 22031 | * Number is special because it doesn't have a specific |
| 22032 | * tag in the 8-byte representation. |
| 22033 | */ |
| 22034 | |
| 22035 | /* XXX: shorter version for unpacked representation? */ |
| 22036 | |
| 22037 | tv = duk_get_tval_or_unused(thr, idx); |
| 22038 | DUK_ASSERT(tv != NULL); |
| 22039 | return DUK_TVAL_IS_NUMBER(tv); |
| 22040 | } |
| 22041 | |
| 22042 | DUK_EXTERNAL duk_bool_t duk_is_nan(duk_hthread *thr, duk_idx_t idx) { |
| 22043 | /* XXX: This will now return false for non-numbers, even though they would |
| 22044 | * coerce to NaN (as a general rule). In particular, duk_get_number() |
| 22045 | * returns a NaN for non-numbers, so should this function also return |
| 22046 | * true for non-numbers? |
| 22047 | */ |
| 22048 | |
| 22049 | duk_tval *tv; |
| 22050 | |
| 22051 | DUK_ASSERT_API_ENTRY(thr); |
| 22052 | |
| 22053 | tv = duk_get_tval_or_unused(thr, idx); |
| 22054 | DUK_ASSERT(tv != NULL); |
| 22055 | |
| 22056 | /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */ |
| 22057 | if (!DUK_TVAL_IS_NUMBER(tv)) { |
| 22058 | return 0; |
| 22059 | } |
| 22060 | return (duk_bool_t) DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv)); |
| 22061 | } |
| 22062 | |
| 22063 | DUK_EXTERNAL duk_bool_t duk_is_string(duk_hthread *thr, duk_idx_t idx) { |
| 22064 | DUK_ASSERT_API_ENTRY(thr); |
| 22065 | return duk__tag_check(thr, idx, DUK_TAG_STRING); |
| 22066 | } |
| 22067 | |
| 22068 | DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx) { |
| 22069 | DUK_ASSERT_API_ENTRY(thr); |
| 22070 | return duk_get_hstring_notsymbol(thr, idx) != NULL; |
| 22071 | } |
| 22072 | |
| 22073 | DUK_EXTERNAL duk_bool_t duk_is_object(duk_hthread *thr, duk_idx_t idx) { |
| 22074 | DUK_ASSERT_API_ENTRY(thr); |
| 22075 | return duk__tag_check(thr, idx, DUK_TAG_OBJECT); |
| 22076 | } |
| 22077 | |
| 22078 | DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_hthread *thr, duk_idx_t idx) { |
| 22079 | DUK_ASSERT_API_ENTRY(thr); |
| 22080 | return duk__tag_check(thr, idx, DUK_TAG_BUFFER); |
| 22081 | } |
| 22082 | |
| 22083 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 22084 | DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) { |
| 22085 | duk_tval *tv; |
| 22086 | |
| 22087 | DUK_ASSERT_API_ENTRY(thr); |
| 22088 | |
| 22089 | tv = duk_get_tval_or_unused(thr, idx); |
| 22090 | DUK_ASSERT(tv != NULL); |
| 22091 | if (DUK_TVAL_IS_BUFFER(tv)) { |
| 22092 | return 1; |
| 22093 | } else if (DUK_TVAL_IS_OBJECT(tv)) { |
| 22094 | duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); |
| 22095 | DUK_ASSERT(h != NULL); |
| 22096 | if (DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 22097 | return 1; |
| 22098 | } |
| 22099 | } |
| 22100 | return 0; |
| 22101 | } |
| 22102 | #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 22103 | DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) { |
| 22104 | DUK_ASSERT_API_ENTRY(thr); |
| 22105 | |
| 22106 | return duk_is_buffer(thr, idx); |
| 22107 | } |
| 22108 | |
| 22109 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 22110 | |
| 22111 | DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_hthread *thr, duk_idx_t idx) { |
| 22112 | DUK_ASSERT_API_ENTRY(thr); |
| 22113 | return duk__tag_check(thr, idx, DUK_TAG_POINTER); |
| 22114 | } |
| 22115 | |
| 22116 | DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_hthread *thr, duk_idx_t idx) { |
| 22117 | DUK_ASSERT_API_ENTRY(thr); |
| 22118 | return duk__tag_check(thr, idx, DUK_TAG_LIGHTFUNC); |
| 22119 | } |
| 22120 | |
| 22121 | DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_hthread *thr, duk_idx_t idx) { |
| 22122 | duk_hstring *h; |
| 22123 | |
| 22124 | DUK_ASSERT_API_ENTRY(thr); |
| 22125 | h = duk_get_hstring(thr, idx); |
| 22126 | /* Use DUK_LIKELY() here because caller may be more likely to type |
| 22127 | * check an expected symbol than not. |
| 22128 | */ |
| 22129 | if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) { |
| 22130 | return 1; |
| 22131 | } |
| 22132 | return 0; |
| 22133 | } |
| 22134 | |
| 22135 | /* IsArray(), returns true for Array instance or Proxy of Array instance. */ |
| 22136 | DUK_EXTERNAL duk_bool_t duk_is_array(duk_hthread *thr, duk_idx_t idx) { |
| 22137 | duk_tval *tv; |
| 22138 | |
| 22139 | DUK_ASSERT_API_ENTRY(thr); |
| 22140 | |
| 22141 | tv = duk_get_tval(thr, idx); |
| 22142 | if (tv) { |
| 22143 | return duk_js_isarray(tv); |
| 22144 | } |
| 22145 | return 0; |
| 22146 | } |
| 22147 | |
| 22148 | DUK_EXTERNAL duk_bool_t duk_is_function(duk_hthread *thr, duk_idx_t idx) { |
| 22149 | duk_tval *tv; |
| 22150 | |
| 22151 | DUK_ASSERT_API_ENTRY(thr); |
| 22152 | |
| 22153 | tv = duk_get_tval_or_unused(thr, idx); |
| 22154 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 22155 | duk_hobject *h; |
| 22156 | h = DUK_TVAL_GET_OBJECT(tv); |
| 22157 | DUK_ASSERT(h != NULL); |
| 22158 | return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0; |
| 22159 | } |
| 22160 | if (DUK_TVAL_IS_LIGHTFUNC(tv)) { |
| 22161 | return 1; |
| 22162 | } |
| 22163 | return 0; |
| 22164 | } |
| 22165 | |
| 22166 | DUK_INTERNAL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv) { |
| 22167 | DUK_ASSERT_API_ENTRY(thr); |
| 22168 | |
| 22169 | DUK_UNREF(thr); |
| 22170 | |
| 22171 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 22172 | duk_hobject *h; |
| 22173 | h = DUK_TVAL_GET_OBJECT(tv); |
| 22174 | DUK_ASSERT(h != NULL); |
| 22175 | return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0; |
| 22176 | } |
| 22177 | if (DUK_TVAL_IS_LIGHTFUNC(tv)) { |
| 22178 | return 1; |
| 22179 | } |
| 22180 | return 0; |
| 22181 | } |
| 22182 | |
| 22183 | DUK_EXTERNAL duk_bool_t duk_is_constructable(duk_hthread *thr, duk_idx_t idx) { |
| 22184 | duk_tval *tv; |
| 22185 | |
| 22186 | DUK_ASSERT_API_ENTRY(thr); |
| 22187 | |
| 22188 | tv = duk_get_tval_or_unused(thr, idx); |
| 22189 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 22190 | duk_hobject *h; |
| 22191 | h = DUK_TVAL_GET_OBJECT(tv); |
| 22192 | DUK_ASSERT(h != NULL); |
| 22193 | return DUK_HOBJECT_HAS_CONSTRUCTABLE(h) ? 1 : 0; |
| 22194 | } |
| 22195 | if (DUK_TVAL_IS_LIGHTFUNC(tv)) { |
| 22196 | return 1; |
| 22197 | } |
| 22198 | return 0; |
| 22199 | } |
| 22200 | |
| 22201 | DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_hthread *thr, duk_idx_t idx) { |
| 22202 | DUK_ASSERT_API_ENTRY(thr); |
| 22203 | return duk__obj_flag_any_default_false(thr, |
| 22204 | idx, |
| 22205 | DUK_HOBJECT_FLAG_NATFUNC); |
| 22206 | } |
| 22207 | |
| 22208 | DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_hthread *thr, duk_idx_t idx) { |
| 22209 | DUK_ASSERT_API_ENTRY(thr); |
| 22210 | return duk__obj_flag_any_default_false(thr, |
| 22211 | idx, |
| 22212 | DUK_HOBJECT_FLAG_COMPFUNC); |
| 22213 | } |
| 22214 | |
| 22215 | DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_hthread *thr, duk_idx_t idx) { |
| 22216 | DUK_ASSERT_API_ENTRY(thr); |
| 22217 | return duk__obj_flag_any_default_false(thr, |
| 22218 | idx, |
| 22219 | DUK_HOBJECT_FLAG_BOUNDFUNC); |
| 22220 | } |
| 22221 | |
| 22222 | DUK_EXTERNAL duk_bool_t duk_is_thread(duk_hthread *thr, duk_idx_t idx) { |
| 22223 | duk_hobject *obj; |
| 22224 | |
| 22225 | DUK_ASSERT_API_ENTRY(thr); |
| 22226 | |
| 22227 | obj = duk_get_hobject(thr, idx); |
| 22228 | if (obj) { |
| 22229 | return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0); |
| 22230 | } |
| 22231 | return 0; |
| 22232 | } |
| 22233 | |
| 22234 | DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_hthread *thr, duk_idx_t idx) { |
| 22235 | duk_tval *tv; |
| 22236 | |
| 22237 | DUK_ASSERT_API_ENTRY(thr); |
| 22238 | |
| 22239 | tv = duk_get_tval_or_unused(thr, idx); |
| 22240 | DUK_ASSERT(tv != NULL); |
| 22241 | if (DUK_TVAL_IS_BUFFER(tv)) { |
| 22242 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); |
| 22243 | DUK_ASSERT(h != NULL); |
| 22244 | return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1); |
| 22245 | } |
| 22246 | return 0; |
| 22247 | } |
| 22248 | |
| 22249 | DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_hthread *thr, duk_idx_t idx) { |
| 22250 | duk_tval *tv; |
| 22251 | |
| 22252 | DUK_ASSERT_API_ENTRY(thr); |
| 22253 | |
| 22254 | tv = duk_get_tval_or_unused(thr, idx); |
| 22255 | DUK_ASSERT(tv != NULL); |
| 22256 | if (DUK_TVAL_IS_BUFFER(tv)) { |
| 22257 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); |
| 22258 | DUK_ASSERT(h != NULL); |
| 22259 | return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); |
| 22260 | } |
| 22261 | return 0; |
| 22262 | } |
| 22263 | |
| 22264 | DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_hthread *thr, duk_idx_t idx) { |
| 22265 | duk_tval *tv; |
| 22266 | |
| 22267 | DUK_ASSERT_API_ENTRY(thr); |
| 22268 | |
| 22269 | tv = duk_get_tval_or_unused(thr, idx); |
| 22270 | DUK_ASSERT(tv != NULL); |
| 22271 | if (DUK_TVAL_IS_BUFFER(tv)) { |
| 22272 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); |
| 22273 | DUK_ASSERT(h != NULL); |
| 22274 | return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0); |
| 22275 | } |
| 22276 | return 0; |
| 22277 | } |
| 22278 | |
| 22279 | DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_hthread *thr, duk_idx_t idx) { |
| 22280 | duk_hobject *h; |
| 22281 | duk_uint_t sanity; |
| 22282 | |
| 22283 | DUK_ASSERT_API_ENTRY(thr); |
| 22284 | |
| 22285 | h = duk_get_hobject(thr, idx); |
| 22286 | |
| 22287 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 22288 | do { |
| 22289 | if (!h) { |
| 22290 | return DUK_ERR_NONE; |
| 22291 | } |
| 22292 | |
| 22293 | /* XXX: something more convenient? */ |
| 22294 | |
| 22295 | if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) { |
| 22296 | return DUK_ERR_EVAL_ERROR; |
| 22297 | } |
| 22298 | if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) { |
| 22299 | return DUK_ERR_RANGE_ERROR; |
| 22300 | } |
| 22301 | if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) { |
| 22302 | return DUK_ERR_REFERENCE_ERROR; |
| 22303 | } |
| 22304 | if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) { |
| 22305 | return DUK_ERR_SYNTAX_ERROR; |
| 22306 | } |
| 22307 | if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) { |
| 22308 | return DUK_ERR_TYPE_ERROR; |
| 22309 | } |
| 22310 | if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) { |
| 22311 | return DUK_ERR_URI_ERROR; |
| 22312 | } |
| 22313 | if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) { |
| 22314 | return DUK_ERR_ERROR; |
| 22315 | } |
| 22316 | |
| 22317 | h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); |
| 22318 | } while (--sanity > 0); |
| 22319 | |
| 22320 | return DUK_ERR_NONE; |
| 22321 | } |
| 22322 | |
| 22323 | /* |
| 22324 | * Pushers |
| 22325 | */ |
| 22326 | |
| 22327 | DUK_INTERNAL void duk_push_tval(duk_hthread *thr, duk_tval *tv) { |
| 22328 | duk_tval *tv_slot; |
| 22329 | |
| 22330 | DUK_ASSERT_API_ENTRY(thr); |
| 22331 | DUK_ASSERT(tv != NULL); |
| 22332 | |
| 22333 | DUK__CHECK_SPACE(); |
| 22334 | tv_slot = thr->valstack_top++; |
| 22335 | DUK_TVAL_SET_TVAL(tv_slot, tv); |
| 22336 | DUK_TVAL_INCREF(thr, tv); /* no side effects */ |
| 22337 | } |
| 22338 | |
| 22339 | DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr) { |
| 22340 | DUK_ASSERT_API_ENTRY(thr); |
| 22341 | |
| 22342 | DUK__CHECK_SPACE(); |
| 22343 | |
| 22344 | /* Because value stack init policy is 'undefined above top', |
| 22345 | * we don't need to write, just assert. |
| 22346 | */ |
| 22347 | thr->valstack_top++; |
| 22348 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1)); |
| 22349 | } |
| 22350 | |
| 22351 | DUK_EXTERNAL void duk_push_null(duk_hthread *thr) { |
| 22352 | duk_tval *tv_slot; |
| 22353 | |
| 22354 | DUK_ASSERT_API_ENTRY(thr); |
| 22355 | DUK__CHECK_SPACE(); |
| 22356 | tv_slot = thr->valstack_top++; |
| 22357 | DUK_TVAL_SET_NULL(tv_slot); |
| 22358 | } |
| 22359 | |
| 22360 | DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val) { |
| 22361 | duk_tval *tv_slot; |
| 22362 | duk_small_int_t b; |
| 22363 | |
| 22364 | DUK_ASSERT_API_ENTRY(thr); |
| 22365 | DUK__CHECK_SPACE(); |
| 22366 | b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */ |
| 22367 | tv_slot = thr->valstack_top++; |
| 22368 | DUK_TVAL_SET_BOOLEAN(tv_slot, b); |
| 22369 | } |
| 22370 | |
| 22371 | DUK_EXTERNAL void duk_push_true(duk_hthread *thr) { |
| 22372 | duk_tval *tv_slot; |
| 22373 | |
| 22374 | DUK_ASSERT_API_ENTRY(thr); |
| 22375 | DUK__CHECK_SPACE(); |
| 22376 | tv_slot = thr->valstack_top++; |
| 22377 | DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot); |
| 22378 | } |
| 22379 | |
| 22380 | DUK_EXTERNAL void duk_push_false(duk_hthread *thr) { |
| 22381 | duk_tval *tv_slot; |
| 22382 | |
| 22383 | DUK_ASSERT_API_ENTRY(thr); |
| 22384 | DUK__CHECK_SPACE(); |
| 22385 | tv_slot = thr->valstack_top++; |
| 22386 | DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot); |
| 22387 | } |
| 22388 | |
| 22389 | /* normalize NaN which may not match our canonical internal NaN */ |
| 22390 | DUK_EXTERNAL void duk_push_number(duk_hthread *thr, duk_double_t val) { |
| 22391 | duk_tval *tv_slot; |
| 22392 | duk_double_union du; |
| 22393 | |
| 22394 | DUK_ASSERT_API_ENTRY(thr); |
| 22395 | DUK__CHECK_SPACE(); |
| 22396 | du.d = val; |
| 22397 | DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); |
| 22398 | tv_slot = thr->valstack_top++; |
| 22399 | DUK_TVAL_SET_NUMBER(tv_slot, du.d); |
| 22400 | } |
| 22401 | |
| 22402 | DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val) { |
| 22403 | #if defined(DUK_USE_FASTINT) |
| 22404 | duk_tval *tv_slot; |
| 22405 | |
| 22406 | DUK_ASSERT_API_ENTRY(thr); |
| 22407 | DUK__CHECK_SPACE(); |
| 22408 | tv_slot = thr->valstack_top++; |
| 22409 | #if DUK_INT_MAX <= 0x7fffffffL |
| 22410 | DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val); |
| 22411 | #else |
| 22412 | if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) { |
| 22413 | DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val); |
| 22414 | } else { |
| 22415 | duk_double_t = (duk_double_t) val; |
| 22416 | DUK_TVAL_SET_NUMBER(tv_slot, d); |
| 22417 | } |
| 22418 | #endif |
| 22419 | #else /* DUK_USE_FASTINT */ |
| 22420 | duk_tval *tv_slot; |
| 22421 | duk_double_t d; |
| 22422 | |
| 22423 | DUK_ASSERT_API_ENTRY(thr); |
| 22424 | DUK__CHECK_SPACE(); |
| 22425 | d = (duk_double_t) val; |
| 22426 | tv_slot = thr->valstack_top++; |
| 22427 | DUK_TVAL_SET_NUMBER(tv_slot, d); |
| 22428 | #endif /* DUK_USE_FASTINT */ |
| 22429 | } |
| 22430 | |
| 22431 | DUK_EXTERNAL void duk_push_uint(duk_hthread *thr, duk_uint_t val) { |
| 22432 | #if defined(DUK_USE_FASTINT) |
| 22433 | duk_tval *tv_slot; |
| 22434 | |
| 22435 | DUK_ASSERT_API_ENTRY(thr); |
| 22436 | DUK__CHECK_SPACE(); |
| 22437 | tv_slot = thr->valstack_top++; |
| 22438 | #if DUK_UINT_MAX <= 0xffffffffUL |
| 22439 | DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val); |
| 22440 | #else |
| 22441 | if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */ |
| 22442 | /* XXX: take advantage of val being unsigned, no need to mask */ |
| 22443 | DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val); |
| 22444 | } else { |
| 22445 | duk_double_t = (duk_double_t) val; |
| 22446 | DUK_TVAL_SET_NUMBER(tv_slot, d); |
| 22447 | } |
| 22448 | #endif |
| 22449 | #else /* DUK_USE_FASTINT */ |
| 22450 | duk_tval *tv_slot; |
| 22451 | duk_double_t d; |
| 22452 | |
| 22453 | DUK_ASSERT_API_ENTRY(thr); |
| 22454 | DUK__CHECK_SPACE(); |
| 22455 | d = (duk_double_t) val; |
| 22456 | tv_slot = thr->valstack_top++; |
| 22457 | DUK_TVAL_SET_NUMBER(tv_slot, d); |
| 22458 | #endif /* DUK_USE_FASTINT */ |
| 22459 | } |
| 22460 | |
| 22461 | DUK_EXTERNAL void duk_push_nan(duk_hthread *thr) { |
| 22462 | duk_tval *tv_slot; |
| 22463 | duk_double_union du; |
| 22464 | |
| 22465 | DUK_ASSERT_API_ENTRY(thr); |
| 22466 | DUK__CHECK_SPACE(); |
| 22467 | DUK_DBLUNION_SET_NAN(&du); |
| 22468 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 22469 | tv_slot = thr->valstack_top++; |
| 22470 | DUK_TVAL_SET_NUMBER(tv_slot, du.d); |
| 22471 | } |
| 22472 | |
| 22473 | DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len) { |
| 22474 | duk_hstring *h; |
| 22475 | duk_tval *tv_slot; |
| 22476 | |
| 22477 | DUK_ASSERT_API_ENTRY(thr); |
| 22478 | |
| 22479 | /* Check stack before interning (avoid hanging temp). */ |
| 22480 | DUK__CHECK_SPACE(); |
| 22481 | |
| 22482 | /* NULL with zero length represents an empty string; NULL with higher |
| 22483 | * length is also now treated like an empty string although it is |
| 22484 | * a bit dubious. This is unlike duk_push_string() which pushes a |
| 22485 | * 'null' if the input string is a NULL. |
| 22486 | */ |
| 22487 | if (DUK_UNLIKELY(str == NULL)) { |
| 22488 | len = 0U; |
| 22489 | } |
| 22490 | |
| 22491 | /* Check for maximum string length. */ |
| 22492 | if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { |
| 22493 | DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); |
| 22494 | DUK_WO_NORETURN(return NULL;); |
| 22495 | } |
| 22496 | |
| 22497 | h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); |
| 22498 | DUK_ASSERT(h != NULL); |
| 22499 | |
| 22500 | tv_slot = thr->valstack_top++; |
| 22501 | DUK_TVAL_SET_STRING(tv_slot, h); |
| 22502 | DUK_HSTRING_INCREF(thr, h); /* no side effects */ |
| 22503 | |
| 22504 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 22505 | } |
| 22506 | |
| 22507 | DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) { |
| 22508 | DUK_ASSERT_API_ENTRY(thr); |
| 22509 | |
| 22510 | if (str) { |
| 22511 | return duk_push_lstring(thr, str, DUK_STRLEN(str)); |
| 22512 | } else { |
| 22513 | duk_push_null(thr); |
| 22514 | return NULL; |
| 22515 | } |
| 22516 | } |
| 22517 | |
| 22518 | #if !defined(DUK_USE_PREFER_SIZE) |
| 22519 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 22520 | DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) { |
| 22521 | duk_hstring *h; |
| 22522 | duk_tval *tv_slot; |
| 22523 | |
| 22524 | DUK_ASSERT_API_ENTRY(thr); |
| 22525 | DUK_ASSERT(str != NULL); |
| 22526 | DUK_ASSERT(str[len] == (char) 0); |
| 22527 | |
| 22528 | /* Check for maximum string length. */ |
| 22529 | if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) { |
| 22530 | DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG); |
| 22531 | DUK_WO_NORETURN(return NULL;); |
| 22532 | } |
| 22533 | |
| 22534 | h = duk_heap_strtable_intern_literal_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len); |
| 22535 | DUK_ASSERT(h != NULL); |
| 22536 | |
| 22537 | tv_slot = thr->valstack_top++; |
| 22538 | DUK_TVAL_SET_STRING(tv_slot, h); |
| 22539 | DUK_HSTRING_INCREF(thr, h); /* no side effects */ |
| 22540 | |
| 22541 | return (const char *) DUK_HSTRING_GET_DATA(h); |
| 22542 | } |
| 22543 | #else /* DUK_USE_LITCACHE_SIZE */ |
| 22544 | DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) { |
| 22545 | DUK_ASSERT_API_ENTRY(thr); |
| 22546 | DUK_ASSERT(str != NULL); |
| 22547 | DUK_ASSERT(str[len] == (char) 0); |
| 22548 | |
| 22549 | return duk_push_lstring(thr, str, len); |
| 22550 | } |
| 22551 | #endif /* DUK_USE_LITCACHE_SIZE */ |
| 22552 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 22553 | |
| 22554 | DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) { |
| 22555 | duk_tval *tv_slot; |
| 22556 | |
| 22557 | DUK_ASSERT_API_ENTRY(thr); |
| 22558 | DUK__CHECK_SPACE(); |
| 22559 | tv_slot = thr->valstack_top++; |
| 22560 | DUK_TVAL_SET_POINTER(tv_slot, val); |
| 22561 | } |
| 22562 | |
| 22563 | DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i) { |
| 22564 | duk_hstring *h_tmp; |
| 22565 | |
| 22566 | DUK_ASSERT_API_ENTRY(thr); |
| 22567 | |
| 22568 | /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */ |
| 22569 | duk_push_uint(thr, (duk_uint_t) i); |
| 22570 | h_tmp = duk_to_hstring_m1(thr); |
| 22571 | DUK_ASSERT(h_tmp != NULL); |
| 22572 | return h_tmp; |
| 22573 | } |
| 22574 | |
| 22575 | DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_object_coercible) { |
| 22576 | duk_tval *tv_slot; |
| 22577 | |
| 22578 | DUK__CHECK_SPACE(); |
| 22579 | |
| 22580 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */ |
| 22581 | tv_slot = thr->valstack_top++; |
| 22582 | |
| 22583 | if (DUK_UNLIKELY(thr->callstack_curr == NULL)) { |
| 22584 | if (check_object_coercible) { |
| 22585 | goto type_error; |
| 22586 | } |
| 22587 | /* 'undefined' already on stack top */ |
| 22588 | } else { |
| 22589 | duk_tval *tv; |
| 22590 | |
| 22591 | /* 'this' binding is just before current activation's bottom */ |
| 22592 | DUK_ASSERT(thr->valstack_bottom > thr->valstack); |
| 22593 | tv = thr->valstack_bottom - 1; |
| 22594 | if (check_object_coercible && |
| 22595 | (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) { |
| 22596 | /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */ |
| 22597 | goto type_error; |
| 22598 | } |
| 22599 | |
| 22600 | DUK_TVAL_SET_TVAL(tv_slot, tv); |
| 22601 | DUK_TVAL_INCREF(thr, tv); |
| 22602 | } |
| 22603 | return; |
| 22604 | |
| 22605 | type_error: |
| 22606 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE); |
| 22607 | DUK_WO_NORETURN(return;); |
| 22608 | } |
| 22609 | |
| 22610 | DUK_EXTERNAL void duk_push_this(duk_hthread *thr) { |
| 22611 | DUK_ASSERT_API_ENTRY(thr); |
| 22612 | |
| 22613 | duk__push_this_helper(thr, 0 /*check_object_coercible*/); |
| 22614 | } |
| 22615 | |
| 22616 | DUK_INTERNAL void duk_push_this_check_object_coercible(duk_hthread *thr) { |
| 22617 | DUK_ASSERT_API_ENTRY(thr); |
| 22618 | |
| 22619 | duk__push_this_helper(thr, 1 /*check_object_coercible*/); |
| 22620 | } |
| 22621 | |
| 22622 | DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr) { |
| 22623 | duk_hobject *h; |
| 22624 | |
| 22625 | DUK_ASSERT_API_ENTRY(thr); |
| 22626 | |
| 22627 | duk__push_this_helper(thr, 1 /*check_object_coercible*/); |
| 22628 | h = duk_to_hobject(thr, -1); |
| 22629 | DUK_ASSERT(h != NULL); |
| 22630 | return h; |
| 22631 | } |
| 22632 | |
| 22633 | DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr) { |
| 22634 | DUK_ASSERT_API_ENTRY(thr); |
| 22635 | |
| 22636 | duk__push_this_helper(thr, 1 /*check_object_coercible*/); |
| 22637 | return duk_to_hstring_m1(thr); /* This will reject all Symbol values; accepts Symbol objects. */ |
| 22638 | } |
| 22639 | |
| 22640 | DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) { |
| 22641 | DUK_ASSERT_API_ENTRY(thr); |
| 22642 | |
| 22643 | DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */ |
| 22644 | DUK_ASSERT(thr->callstack_curr != NULL); /* caller required to know */ |
| 22645 | DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */ |
| 22646 | DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */ |
| 22647 | |
| 22648 | return thr->valstack_bottom - 1; |
| 22649 | } |
| 22650 | |
| 22651 | DUK_EXTERNAL void duk_push_new_target(duk_hthread *thr) { |
| 22652 | duk_activation *act; |
| 22653 | |
| 22654 | DUK_ASSERT_API_ENTRY(thr); |
| 22655 | |
| 22656 | /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation |
| 22657 | * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget |
| 22658 | * |
| 22659 | * No newTarget support now, so as a first approximation |
| 22660 | * use the resolved (non-bound) target function. |
| 22661 | * |
| 22662 | * Check CONSTRUCT flag from current function, or if running |
| 22663 | * direct eval, from a non-direct-eval parent (with possibly |
| 22664 | * more than one nested direct eval). An alternative to this |
| 22665 | * would be to store [[NewTarget]] as a hidden symbol of the |
| 22666 | * lexical scope, and then just look up that variable. |
| 22667 | * |
| 22668 | * Calls from the application will either be for an empty |
| 22669 | * call stack, or a Duktape/C function as the top activation. |
| 22670 | */ |
| 22671 | |
| 22672 | act = thr->callstack_curr; |
| 22673 | for (;;) { |
| 22674 | if (act == NULL) { |
| 22675 | break; |
| 22676 | } |
| 22677 | |
| 22678 | if (act->flags & DUK_ACT_FLAG_CONSTRUCT) { |
| 22679 | duk_push_tval(thr, &act->tv_func); |
| 22680 | return; |
| 22681 | } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) { |
| 22682 | act = act->parent; |
| 22683 | } else { |
| 22684 | break; |
| 22685 | } |
| 22686 | } |
| 22687 | |
| 22688 | duk_push_undefined(thr); |
| 22689 | } |
| 22690 | |
| 22691 | DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) { |
| 22692 | duk_activation *act; |
| 22693 | |
| 22694 | DUK_ASSERT_API_ENTRY(thr); |
| 22695 | |
| 22696 | act = thr->callstack_curr; |
| 22697 | if (act != NULL) { |
| 22698 | duk_push_tval(thr, &act->tv_func); |
| 22699 | } else { |
| 22700 | duk_push_undefined(thr); |
| 22701 | } |
| 22702 | } |
| 22703 | |
| 22704 | DUK_EXTERNAL void duk_push_current_thread(duk_hthread *thr) { |
| 22705 | DUK_ASSERT_API_ENTRY(thr); |
| 22706 | |
| 22707 | if (thr->heap->curr_thread) { |
| 22708 | duk_push_hobject(thr, (duk_hobject *) thr->heap->curr_thread); |
| 22709 | } else { |
| 22710 | duk_push_undefined(thr); |
| 22711 | } |
| 22712 | } |
| 22713 | |
| 22714 | DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr) { |
| 22715 | DUK_ASSERT_API_ENTRY(thr); |
| 22716 | |
| 22717 | duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL); |
| 22718 | } |
| 22719 | |
| 22720 | /* XXX: size optimize */ |
| 22721 | DUK_LOCAL void duk__push_stash(duk_hthread *thr) { |
| 22722 | if (!duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE)) { |
| 22723 | DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use" )); |
| 22724 | duk_pop_unsafe(thr); |
| 22725 | duk_push_bare_object(thr); |
| 22726 | duk_dup_top(thr); |
| 22727 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */ |
| 22728 | } |
| 22729 | duk_remove_m2(thr); |
| 22730 | } |
| 22731 | |
| 22732 | DUK_EXTERNAL void duk_push_heap_stash(duk_hthread *thr) { |
| 22733 | duk_heap *heap; |
| 22734 | DUK_ASSERT_API_ENTRY(thr); |
| 22735 | heap = thr->heap; |
| 22736 | DUK_ASSERT(heap->heap_object != NULL); |
| 22737 | duk_push_hobject(thr, heap->heap_object); |
| 22738 | duk__push_stash(thr); |
| 22739 | } |
| 22740 | |
| 22741 | DUK_EXTERNAL void duk_push_global_stash(duk_hthread *thr) { |
| 22742 | DUK_ASSERT_API_ENTRY(thr); |
| 22743 | duk_push_global_object(thr); |
| 22744 | duk__push_stash(thr); |
| 22745 | } |
| 22746 | |
| 22747 | DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_thr) { |
| 22748 | DUK_ASSERT_API_ENTRY(thr); |
| 22749 | if (DUK_UNLIKELY(target_thr == NULL)) { |
| 22750 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 22751 | DUK_WO_NORETURN(return;); |
| 22752 | } |
| 22753 | duk_push_hobject(thr, (duk_hobject *) target_thr); |
| 22754 | duk__push_stash(thr); |
| 22755 | } |
| 22756 | |
| 22757 | /* XXX: duk_ssize_t would be useful here */ |
| 22758 | DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_hthread *thr, void *buf, duk_size_t sz, const char *fmt, va_list ap) { |
| 22759 | duk_int_t len; |
| 22760 | |
| 22761 | DUK_CTX_ASSERT_VALID(thr); |
| 22762 | DUK_UNREF(thr); |
| 22763 | |
| 22764 | /* NUL terminator handling doesn't matter here */ |
| 22765 | len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap); |
| 22766 | if (len < (duk_int_t) sz) { |
| 22767 | /* Return value of 'sz' or more indicates output was (potentially) |
| 22768 | * truncated. |
| 22769 | */ |
| 22770 | return (duk_int_t) len; |
| 22771 | } |
| 22772 | return -1; |
| 22773 | } |
| 22774 | |
| 22775 | DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va_list ap) { |
| 22776 | duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE]; |
| 22777 | duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE; |
| 22778 | duk_bool_t pushed_buf = 0; |
| 22779 | void *buf; |
| 22780 | duk_int_t len; /* XXX: duk_ssize_t */ |
| 22781 | const char *res; |
| 22782 | |
| 22783 | DUK_ASSERT_API_ENTRY(thr); |
| 22784 | |
| 22785 | /* special handling of fmt==NULL */ |
| 22786 | if (!fmt) { |
| 22787 | duk_hstring *h_str; |
| 22788 | duk_push_hstring_empty(thr); |
| 22789 | h_str = duk_known_hstring(thr, -1); |
| 22790 | return (const char *) DUK_HSTRING_GET_DATA(h_str); |
| 22791 | } |
| 22792 | |
| 22793 | /* initial estimate based on format string */ |
| 22794 | sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */ |
| 22795 | if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) { |
| 22796 | sz = DUK_PUSH_SPRINTF_INITIAL_SIZE; |
| 22797 | } |
| 22798 | DUK_ASSERT(sz > 0); |
| 22799 | |
| 22800 | /* Try to make do with a stack buffer to avoid allocating a temporary buffer. |
| 22801 | * This works 99% of the time which is quite nice. |
| 22802 | */ |
| 22803 | for (;;) { |
| 22804 | va_list ap_copy; /* copied so that 'ap' can be reused */ |
| 22805 | |
| 22806 | if (sz <= sizeof(stack_buf)) { |
| 22807 | buf = stack_buf; |
| 22808 | } else if (!pushed_buf) { |
| 22809 | pushed_buf = 1; |
| 22810 | buf = duk_push_dynamic_buffer(thr, sz); |
| 22811 | } else { |
| 22812 | buf = duk_resize_buffer(thr, -1, sz); |
| 22813 | } |
| 22814 | DUK_ASSERT(buf != NULL); |
| 22815 | |
| 22816 | DUK_VA_COPY(ap_copy, ap); |
| 22817 | len = duk__try_push_vsprintf(thr, buf, sz, fmt, ap_copy); |
| 22818 | va_end(ap_copy); |
| 22819 | if (len >= 0) { |
| 22820 | break; |
| 22821 | } |
| 22822 | |
| 22823 | /* failed, resize and try again */ |
| 22824 | sz = sz * 2; |
| 22825 | if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) { |
| 22826 | DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); |
| 22827 | DUK_WO_NORETURN(return NULL;); |
| 22828 | } |
| 22829 | } |
| 22830 | |
| 22831 | /* Cannot use duk_buffer_to_string() on the buffer because it is |
| 22832 | * usually larger than 'len'; 'buf' is also usually a stack buffer. |
| 22833 | */ |
| 22834 | res = duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */ |
| 22835 | if (pushed_buf) { |
| 22836 | duk_remove_m2(thr); |
| 22837 | } |
| 22838 | return res; |
| 22839 | } |
| 22840 | |
| 22841 | DUK_EXTERNAL const char *duk_push_sprintf(duk_hthread *thr, const char *fmt, ...) { |
| 22842 | va_list ap; |
| 22843 | const char *ret; |
| 22844 | |
| 22845 | DUK_ASSERT_API_ENTRY(thr); |
| 22846 | |
| 22847 | /* allow fmt==NULL */ |
| 22848 | va_start(ap, fmt); |
| 22849 | ret = duk_push_vsprintf(thr, fmt, ap); |
| 22850 | va_end(ap); |
| 22851 | |
| 22852 | return ret; |
| 22853 | } |
| 22854 | |
| 22855 | DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { |
| 22856 | duk_tval *tv_slot; |
| 22857 | duk_hobject *h; |
| 22858 | |
| 22859 | DUK_ASSERT_API_ENTRY(thr); |
| 22860 | DUK_ASSERT(prototype_bidx == -1 || |
| 22861 | (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS)); |
| 22862 | |
| 22863 | DUK__CHECK_SPACE(); |
| 22864 | |
| 22865 | h = duk_hobject_alloc(thr, hobject_flags_and_class); |
| 22866 | DUK_ASSERT(h != NULL); |
| 22867 | |
| 22868 | DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx" , (unsigned long) h->hdr.h_flags)); |
| 22869 | |
| 22870 | tv_slot = thr->valstack_top; |
| 22871 | DUK_TVAL_SET_OBJECT(tv_slot, h); |
| 22872 | DUK_HOBJECT_INCREF(thr, h); /* no side effects */ |
| 22873 | thr->valstack_top++; |
| 22874 | |
| 22875 | /* object is now reachable */ |
| 22876 | |
| 22877 | if (prototype_bidx >= 0) { |
| 22878 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, thr->builtins[prototype_bidx]); |
| 22879 | } else { |
| 22880 | DUK_ASSERT(prototype_bidx == -1); |
| 22881 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL); |
| 22882 | } |
| 22883 | |
| 22884 | return h; |
| 22885 | } |
| 22886 | |
| 22887 | DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto) { |
| 22888 | duk_hobject *h; |
| 22889 | |
| 22890 | DUK_ASSERT_API_ENTRY(thr); |
| 22891 | |
| 22892 | h = duk_push_object_helper(thr, hobject_flags_and_class, -1); |
| 22893 | DUK_ASSERT(h != NULL); |
| 22894 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, proto); |
| 22895 | return h; |
| 22896 | } |
| 22897 | |
| 22898 | DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr) { |
| 22899 | DUK_ASSERT_API_ENTRY(thr); |
| 22900 | |
| 22901 | (void) duk_push_object_helper(thr, |
| 22902 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 22903 | DUK_HOBJECT_FLAG_FASTREFS | |
| 22904 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), |
| 22905 | DUK_BIDX_OBJECT_PROTOTYPE); |
| 22906 | return duk_get_top_index_unsafe(thr); |
| 22907 | } |
| 22908 | |
| 22909 | DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr) { |
| 22910 | duk_uint_t flags; |
| 22911 | duk_harray *obj; |
| 22912 | duk_idx_t ret; |
| 22913 | duk_tval *tv_slot; |
| 22914 | |
| 22915 | DUK_ASSERT_API_ENTRY(thr); |
| 22916 | |
| 22917 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 22918 | DUK_HOBJECT_FLAG_FASTREFS | |
| 22919 | DUK_HOBJECT_FLAG_ARRAY_PART | |
| 22920 | DUK_HOBJECT_FLAG_EXOTIC_ARRAY | |
| 22921 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); |
| 22922 | |
| 22923 | obj = duk_harray_alloc(thr, flags); |
| 22924 | DUK_ASSERT(obj != NULL); |
| 22925 | |
| 22926 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]); |
| 22927 | |
| 22928 | tv_slot = thr->valstack_top; |
| 22929 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); |
| 22930 | DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */ |
| 22931 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 22932 | thr->valstack_top++; |
| 22933 | |
| 22934 | DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */ |
| 22935 | return ret; |
| 22936 | } |
| 22937 | |
| 22938 | DUK_EXTERNAL duk_idx_t duk_push_bare_array(duk_hthread *thr) { |
| 22939 | duk_uint_t flags; |
| 22940 | duk_harray *obj; |
| 22941 | duk_idx_t ret; |
| 22942 | duk_tval *tv_slot; |
| 22943 | |
| 22944 | DUK_ASSERT_API_ENTRY(thr); |
| 22945 | |
| 22946 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 22947 | DUK_HOBJECT_FLAG_FASTREFS | |
| 22948 | DUK_HOBJECT_FLAG_ARRAY_PART | |
| 22949 | DUK_HOBJECT_FLAG_EXOTIC_ARRAY | |
| 22950 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY); |
| 22951 | |
| 22952 | obj = duk_harray_alloc(thr, flags); |
| 22953 | DUK_ASSERT(obj != NULL); |
| 22954 | |
| 22955 | tv_slot = thr->valstack_top; |
| 22956 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); |
| 22957 | DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */ |
| 22958 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 22959 | thr->valstack_top++; |
| 22960 | |
| 22961 | DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */ |
| 22962 | return ret; |
| 22963 | } |
| 22964 | |
| 22965 | DUK_INTERNAL duk_harray *duk_push_harray(duk_hthread *thr) { |
| 22966 | /* XXX: API call could do this directly, cast to void in API macro. */ |
| 22967 | duk_harray *a; |
| 22968 | |
| 22969 | DUK_ASSERT_API_ENTRY(thr); |
| 22970 | |
| 22971 | (void) duk_push_array(thr); |
| 22972 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1)); |
| 22973 | a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1); |
| 22974 | DUK_ASSERT(a != NULL); |
| 22975 | return a; |
| 22976 | } |
| 22977 | |
| 22978 | /* Push a duk_harray with preallocated size (.length also set to match size). |
| 22979 | * Caller may then populate array part of the duk_harray directly. |
| 22980 | */ |
| 22981 | DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size) { |
| 22982 | duk_harray *a; |
| 22983 | |
| 22984 | DUK_ASSERT_API_ENTRY(thr); |
| 22985 | |
| 22986 | a = duk_push_harray(thr); |
| 22987 | |
| 22988 | duk_hobject_realloc_props(thr, |
| 22989 | (duk_hobject *) a, |
| 22990 | 0, |
| 22991 | size, |
| 22992 | 0, |
| 22993 | 0); |
| 22994 | a->length = size; |
| 22995 | return a; |
| 22996 | } |
| 22997 | |
| 22998 | DUK_INTERNAL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size) { |
| 22999 | duk_harray *a; |
| 23000 | |
| 23001 | DUK_ASSERT_API_ENTRY(thr); |
| 23002 | |
| 23003 | a = duk_push_harray_with_size(thr, size); |
| 23004 | DUK_ASSERT(a != NULL); |
| 23005 | return DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a); |
| 23006 | } |
| 23007 | |
| 23008 | DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) { |
| 23009 | duk_hthread *obj; |
| 23010 | duk_idx_t ret; |
| 23011 | duk_tval *tv_slot; |
| 23012 | |
| 23013 | DUK_ASSERT_API_ENTRY(thr); |
| 23014 | |
| 23015 | DUK__CHECK_SPACE(); |
| 23016 | |
| 23017 | obj = duk_hthread_alloc(thr, |
| 23018 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23019 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); |
| 23020 | DUK_ASSERT(obj != NULL); |
| 23021 | obj->state = DUK_HTHREAD_STATE_INACTIVE; |
| 23022 | #if defined(DUK_USE_ROM_STRINGS) |
| 23023 | /* Nothing to initialize, strs[] is in ROM. */ |
| 23024 | #else |
| 23025 | #if defined(DUK_USE_HEAPPTR16) |
| 23026 | obj->strs16 = thr->strs16; |
| 23027 | #else |
| 23028 | obj->strs = thr->strs; |
| 23029 | #endif |
| 23030 | #endif |
| 23031 | DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx" , (unsigned long) obj->obj.hdr.h_flags)); |
| 23032 | |
| 23033 | /* make the new thread reachable */ |
| 23034 | tv_slot = thr->valstack_top; |
| 23035 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); |
| 23036 | DUK_HTHREAD_INCREF(thr, obj); |
| 23037 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 23038 | thr->valstack_top++; |
| 23039 | |
| 23040 | /* important to do this *after* pushing, to make the thread reachable for gc */ |
| 23041 | if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) { |
| 23042 | DUK_ERROR_ALLOC_FAILED(thr); |
| 23043 | DUK_WO_NORETURN(return 0;); |
| 23044 | } |
| 23045 | |
| 23046 | /* initialize built-ins - either by copying or creating new ones */ |
| 23047 | if (flags & DUK_THREAD_NEW_GLOBAL_ENV) { |
| 23048 | duk_hthread_create_builtin_objects(obj); |
| 23049 | } else { |
| 23050 | duk_hthread_copy_builtin_objects(thr, obj); |
| 23051 | } |
| 23052 | |
| 23053 | /* default prototype */ |
| 23054 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]); |
| 23055 | |
| 23056 | /* Initial stack size satisfies the stack slack constraints so there |
| 23057 | * is no need to require stack here. |
| 23058 | */ |
| 23059 | DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >= |
| 23060 | DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); |
| 23061 | |
| 23062 | return ret; |
| 23063 | } |
| 23064 | |
| 23065 | DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) { |
| 23066 | duk_hcompfunc *obj; |
| 23067 | duk_tval *tv_slot; |
| 23068 | |
| 23069 | DUK_ASSERT_API_ENTRY(thr); |
| 23070 | |
| 23071 | DUK__CHECK_SPACE(); |
| 23072 | |
| 23073 | /* Template functions are not strictly constructable (they don't |
| 23074 | * have a "prototype" property for instance), so leave the |
| 23075 | * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here. |
| 23076 | */ |
| 23077 | |
| 23078 | obj = duk_hcompfunc_alloc(thr, |
| 23079 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23080 | DUK_HOBJECT_FLAG_CALLABLE | |
| 23081 | DUK_HOBJECT_FLAG_COMPFUNC | |
| 23082 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); |
| 23083 | if (DUK_UNLIKELY(obj == NULL)) { |
| 23084 | DUK_ERROR_ALLOC_FAILED(thr); |
| 23085 | DUK_WO_NORETURN(return NULL;); |
| 23086 | } |
| 23087 | |
| 23088 | DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx" , (unsigned long) obj->obj.hdr.h_flags)); |
| 23089 | |
| 23090 | tv_slot = thr->valstack_top; |
| 23091 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); |
| 23092 | DUK_HOBJECT_INCREF(thr, obj); |
| 23093 | thr->valstack_top++; |
| 23094 | |
| 23095 | /* default prototype */ |
| 23096 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL); |
| 23097 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 23098 | |
| 23099 | return obj; |
| 23100 | } |
| 23101 | |
| 23102 | DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) { |
| 23103 | duk_hboundfunc *obj; |
| 23104 | duk_tval *tv_slot; |
| 23105 | |
| 23106 | DUK_ASSERT_API_ENTRY(thr); |
| 23107 | |
| 23108 | DUK__CHECK_SPACE(); |
| 23109 | obj = duk_hboundfunc_alloc(thr->heap, |
| 23110 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23111 | DUK_HOBJECT_FLAG_BOUNDFUNC | |
| 23112 | DUK_HOBJECT_FLAG_CONSTRUCTABLE | |
| 23113 | DUK_HOBJECT_FLAG_CALLABLE | |
| 23114 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION)); |
| 23115 | if (!obj) { |
| 23116 | DUK_ERROR_ALLOC_FAILED(thr); |
| 23117 | DUK_WO_NORETURN(return NULL;); |
| 23118 | } |
| 23119 | |
| 23120 | tv_slot = thr->valstack_top++; |
| 23121 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); |
| 23122 | DUK_HOBJECT_INCREF(thr, obj); |
| 23123 | |
| 23124 | /* Prototype is left as NULL because the caller always sets it (and |
| 23125 | * it depends on the target function). |
| 23126 | */ |
| 23127 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL); |
| 23128 | |
| 23129 | return obj; |
| 23130 | } |
| 23131 | |
| 23132 | DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_uint_t flags, duk_small_uint_t proto_bidx) { |
| 23133 | duk_hnatfunc *obj; |
| 23134 | duk_idx_t ret; |
| 23135 | duk_tval *tv_slot; |
| 23136 | duk_int16_t func_nargs; |
| 23137 | |
| 23138 | DUK_CTX_ASSERT_VALID(thr); |
| 23139 | |
| 23140 | DUK__CHECK_SPACE(); |
| 23141 | |
| 23142 | if (DUK_UNLIKELY(func == NULL)) { |
| 23143 | goto api_error; |
| 23144 | } |
| 23145 | if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) { |
| 23146 | func_nargs = (duk_int16_t) nargs; |
| 23147 | } else if (nargs == DUK_VARARGS) { |
| 23148 | func_nargs = DUK_HNATFUNC_NARGS_VARARGS; |
| 23149 | } else { |
| 23150 | goto api_error; |
| 23151 | } |
| 23152 | |
| 23153 | obj = duk_hnatfunc_alloc(thr, flags); |
| 23154 | DUK_ASSERT(obj != NULL); |
| 23155 | |
| 23156 | obj->func = func; |
| 23157 | obj->nargs = func_nargs; |
| 23158 | |
| 23159 | DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld" , |
| 23160 | (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs)); |
| 23161 | |
| 23162 | tv_slot = thr->valstack_top; |
| 23163 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); |
| 23164 | DUK_HOBJECT_INCREF(thr, obj); |
| 23165 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 23166 | thr->valstack_top++; |
| 23167 | |
| 23168 | DUK_ASSERT_BIDX_VALID(proto_bidx); |
| 23169 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[proto_bidx]); |
| 23170 | return ret; |
| 23171 | |
| 23172 | api_error: |
| 23173 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 23174 | DUK_WO_NORETURN(return 0;); |
| 23175 | } |
| 23176 | |
| 23177 | DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) { |
| 23178 | duk_uint_t flags; |
| 23179 | |
| 23180 | DUK_ASSERT_API_ENTRY(thr); |
| 23181 | |
| 23182 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23183 | DUK_HOBJECT_FLAG_CONSTRUCTABLE | |
| 23184 | DUK_HOBJECT_FLAG_CALLABLE | |
| 23185 | DUK_HOBJECT_FLAG_FASTREFS | |
| 23186 | DUK_HOBJECT_FLAG_NATFUNC | |
| 23187 | DUK_HOBJECT_FLAG_NEWENV | |
| 23188 | DUK_HOBJECT_FLAG_STRICT | |
| 23189 | DUK_HOBJECT_FLAG_NOTAIL | |
| 23190 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); |
| 23191 | |
| 23192 | /* Default prototype is a Duktape specific %NativeFunctionPrototype% |
| 23193 | * which provides .length and .name getters. |
| 23194 | */ |
| 23195 | return duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE); |
| 23196 | } |
| 23197 | |
| 23198 | DUK_INTERNAL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs) { |
| 23199 | duk_uint_t flags; |
| 23200 | |
| 23201 | DUK_ASSERT_API_ENTRY(thr); |
| 23202 | |
| 23203 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23204 | DUK_HOBJECT_FLAG_CONSTRUCTABLE | |
| 23205 | DUK_HOBJECT_FLAG_CALLABLE | |
| 23206 | DUK_HOBJECT_FLAG_FASTREFS | |
| 23207 | DUK_HOBJECT_FLAG_NATFUNC | |
| 23208 | DUK_HOBJECT_FLAG_NEWENV | |
| 23209 | DUK_HOBJECT_FLAG_STRICT | |
| 23210 | DUK_HOBJECT_FLAG_NOTAIL | |
| 23211 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); |
| 23212 | |
| 23213 | /* Must use Function.prototype for standard built-in functions. */ |
| 23214 | (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE); |
| 23215 | } |
| 23216 | |
| 23217 | DUK_INTERNAL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs) { |
| 23218 | duk_uint_t flags; |
| 23219 | |
| 23220 | DUK_ASSERT_API_ENTRY(thr); |
| 23221 | |
| 23222 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23223 | DUK_HOBJECT_FLAG_CALLABLE | |
| 23224 | DUK_HOBJECT_FLAG_FASTREFS | |
| 23225 | DUK_HOBJECT_FLAG_NATFUNC | |
| 23226 | DUK_HOBJECT_FLAG_NEWENV | |
| 23227 | DUK_HOBJECT_FLAG_STRICT | |
| 23228 | DUK_HOBJECT_FLAG_NOTAIL | |
| 23229 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION); |
| 23230 | |
| 23231 | /* Must use Function.prototype for standard built-in functions. */ |
| 23232 | (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE); |
| 23233 | } |
| 23234 | |
| 23235 | DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_hthread *thr, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) { |
| 23236 | duk_small_uint_t lf_flags; |
| 23237 | duk_tval *tv_slot; |
| 23238 | |
| 23239 | DUK_ASSERT_API_ENTRY(thr); |
| 23240 | |
| 23241 | DUK__CHECK_SPACE(); |
| 23242 | |
| 23243 | if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) { |
| 23244 | /* as is */ |
| 23245 | } else if (nargs == DUK_VARARGS) { |
| 23246 | nargs = DUK_LFUNC_NARGS_VARARGS; |
| 23247 | } else { |
| 23248 | goto api_error; |
| 23249 | } |
| 23250 | if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) { |
| 23251 | goto api_error; |
| 23252 | } |
| 23253 | if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) { |
| 23254 | goto api_error; |
| 23255 | } |
| 23256 | |
| 23257 | lf_flags = DUK_LFUNC_FLAGS_PACK((duk_small_int_t) magic, (duk_small_uint_t) length, (duk_small_uint_t) nargs); |
| 23258 | tv_slot = thr->valstack_top++; |
| 23259 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_slot)); |
| 23260 | DUK_TVAL_SET_LIGHTFUNC(tv_slot, func, lf_flags); |
| 23261 | DUK_ASSERT(tv_slot >= thr->valstack_bottom); |
| 23262 | return (duk_idx_t) (tv_slot - thr->valstack_bottom); |
| 23263 | |
| 23264 | api_error: |
| 23265 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 23266 | DUK_WO_NORETURN(return 0;); |
| 23267 | } |
| 23268 | |
| 23269 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 23270 | DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) { |
| 23271 | duk_hbufobj *obj; |
| 23272 | duk_tval *tv_slot; |
| 23273 | |
| 23274 | DUK_ASSERT_API_ENTRY(thr); |
| 23275 | DUK_ASSERT(prototype_bidx >= 0); |
| 23276 | |
| 23277 | DUK__CHECK_SPACE(); |
| 23278 | |
| 23279 | obj = duk_hbufobj_alloc(thr, hobject_flags_and_class); |
| 23280 | DUK_ASSERT(obj != NULL); |
| 23281 | |
| 23282 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]); |
| 23283 | DUK_HBUFOBJ_ASSERT_VALID(obj); |
| 23284 | |
| 23285 | tv_slot = thr->valstack_top; |
| 23286 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj); |
| 23287 | DUK_HOBJECT_INCREF(thr, obj); |
| 23288 | thr->valstack_top++; |
| 23289 | |
| 23290 | return obj; |
| 23291 | } |
| 23292 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 23293 | |
| 23294 | /* XXX: There's quite a bit of overlap with buffer creation handling in |
| 23295 | * duk_bi_buffer.c. Look for overlap and refactor. |
| 23296 | */ |
| 23297 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 23298 | #define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \ |
| 23299 | (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray)) |
| 23300 | |
| 23301 | static const duk_uint32_t duk__bufobj_flags_lookup[] = { |
| 23302 | /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */ |
| 23303 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */ |
| 23304 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_NODEJS_BUFFER */ |
| 23305 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DATAVIEW */ |
| 23306 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */ |
| 23307 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */ |
| 23308 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */ |
| 23309 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */ |
| 23310 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */ |
| 23311 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */ |
| 23312 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */ |
| 23313 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */ |
| 23314 | DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */ |
| 23315 | }; |
| 23316 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 23317 | |
| 23318 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 23319 | DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { |
| 23320 | duk_hbufobj *h_bufobj; |
| 23321 | duk_hbuffer *h_val; |
| 23322 | duk_hobject *h_arraybuf; |
| 23323 | duk_uint32_t tmp; |
| 23324 | duk_uint_t classnum; |
| 23325 | duk_uint_t protobidx; |
| 23326 | duk_uint_t lookupidx; |
| 23327 | duk_uint_t uint_offset, uint_length, uint_added; |
| 23328 | |
| 23329 | DUK_ASSERT_API_ENTRY(thr); |
| 23330 | |
| 23331 | /* The underlying types for offset/length in duk_hbufobj is |
| 23332 | * duk_uint_t; make sure argument values fit. |
| 23333 | */ |
| 23334 | uint_offset = (duk_uint_t) byte_offset; |
| 23335 | uint_length = (duk_uint_t) byte_length; |
| 23336 | if (sizeof(duk_size_t) != sizeof(duk_uint_t)) { |
| 23337 | if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) { |
| 23338 | goto range_error; |
| 23339 | } |
| 23340 | } |
| 23341 | |
| 23342 | DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */ |
| 23343 | lookupidx = flags; |
| 23344 | if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) { |
| 23345 | goto arg_error; |
| 23346 | } |
| 23347 | tmp = duk__bufobj_flags_lookup[lookupidx]; |
| 23348 | classnum = tmp >> 24; |
| 23349 | protobidx = (tmp >> 16) & 0xff; |
| 23350 | |
| 23351 | h_arraybuf = duk_get_hobject(thr, idx_buffer); |
| 23352 | if (h_arraybuf != NULL && /* argument is an object */ |
| 23353 | flags != DUK_BUFOBJ_ARRAYBUFFER && /* creating a view */ |
| 23354 | DUK_HOBJECT_GET_CLASS_NUMBER(h_arraybuf) == DUK_HOBJECT_CLASS_ARRAYBUFFER /* argument is ArrayBuffer */) { |
| 23355 | duk_uint_t tmp_offset; |
| 23356 | |
| 23357 | DUK_HBUFOBJ_ASSERT_VALID((duk_hbufobj *) h_arraybuf); |
| 23358 | h_val = ((duk_hbufobj *) h_arraybuf)->buf; |
| 23359 | if (DUK_UNLIKELY(h_val == NULL)) { |
| 23360 | goto arg_error; |
| 23361 | } |
| 23362 | |
| 23363 | tmp_offset = uint_offset + ((duk_hbufobj *) h_arraybuf)->offset; |
| 23364 | if (DUK_UNLIKELY(tmp_offset < uint_offset)) { |
| 23365 | goto range_error; |
| 23366 | } |
| 23367 | uint_offset = tmp_offset; |
| 23368 | |
| 23369 | /* Note intentional difference to new TypedArray(): we allow |
| 23370 | * caller to create an uncovered typed array (which is memory |
| 23371 | * safe); new TypedArray() rejects it. |
| 23372 | */ |
| 23373 | } else { |
| 23374 | /* Handle unexpected object arguments here too, for nice error |
| 23375 | * messages. |
| 23376 | */ |
| 23377 | h_arraybuf = NULL; |
| 23378 | h_val = duk_require_hbuffer(thr, idx_buffer); |
| 23379 | } |
| 23380 | |
| 23381 | /* Wrap check for offset+length. */ |
| 23382 | uint_added = uint_offset + uint_length; |
| 23383 | if (DUK_UNLIKELY(uint_added < uint_offset)) { |
| 23384 | goto range_error; |
| 23385 | } |
| 23386 | DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length); |
| 23387 | |
| 23388 | DUK_ASSERT(h_val != NULL); |
| 23389 | |
| 23390 | h_bufobj = duk_push_bufobj_raw(thr, |
| 23391 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23392 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 23393 | DUK_HOBJECT_CLASS_AS_FLAGS(classnum), |
| 23394 | (duk_small_int_t) protobidx); |
| 23395 | DUK_ASSERT(h_bufobj != NULL); |
| 23396 | |
| 23397 | h_bufobj->buf = h_val; |
| 23398 | DUK_HBUFFER_INCREF(thr, h_val); |
| 23399 | h_bufobj->buf_prop = h_arraybuf; |
| 23400 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, h_arraybuf); |
| 23401 | h_bufobj->offset = uint_offset; |
| 23402 | h_bufobj->length = uint_length; |
| 23403 | h_bufobj->shift = (tmp >> 4) & 0x0f; |
| 23404 | h_bufobj->elem_type = (tmp >> 8) & 0xff; |
| 23405 | h_bufobj->is_typedarray = tmp & 0x0f; |
| 23406 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 23407 | |
| 23408 | /* TypedArray views need an automatic ArrayBuffer which must be |
| 23409 | * provided as .buffer property of the view. The ArrayBuffer is |
| 23410 | * referenced via duk_hbufobj->buf_prop and an inherited .buffer |
| 23411 | * accessor returns it. The ArrayBuffer is created lazily on first |
| 23412 | * access if necessary so we don't need to do anything more here. |
| 23413 | */ |
| 23414 | return; |
| 23415 | |
| 23416 | range_error: |
| 23417 | DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); |
| 23418 | DUK_WO_NORETURN(return;); |
| 23419 | |
| 23420 | arg_error: |
| 23421 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS); |
| 23422 | DUK_WO_NORETURN(return;); |
| 23423 | } |
| 23424 | #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 23425 | DUK_EXTERNAL void duk_push_buffer_object(duk_hthread *thr, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) { |
| 23426 | DUK_ASSERT_API_ENTRY(thr); |
| 23427 | DUK_UNREF(idx_buffer); |
| 23428 | DUK_UNREF(byte_offset); |
| 23429 | DUK_UNREF(byte_length); |
| 23430 | DUK_UNREF(flags); |
| 23431 | DUK_ERROR_UNSUPPORTED(thr); |
| 23432 | DUK_WO_NORETURN(return;); |
| 23433 | } |
| 23434 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 23435 | |
| 23436 | DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { |
| 23437 | duk_hobject *proto; |
| 23438 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 23439 | duk_small_uint_t augment_flags; |
| 23440 | #endif |
| 23441 | |
| 23442 | DUK_ASSERT_API_ENTRY(thr); |
| 23443 | DUK_ASSERT(thr != NULL); |
| 23444 | DUK_UNREF(filename); |
| 23445 | DUK_UNREF(line); |
| 23446 | |
| 23447 | /* Error code also packs a tracedata related flag. */ |
| 23448 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 23449 | augment_flags = 0; |
| 23450 | if (err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE) { |
| 23451 | augment_flags = DUK_AUGMENT_FLAG_NOBLAME_FILELINE; |
| 23452 | } |
| 23453 | #endif |
| 23454 | err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE); |
| 23455 | |
| 23456 | /* error gets its 'name' from the prototype */ |
| 23457 | proto = duk_error_prototype_from_code(thr, err_code); |
| 23458 | (void) duk_push_object_helper_proto(thr, |
| 23459 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23460 | DUK_HOBJECT_FLAG_FASTREFS | |
| 23461 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR), |
| 23462 | proto); |
| 23463 | |
| 23464 | /* ... and its 'message' from an instance property */ |
| 23465 | if (fmt) { |
| 23466 | duk_push_vsprintf(thr, fmt, ap); |
| 23467 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); |
| 23468 | } else { |
| 23469 | /* If no explicit message given, put error code into message field |
| 23470 | * (as a number). This is not fully in keeping with the ECMAScript |
| 23471 | * error model because messages are supposed to be strings (Error |
| 23472 | * constructors use ToString() on their argument). However, it's |
| 23473 | * probably more useful than having a separate 'code' property. |
| 23474 | */ |
| 23475 | duk_push_int(thr, err_code); |
| 23476 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); |
| 23477 | } |
| 23478 | |
| 23479 | /* XXX: .code = err_code disabled, not sure if useful */ |
| 23480 | |
| 23481 | /* Creation time error augmentation */ |
| 23482 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 23483 | /* filename may be NULL in which case file/line is not recorded */ |
| 23484 | duk_err_augment_error_create(thr, thr, filename, line, augment_flags); /* may throw an error */ |
| 23485 | #endif |
| 23486 | |
| 23487 | return duk_get_top_index_unsafe(thr); |
| 23488 | } |
| 23489 | |
| 23490 | DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { |
| 23491 | va_list ap; |
| 23492 | duk_idx_t ret; |
| 23493 | |
| 23494 | DUK_ASSERT_API_ENTRY(thr); |
| 23495 | |
| 23496 | va_start(ap, fmt); |
| 23497 | ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); |
| 23498 | va_end(ap); |
| 23499 | return ret; |
| 23500 | } |
| 23501 | |
| 23502 | #if !defined(DUK_USE_VARIADIC_MACROS) |
| 23503 | DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) { |
| 23504 | const char *filename = duk_api_global_filename; |
| 23505 | duk_int_t line = duk_api_global_line; |
| 23506 | va_list ap; |
| 23507 | duk_idx_t ret; |
| 23508 | |
| 23509 | DUK_ASSERT_API_ENTRY(thr); |
| 23510 | |
| 23511 | duk_api_global_filename = NULL; |
| 23512 | duk_api_global_line = 0; |
| 23513 | va_start(ap, fmt); |
| 23514 | ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); |
| 23515 | va_end(ap); |
| 23516 | return ret; |
| 23517 | } |
| 23518 | #endif /* DUK_USE_VARIADIC_MACROS */ |
| 23519 | |
| 23520 | DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_small_uint_t flags) { |
| 23521 | duk_tval *tv_slot; |
| 23522 | duk_hbuffer *h; |
| 23523 | void *buf_data; |
| 23524 | |
| 23525 | DUK_ASSERT_API_ENTRY(thr); |
| 23526 | |
| 23527 | DUK__CHECK_SPACE(); |
| 23528 | |
| 23529 | /* Check for maximum buffer length. */ |
| 23530 | if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) { |
| 23531 | DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); |
| 23532 | DUK_WO_NORETURN(return NULL;); |
| 23533 | } |
| 23534 | |
| 23535 | h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data); |
| 23536 | if (DUK_UNLIKELY(h == NULL)) { |
| 23537 | DUK_ERROR_ALLOC_FAILED(thr); |
| 23538 | DUK_WO_NORETURN(return NULL;); |
| 23539 | } |
| 23540 | |
| 23541 | tv_slot = thr->valstack_top; |
| 23542 | DUK_TVAL_SET_BUFFER(tv_slot, h); |
| 23543 | DUK_HBUFFER_INCREF(thr, h); |
| 23544 | thr->valstack_top++; |
| 23545 | |
| 23546 | return (void *) buf_data; |
| 23547 | } |
| 23548 | |
| 23549 | DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len) { |
| 23550 | DUK_ASSERT_API_ENTRY(thr); |
| 23551 | return duk_push_buffer_raw(thr, len, DUK_BUF_FLAG_NOZERO); |
| 23552 | } |
| 23553 | |
| 23554 | DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) { |
| 23555 | void *ptr; |
| 23556 | |
| 23557 | DUK_ASSERT_API_ENTRY(thr); |
| 23558 | |
| 23559 | ptr = duk_push_buffer_raw(thr, len, 0); |
| 23560 | DUK_ASSERT(ptr != NULL); |
| 23561 | #if !defined(DUK_USE_ZERO_BUFFER_DATA) |
| 23562 | /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA |
| 23563 | * is not set. |
| 23564 | */ |
| 23565 | duk_memzero((void *) ptr, (size_t) len); |
| 23566 | #endif |
| 23567 | return ptr; |
| 23568 | } |
| 23569 | |
| 23570 | #if defined(DUK_USE_ES6_PROXY) |
| 23571 | DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) { |
| 23572 | duk_hobject *h_target; |
| 23573 | duk_hobject *h_handler; |
| 23574 | duk_hproxy *h_proxy; |
| 23575 | duk_tval *tv_slot; |
| 23576 | duk_uint_t flags; |
| 23577 | |
| 23578 | DUK_ASSERT_API_ENTRY(thr); |
| 23579 | DUK_UNREF(proxy_flags); |
| 23580 | |
| 23581 | /* DUK__CHECK_SPACE() unnecessary because the Proxy is written to |
| 23582 | * value stack in-place. |
| 23583 | */ |
| 23584 | #if 0 |
| 23585 | DUK__CHECK_SPACE(); |
| 23586 | #endif |
| 23587 | |
| 23588 | /* Reject a proxy object as the target because it would need |
| 23589 | * special handling in property lookups. (ES2015 has no such |
| 23590 | * restriction.) |
| 23591 | */ |
| 23592 | h_target = duk_require_hobject_promote_mask(thr, -2, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 23593 | DUK_ASSERT(h_target != NULL); |
| 23594 | if (DUK_HOBJECT_IS_PROXY(h_target)) { |
| 23595 | goto fail_args; |
| 23596 | } |
| 23597 | |
| 23598 | /* Reject a proxy object as the handler because it would cause |
| 23599 | * potentially unbounded recursion. (ES2015 has no such |
| 23600 | * restriction.) |
| 23601 | * |
| 23602 | * There's little practical reason to use a lightfunc or a plain |
| 23603 | * buffer as the handler table: one could only provide traps via |
| 23604 | * their prototype objects (Function.prototype and ArrayBuffer.prototype). |
| 23605 | * Even so, as lightfuncs and plain buffers mimic their object |
| 23606 | * counterparts, they're promoted and accepted here. |
| 23607 | */ |
| 23608 | h_handler = duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 23609 | DUK_ASSERT(h_handler != NULL); |
| 23610 | if (DUK_HOBJECT_IS_PROXY(h_handler)) { |
| 23611 | goto fail_args; |
| 23612 | } |
| 23613 | |
| 23614 | /* XXX: Proxy object currently has no prototype, so ToPrimitive() |
| 23615 | * coercion fails which is a bit confusing. |
| 23616 | */ |
| 23617 | |
| 23618 | /* CALLABLE and CONSTRUCTABLE flags are copied from the (initial) |
| 23619 | * target, see ES2015 Sections 9.5.15 and 9.5.13. |
| 23620 | */ |
| 23621 | flags = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h_target) & |
| 23622 | (DUK_HOBJECT_FLAG_CALLABLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE); |
| 23623 | flags |= DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23624 | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ; |
| 23625 | if (flags & DUK_HOBJECT_FLAG_CALLABLE) { |
| 23626 | flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION) | |
| 23627 | DUK_HOBJECT_FLAG_SPECIAL_CALL; |
| 23628 | } else { |
| 23629 | flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT); |
| 23630 | } |
| 23631 | |
| 23632 | h_proxy = duk_hproxy_alloc(thr, flags); |
| 23633 | DUK_ASSERT(h_proxy != NULL); |
| 23634 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_proxy) == NULL); |
| 23635 | |
| 23636 | /* Initialize Proxy target and handler references; avoid INCREF |
| 23637 | * by stealing the value stack refcounts via direct value stack |
| 23638 | * manipulation. INCREF is needed for the Proxy itself however. |
| 23639 | */ |
| 23640 | DUK_ASSERT(h_target != NULL); |
| 23641 | h_proxy->target = h_target; |
| 23642 | DUK_ASSERT(h_handler != NULL); |
| 23643 | h_proxy->handler = h_handler; |
| 23644 | DUK_HPROXY_ASSERT_VALID(h_proxy); |
| 23645 | |
| 23646 | DUK_ASSERT(duk_get_hobject(thr, -2) == h_target); |
| 23647 | DUK_ASSERT(duk_get_hobject(thr, -1) == h_handler); |
| 23648 | tv_slot = thr->valstack_top - 2; |
| 23649 | DUK_ASSERT(tv_slot >= thr->valstack_bottom); |
| 23650 | DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) h_proxy); |
| 23651 | DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_proxy); |
| 23652 | tv_slot++; |
| 23653 | DUK_TVAL_SET_UNDEFINED(tv_slot); /* [ ... target handler ] -> [ ... proxy undefined ] */ |
| 23654 | thr->valstack_top = tv_slot; /* -> [ ... proxy ] */ |
| 23655 | |
| 23656 | DUK_DD(DUK_DDPRINT("created Proxy: %!iT" , duk_get_tval(thr, -1))); |
| 23657 | |
| 23658 | return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom - 1); |
| 23659 | |
| 23660 | fail_args: |
| 23661 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 23662 | DUK_WO_NORETURN(return 0;); |
| 23663 | } |
| 23664 | #else /* DUK_USE_ES6_PROXY */ |
| 23665 | DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) { |
| 23666 | DUK_ASSERT_API_ENTRY(thr); |
| 23667 | DUK_UNREF(proxy_flags); |
| 23668 | DUK_ERROR_UNSUPPORTED(thr); |
| 23669 | DUK_WO_NORETURN(return 0;); |
| 23670 | } |
| 23671 | #endif /* DUK_USE_ES6_PROXY */ |
| 23672 | |
| 23673 | #if defined(DUK_USE_ASSERTIONS) |
| 23674 | DUK_LOCAL void duk__validate_push_heapptr(duk_hthread *thr, void *ptr) { |
| 23675 | duk_heaphdr *h; |
| 23676 | duk_heaphdr *curr; |
| 23677 | duk_bool_t found = 0; |
| 23678 | |
| 23679 | h = (duk_heaphdr *) ptr; |
| 23680 | if (h == NULL) { |
| 23681 | /* Allowed. */ |
| 23682 | return; |
| 23683 | } |
| 23684 | DUK_ASSERT(h != NULL); |
| 23685 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); |
| 23686 | |
| 23687 | /* One particular problem case is where an object has been |
| 23688 | * queued for finalization but the finalizer hasn't yet been |
| 23689 | * executed. |
| 23690 | * |
| 23691 | * Corner case: we're running in a finalizer for object X, and |
| 23692 | * user code calls duk_push_heapptr() for X itself. In this |
| 23693 | * case X will be in finalize_list, and we can detect the case |
| 23694 | * by seeing that X's FINALIZED flag is set (which is done before |
| 23695 | * the finalizer starts executing). |
| 23696 | */ |
| 23697 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 23698 | for (curr = thr->heap->finalize_list; |
| 23699 | curr != NULL; |
| 23700 | curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { |
| 23701 | /* FINALIZABLE is set for all objects on finalize_list |
| 23702 | * except for an object being finalized right now. So |
| 23703 | * can't assert here. |
| 23704 | */ |
| 23705 | #if 0 |
| 23706 | DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); |
| 23707 | #endif |
| 23708 | |
| 23709 | if (curr == h) { |
| 23710 | if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) { |
| 23711 | /* Object is currently being finalized. */ |
| 23712 | DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ |
| 23713 | found = 1; |
| 23714 | } else { |
| 23715 | /* Not being finalized but on finalize_list, |
| 23716 | * allowed since Duktape 2.1. |
| 23717 | */ |
| 23718 | DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ |
| 23719 | found = 1; |
| 23720 | } |
| 23721 | } |
| 23722 | } |
| 23723 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 23724 | |
| 23725 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 23726 | /* Because refzero_list is now processed to completion inline with |
| 23727 | * no side effects, it's always empty here. |
| 23728 | */ |
| 23729 | DUK_ASSERT(thr->heap->refzero_list == NULL); |
| 23730 | #endif |
| 23731 | |
| 23732 | /* If not present in finalize_list (or refzero_list), it |
| 23733 | * must be either in heap_allocated or the string table. |
| 23734 | */ |
| 23735 | if (DUK_HEAPHDR_IS_STRING(h)) { |
| 23736 | duk_uint32_t i; |
| 23737 | duk_hstring *str; |
| 23738 | duk_heap *heap = thr->heap; |
| 23739 | |
| 23740 | DUK_ASSERT(found == 0); |
| 23741 | for (i = 0; i < heap->st_size; i++) { |
| 23742 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 23743 | str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); |
| 23744 | #else |
| 23745 | str = heap->strtable[i]; |
| 23746 | #endif |
| 23747 | while (str != NULL) { |
| 23748 | if (str == (duk_hstring *) h) { |
| 23749 | DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ |
| 23750 | found = 1; |
| 23751 | break; |
| 23752 | } |
| 23753 | str = str->hdr.h_next; |
| 23754 | } |
| 23755 | } |
| 23756 | DUK_ASSERT(found != 0); |
| 23757 | } else { |
| 23758 | for (curr = thr->heap->heap_allocated; |
| 23759 | curr != NULL; |
| 23760 | curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) { |
| 23761 | if (curr == h) { |
| 23762 | DUK_ASSERT(found == 0); /* Would indicate corrupted lists. */ |
| 23763 | found = 1; |
| 23764 | } |
| 23765 | } |
| 23766 | DUK_ASSERT(found != 0); |
| 23767 | } |
| 23768 | } |
| 23769 | #endif /* DUK_USE_ASSERTIONS */ |
| 23770 | |
| 23771 | DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_hthread *thr, void *ptr) { |
| 23772 | duk_idx_t ret; |
| 23773 | duk_tval *tv; |
| 23774 | |
| 23775 | DUK_ASSERT_API_ENTRY(thr); |
| 23776 | |
| 23777 | /* Reviving an object using a heap pointer is a dangerous API |
| 23778 | * operation: if the application doesn't guarantee that the |
| 23779 | * pointer target is always reachable, difficult-to-diagnose |
| 23780 | * problems may ensue. Try to validate the 'ptr' argument to |
| 23781 | * the extent possible. |
| 23782 | */ |
| 23783 | |
| 23784 | #if defined(DUK_USE_ASSERTIONS) |
| 23785 | duk__validate_push_heapptr(thr, ptr); |
| 23786 | #endif |
| 23787 | |
| 23788 | DUK__CHECK_SPACE(); |
| 23789 | |
| 23790 | ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 23791 | tv = thr->valstack_top++; |
| 23792 | |
| 23793 | if (ptr == NULL) { |
| 23794 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); |
| 23795 | return ret; |
| 23796 | } |
| 23797 | |
| 23798 | DUK_HEAPHDR_ASSERT_VALID((duk_heaphdr *) ptr); |
| 23799 | |
| 23800 | /* If the argument is on finalize_list it has technically been |
| 23801 | * unreachable before duk_push_heapptr() but it's still safe to |
| 23802 | * push it. Starting from Duktape 2.1 allow application code to |
| 23803 | * do so. There are two main cases: |
| 23804 | * |
| 23805 | * (1) The object is on the finalize_list and we're called by |
| 23806 | * the finalizer for the object being finalized. In this |
| 23807 | * case do nothing: finalize_list handling will deal with |
| 23808 | * the object queueing. This is detected by the object not |
| 23809 | * having a FINALIZABLE flag despite being on the finalize_list; |
| 23810 | * the flag is cleared for the object being finalized only. |
| 23811 | * |
| 23812 | * (2) The object is on the finalize_list but is not currently |
| 23813 | * being processed. In this case the object can be queued |
| 23814 | * back to heap_allocated with a few flags cleared, in effect |
| 23815 | * cancelling the finalizer. |
| 23816 | */ |
| 23817 | if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) { |
| 23818 | duk_heaphdr *curr; |
| 23819 | |
| 23820 | DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue" )); |
| 23821 | |
| 23822 | curr = (duk_heaphdr *) ptr; |
| 23823 | DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); |
| 23824 | |
| 23825 | /* Because FINALIZED is set prior to finalizer call, it will |
| 23826 | * be set for the object being currently finalized, but not |
| 23827 | * for other objects on finalize_list. |
| 23828 | */ |
| 23829 | DUK_HEAPHDR_CLEAR_FINALIZED(curr); |
| 23830 | |
| 23831 | /* Dequeue object from finalize_list and queue it back to |
| 23832 | * heap_allocated. |
| 23833 | */ |
| 23834 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 23835 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); /* Preincremented on finalize_list insert. */ |
| 23836 | DUK_HEAPHDR_PREDEC_REFCOUNT(curr); |
| 23837 | #endif |
| 23838 | DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr); |
| 23839 | DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr); |
| 23840 | |
| 23841 | /* Continue with the rest. */ |
| 23842 | } |
| 23843 | |
| 23844 | switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) { |
| 23845 | case DUK_HTYPE_STRING: |
| 23846 | DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr); |
| 23847 | break; |
| 23848 | case DUK_HTYPE_OBJECT: |
| 23849 | DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr); |
| 23850 | break; |
| 23851 | default: |
| 23852 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER); |
| 23853 | DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr); |
| 23854 | break; |
| 23855 | } |
| 23856 | |
| 23857 | DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr); |
| 23858 | |
| 23859 | return ret; |
| 23860 | } |
| 23861 | |
| 23862 | /* Push object with no prototype, i.e. a "bare" object. */ |
| 23863 | DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_hthread *thr) { |
| 23864 | DUK_ASSERT_API_ENTRY(thr); |
| 23865 | |
| 23866 | (void) duk_push_object_helper(thr, |
| 23867 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 23868 | DUK_HOBJECT_FLAG_FASTREFS | |
| 23869 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), |
| 23870 | -1); /* no prototype */ |
| 23871 | return duk_get_top_index_unsafe(thr); |
| 23872 | } |
| 23873 | |
| 23874 | DUK_INTERNAL void duk_push_hstring(duk_hthread *thr, duk_hstring *h) { |
| 23875 | duk_tval tv; |
| 23876 | |
| 23877 | DUK_ASSERT_API_ENTRY(thr); |
| 23878 | DUK_ASSERT(h != NULL); |
| 23879 | |
| 23880 | DUK_TVAL_SET_STRING(&tv, h); |
| 23881 | duk_push_tval(thr, &tv); |
| 23882 | } |
| 23883 | |
| 23884 | DUK_INTERNAL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx) { |
| 23885 | DUK_ASSERT_API_ENTRY(thr); |
| 23886 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 23887 | duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); |
| 23888 | } |
| 23889 | |
| 23890 | DUK_INTERNAL void duk_push_hstring_empty(duk_hthread *thr) { |
| 23891 | DUK_ASSERT_API_ENTRY(thr); |
| 23892 | duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING)); |
| 23893 | } |
| 23894 | |
| 23895 | DUK_INTERNAL void duk_push_hobject(duk_hthread *thr, duk_hobject *h) { |
| 23896 | duk_tval tv; |
| 23897 | |
| 23898 | DUK_ASSERT_API_ENTRY(thr); |
| 23899 | DUK_ASSERT(h != NULL); |
| 23900 | |
| 23901 | DUK_TVAL_SET_OBJECT(&tv, h); |
| 23902 | duk_push_tval(thr, &tv); |
| 23903 | } |
| 23904 | |
| 23905 | DUK_INTERNAL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h) { |
| 23906 | duk_tval tv; |
| 23907 | |
| 23908 | DUK_ASSERT_API_ENTRY(thr); |
| 23909 | DUK_ASSERT(h != NULL); |
| 23910 | |
| 23911 | DUK_TVAL_SET_BUFFER(&tv, h); |
| 23912 | duk_push_tval(thr, &tv); |
| 23913 | } |
| 23914 | |
| 23915 | DUK_INTERNAL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx) { |
| 23916 | DUK_ASSERT_API_ENTRY(thr); |
| 23917 | DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS); |
| 23918 | DUK_ASSERT(thr->builtins[builtin_idx] != NULL); |
| 23919 | |
| 23920 | duk_push_hobject(thr, thr->builtins[builtin_idx]); |
| 23921 | } |
| 23922 | |
| 23923 | /* |
| 23924 | * Poppers |
| 23925 | */ |
| 23926 | |
| 23927 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_n_unsafe_raw(duk_hthread *thr, duk_idx_t count) { |
| 23928 | duk_tval *tv; |
| 23929 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 23930 | duk_tval *tv_end; |
| 23931 | #endif |
| 23932 | |
| 23933 | DUK_CTX_ASSERT_VALID(thr); |
| 23934 | DUK_ASSERT(count >= 0); |
| 23935 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); |
| 23936 | |
| 23937 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 23938 | tv = thr->valstack_top; |
| 23939 | tv_end = tv - count; |
| 23940 | while (tv != tv_end) { |
| 23941 | tv--; |
| 23942 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 23943 | DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); |
| 23944 | } |
| 23945 | thr->valstack_top = tv; |
| 23946 | DUK_REFZERO_CHECK_FAST(thr); |
| 23947 | #else |
| 23948 | tv = thr->valstack_top; |
| 23949 | while (count > 0) { |
| 23950 | count--; |
| 23951 | tv--; |
| 23952 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 23953 | DUK_TVAL_SET_UNDEFINED(tv); |
| 23954 | } |
| 23955 | thr->valstack_top = tv; |
| 23956 | #endif |
| 23957 | |
| 23958 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 23959 | } |
| 23960 | |
| 23961 | DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) { |
| 23962 | DUK_ASSERT_API_ENTRY(thr); |
| 23963 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 23964 | |
| 23965 | if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) { |
| 23966 | DUK_ERROR_RANGE_INVALID_COUNT(thr); |
| 23967 | DUK_WO_NORETURN(return;); |
| 23968 | } |
| 23969 | DUK_ASSERT(count >= 0); |
| 23970 | |
| 23971 | duk__pop_n_unsafe_raw(thr, count); |
| 23972 | } |
| 23973 | |
| 23974 | #if defined(DUK_USE_PREFER_SIZE) |
| 23975 | DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) { |
| 23976 | DUK_ASSERT_API_ENTRY(thr); |
| 23977 | duk_pop_n(thr, count); |
| 23978 | } |
| 23979 | #else /* DUK_USE_PREFER_SIZE */ |
| 23980 | DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) { |
| 23981 | DUK_ASSERT_API_ENTRY(thr); |
| 23982 | duk__pop_n_unsafe_raw(thr, count); |
| 23983 | } |
| 23984 | #endif /* DUK_USE_PREFER_SIZE */ |
| 23985 | |
| 23986 | /* Pop N elements without DECREF (in effect "stealing" any actual refcounts). */ |
| 23987 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 23988 | DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) { |
| 23989 | duk_tval *tv; |
| 23990 | |
| 23991 | DUK_ASSERT_API_ENTRY(thr); |
| 23992 | DUK_ASSERT(count >= 0); |
| 23993 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 23994 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count); |
| 23995 | |
| 23996 | tv = thr->valstack_top; |
| 23997 | while (count > 0) { |
| 23998 | count--; |
| 23999 | tv--; |
| 24000 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 24001 | DUK_TVAL_SET_UNDEFINED(tv); |
| 24002 | } |
| 24003 | thr->valstack_top = tv; |
| 24004 | |
| 24005 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24006 | } |
| 24007 | #else /* DUK_USE_REFERENCE_COUNTING */ |
| 24008 | DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) { |
| 24009 | DUK_ASSERT_API_ENTRY(thr); |
| 24010 | duk_pop_n_unsafe(thr, count); |
| 24011 | } |
| 24012 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 24013 | |
| 24014 | /* Popping one element is called so often that when footprint is not an issue, |
| 24015 | * compile a specialized function for it. |
| 24016 | */ |
| 24017 | #if defined(DUK_USE_PREFER_SIZE) |
| 24018 | DUK_EXTERNAL void duk_pop(duk_hthread *thr) { |
| 24019 | DUK_ASSERT_API_ENTRY(thr); |
| 24020 | duk_pop_n(thr, 1); |
| 24021 | } |
| 24022 | DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) { |
| 24023 | DUK_ASSERT_API_ENTRY(thr); |
| 24024 | duk_pop_n_unsafe(thr, 1); |
| 24025 | } |
| 24026 | DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) { |
| 24027 | DUK_ASSERT_API_ENTRY(thr); |
| 24028 | duk_pop_n_nodecref_unsafe(thr, 1); |
| 24029 | } |
| 24030 | #else /* DUK_USE_PREFER_SIZE */ |
| 24031 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_unsafe_raw(duk_hthread *thr) { |
| 24032 | duk_tval *tv; |
| 24033 | |
| 24034 | DUK_CTX_ASSERT_VALID(thr); |
| 24035 | DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); |
| 24036 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24037 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); |
| 24038 | |
| 24039 | tv = --thr->valstack_top; |
| 24040 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 24041 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 24042 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ |
| 24043 | #else |
| 24044 | DUK_TVAL_SET_UNDEFINED(tv); |
| 24045 | #endif |
| 24046 | |
| 24047 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24048 | } |
| 24049 | DUK_EXTERNAL void duk_pop(duk_hthread *thr) { |
| 24050 | DUK_ASSERT_API_ENTRY(thr); |
| 24051 | |
| 24052 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24053 | if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { |
| 24054 | DUK_ERROR_RANGE_INVALID_COUNT(thr); |
| 24055 | DUK_WO_NORETURN(return;); |
| 24056 | } |
| 24057 | |
| 24058 | duk__pop_unsafe_raw(thr); |
| 24059 | } |
| 24060 | DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) { |
| 24061 | DUK_ASSERT_API_ENTRY(thr); |
| 24062 | duk__pop_unsafe_raw(thr); |
| 24063 | } |
| 24064 | DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) { |
| 24065 | duk_tval *tv; |
| 24066 | |
| 24067 | DUK_ASSERT_API_ENTRY(thr); |
| 24068 | DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); |
| 24069 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24070 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); |
| 24071 | |
| 24072 | tv = --thr->valstack_top; |
| 24073 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 24074 | DUK_TVAL_SET_UNDEFINED(tv); |
| 24075 | |
| 24076 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24077 | } |
| 24078 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 24079 | |
| 24080 | #if defined(DUK_USE_PREFER_SIZE) |
| 24081 | DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) { |
| 24082 | DUK_ASSERT_API_ENTRY(thr); |
| 24083 | duk_pop_nodecref_unsafe(thr); |
| 24084 | } |
| 24085 | #else /* DUK_USE_PREFER_SIZE */ |
| 24086 | DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) { |
| 24087 | DUK_ASSERT_API_ENTRY(thr); |
| 24088 | DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); |
| 24089 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24090 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1); |
| 24091 | |
| 24092 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1)); |
| 24093 | thr->valstack_top--; |
| 24094 | |
| 24095 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24096 | } |
| 24097 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 24098 | |
| 24099 | #if defined(DUK_USE_PREFER_SIZE) |
| 24100 | DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) { |
| 24101 | DUK_ASSERT_API_ENTRY(thr); |
| 24102 | duk_pop_n(thr, 2); |
| 24103 | } |
| 24104 | DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) { |
| 24105 | DUK_ASSERT_API_ENTRY(thr); |
| 24106 | duk_pop_n_unsafe(thr, 2); |
| 24107 | } |
| 24108 | DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) { |
| 24109 | DUK_ASSERT_API_ENTRY(thr); |
| 24110 | duk_pop_n_nodecref_unsafe(thr, 2); |
| 24111 | } |
| 24112 | #else |
| 24113 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_2_unsafe_raw(duk_hthread *thr) { |
| 24114 | duk_tval *tv; |
| 24115 | |
| 24116 | DUK_CTX_ASSERT_VALID(thr); |
| 24117 | DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); |
| 24118 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24119 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2); |
| 24120 | |
| 24121 | tv = --thr->valstack_top; |
| 24122 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 24123 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 24124 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ |
| 24125 | #else |
| 24126 | DUK_TVAL_SET_UNDEFINED(tv); |
| 24127 | #endif |
| 24128 | tv = --thr->valstack_top; |
| 24129 | DUK_ASSERT(tv >= thr->valstack_bottom); |
| 24130 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 24131 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */ |
| 24132 | #else |
| 24133 | DUK_TVAL_SET_UNDEFINED(tv); |
| 24134 | #endif |
| 24135 | |
| 24136 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24137 | } |
| 24138 | DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) { |
| 24139 | DUK_ASSERT_API_ENTRY(thr); |
| 24140 | |
| 24141 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24142 | if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) { |
| 24143 | DUK_ERROR_RANGE_INVALID_COUNT(thr); |
| 24144 | DUK_WO_NORETURN(return;); |
| 24145 | } |
| 24146 | |
| 24147 | duk__pop_2_unsafe_raw(thr); |
| 24148 | } |
| 24149 | DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) { |
| 24150 | DUK_ASSERT_API_ENTRY(thr); |
| 24151 | duk__pop_2_unsafe_raw(thr); |
| 24152 | } |
| 24153 | DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) { |
| 24154 | DUK_ASSERT_API_ENTRY(thr); |
| 24155 | DUK_ASSERT(thr->valstack_top != thr->valstack_bottom); |
| 24156 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24157 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2); |
| 24158 | |
| 24159 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1)); |
| 24160 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 2)); |
| 24161 | thr->valstack_top -= 2; |
| 24162 | |
| 24163 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24164 | } |
| 24165 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 24166 | |
| 24167 | DUK_EXTERNAL void duk_pop_3(duk_hthread *thr) { |
| 24168 | DUK_ASSERT_API_ENTRY(thr); |
| 24169 | duk_pop_n(thr, 3); |
| 24170 | } |
| 24171 | |
| 24172 | DUK_INTERNAL void duk_pop_3_unsafe(duk_hthread *thr) { |
| 24173 | DUK_ASSERT_API_ENTRY(thr); |
| 24174 | duk_pop_n_unsafe(thr, 3); |
| 24175 | } |
| 24176 | |
| 24177 | DUK_INTERNAL void duk_pop_3_nodecref_unsafe(duk_hthread *thr) { |
| 24178 | DUK_ASSERT_API_ENTRY(thr); |
| 24179 | duk_pop_n_nodecref_unsafe(thr, 3); |
| 24180 | } |
| 24181 | |
| 24182 | /* |
| 24183 | * Pack and unpack (pack value stack entries into an array and vice versa) |
| 24184 | */ |
| 24185 | |
| 24186 | /* XXX: pack index range? array index offset? */ |
| 24187 | /* XXX: need ability to pack into a bare array? */ |
| 24188 | DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) { |
| 24189 | duk_tval *tv_src; |
| 24190 | duk_tval *tv_dst; |
| 24191 | duk_tval *tv_curr; |
| 24192 | duk_tval *tv_limit; |
| 24193 | duk_idx_t top; |
| 24194 | |
| 24195 | DUK_ASSERT_API_ENTRY(thr); |
| 24196 | |
| 24197 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24198 | top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 24199 | DUK_ASSERT(top >= 0); |
| 24200 | if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) { |
| 24201 | /* Also handles negative count. */ |
| 24202 | DUK_ERROR_RANGE_INVALID_COUNT(thr); |
| 24203 | DUK_WO_NORETURN(return;); |
| 24204 | } |
| 24205 | DUK_ASSERT(count >= 0); |
| 24206 | |
| 24207 | /* Wrapping is controlled by the check above: value stack top can be |
| 24208 | * at most DUK_USE_VALSTACK_LIMIT which is low enough so that |
| 24209 | * multiplying with sizeof(duk_tval) won't wrap. |
| 24210 | */ |
| 24211 | DUK_ASSERT(count >= 0 && count <= (duk_idx_t) DUK_USE_VALSTACK_LIMIT); |
| 24212 | DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */ |
| 24213 | |
| 24214 | tv_dst = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); /* XXX: uninitialized would be OK */ |
| 24215 | DUK_ASSERT(count == 0 || tv_dst != NULL); |
| 24216 | DUK_ASSERT(!duk_is_bare_object(thr, -1)); |
| 24217 | |
| 24218 | /* Copy value stack values directly to the array part without |
| 24219 | * any refcount updates: net refcount changes are zero. |
| 24220 | */ |
| 24221 | tv_src = thr->valstack_top - count - 1; |
| 24222 | duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval)); |
| 24223 | |
| 24224 | /* Overwrite result array to final value stack location and wipe |
| 24225 | * the rest; no refcount operations needed. |
| 24226 | */ |
| 24227 | |
| 24228 | tv_dst = tv_src; /* when count == 0, same as tv_src (OK) */ |
| 24229 | tv_src = thr->valstack_top - 1; |
| 24230 | DUK_TVAL_SET_TVAL(tv_dst, tv_src); |
| 24231 | |
| 24232 | /* XXX: internal helper to wipe a value stack segment? */ |
| 24233 | tv_curr = tv_dst + 1; |
| 24234 | tv_limit = thr->valstack_top; |
| 24235 | while (tv_curr != tv_limit) { |
| 24236 | /* Wipe policy: keep as 'undefined'. */ |
| 24237 | DUK_TVAL_SET_UNDEFINED(tv_curr); |
| 24238 | tv_curr++; |
| 24239 | } |
| 24240 | thr->valstack_top = tv_dst + 1; |
| 24241 | } |
| 24242 | |
| 24243 | DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) { |
| 24244 | duk_tval *tv; |
| 24245 | |
| 24246 | DUK_ASSERT_API_ENTRY(thr); |
| 24247 | |
| 24248 | tv = duk_require_tval(thr, idx); |
| 24249 | if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv))) { |
| 24250 | duk_hobject *h; |
| 24251 | duk_uint32_t len; |
| 24252 | duk_uint32_t i; |
| 24253 | |
| 24254 | h = DUK_TVAL_GET_OBJECT(tv); |
| 24255 | DUK_ASSERT(h != NULL); |
| 24256 | DUK_UNREF(h); |
| 24257 | |
| 24258 | #if defined(DUK_USE_ARRAY_FASTPATH) /* close enough */ |
| 24259 | if (DUK_LIKELY(DUK_HOBJECT_IS_ARRAY(h) && |
| 24260 | ((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h))) { |
| 24261 | duk_harray *h_arr; |
| 24262 | duk_tval *tv_src; |
| 24263 | duk_tval *tv_dst; |
| 24264 | |
| 24265 | h_arr = (duk_harray *) h; |
| 24266 | len = h_arr->length; |
| 24267 | if (DUK_UNLIKELY(len >= 0x80000000UL)) { |
| 24268 | goto fail_over_2g; |
| 24269 | } |
| 24270 | duk_require_stack(thr, (duk_idx_t) len); |
| 24271 | |
| 24272 | /* The potential allocation in duk_require_stack() may |
| 24273 | * run a finalizer which modifies the argArray so that |
| 24274 | * e.g. becomes sparse. So, we need to recheck that the |
| 24275 | * array didn't change size and that there's still a |
| 24276 | * valid backing array part. |
| 24277 | * |
| 24278 | * XXX: alternatively, could prevent finalizers for the |
| 24279 | * duration. |
| 24280 | */ |
| 24281 | if (DUK_UNLIKELY(len != h_arr->length || |
| 24282 | h_arr->length > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr))) { |
| 24283 | goto skip_fast; |
| 24284 | } |
| 24285 | |
| 24286 | /* Main fast path: arguments array is almost always |
| 24287 | * an actual array (though it might also be an arguments |
| 24288 | * object). |
| 24289 | */ |
| 24290 | |
| 24291 | DUK_DDD(DUK_DDDPRINT("fast path for %ld elements" , (long) h_arr->length)); |
| 24292 | tv_src = DUK_HOBJECT_A_GET_BASE(thr->heap, h); |
| 24293 | tv_dst = thr->valstack_top; |
| 24294 | while (len-- > 0) { |
| 24295 | DUK_ASSERT(tv_dst < thr->valstack_end); |
| 24296 | if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_src))) { |
| 24297 | /* Gaps are very unlikely. Skip over them, |
| 24298 | * without an ancestor lookup (technically |
| 24299 | * not compliant). |
| 24300 | */ |
| 24301 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_dst)); /* valstack policy */ |
| 24302 | } else { |
| 24303 | DUK_TVAL_SET_TVAL(tv_dst, tv_src); |
| 24304 | DUK_TVAL_INCREF(thr, tv_dst); |
| 24305 | } |
| 24306 | tv_src++; |
| 24307 | tv_dst++; |
| 24308 | } |
| 24309 | DUK_ASSERT(tv_dst <= thr->valstack_end); |
| 24310 | thr->valstack_top = tv_dst; |
| 24311 | return (duk_idx_t) h_arr->length; |
| 24312 | } |
| 24313 | skip_fast: |
| 24314 | #endif /* DUK_USE_ARRAY_FASTPATH */ |
| 24315 | |
| 24316 | /* Slow path: actual lookups. The initial 'length' lookup |
| 24317 | * decides the output length, regardless of side effects that |
| 24318 | * may resize or change the argArray while we read the |
| 24319 | * indices. |
| 24320 | */ |
| 24321 | idx = duk_normalize_index(thr, idx); |
| 24322 | duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH); |
| 24323 | len = duk_to_uint32(thr, -1); /* ToUint32() coercion required */ |
| 24324 | if (DUK_UNLIKELY(len >= 0x80000000UL)) { |
| 24325 | goto fail_over_2g; |
| 24326 | } |
| 24327 | duk_pop_unsafe(thr); |
| 24328 | DUK_DDD(DUK_DDDPRINT("slow path for %ld elements" , (long) len)); |
| 24329 | |
| 24330 | duk_require_stack(thr, (duk_idx_t) len); |
| 24331 | for (i = 0; i < len; i++) { |
| 24332 | duk_get_prop_index(thr, idx, (duk_uarridx_t) i); |
| 24333 | } |
| 24334 | return (duk_idx_t) len; |
| 24335 | } else if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) { |
| 24336 | return 0; |
| 24337 | } |
| 24338 | |
| 24339 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 24340 | DUK_WO_NORETURN(return 0;); |
| 24341 | |
| 24342 | fail_over_2g: |
| 24343 | DUK_ERROR_RANGE_INVALID_LENGTH(thr); |
| 24344 | DUK_WO_NORETURN(return 0;); |
| 24345 | } |
| 24346 | |
| 24347 | /* |
| 24348 | * Error throwing |
| 24349 | */ |
| 24350 | |
| 24351 | #if defined(DUK_USE_GCC_PRAGMAS) |
| 24352 | #pragma GCC diagnostic push |
| 24353 | #pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn" |
| 24354 | #elif defined(DUK_USE_CLANG_PRAGMAS) |
| 24355 | #pragma clang diagnostic push |
| 24356 | #endif |
| 24357 | |
| 24358 | DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) { |
| 24359 | duk_tval *tv_val; |
| 24360 | |
| 24361 | DUK_ASSERT_API_ENTRY(thr); |
| 24362 | DUK_ASSERT(thr->valstack_bottom >= thr->valstack); |
| 24363 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 24364 | DUK_ASSERT(thr->valstack_end >= thr->valstack_top); |
| 24365 | |
| 24366 | if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) { |
| 24367 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 24368 | DUK_WO_NORETURN(return;); |
| 24369 | } |
| 24370 | |
| 24371 | /* Errors are augmented when they are created, not when they are |
| 24372 | * thrown or re-thrown. The current error handler, however, runs |
| 24373 | * just before an error is thrown. |
| 24374 | */ |
| 24375 | |
| 24376 | /* Sync so that augmentation sees up-to-date activations, NULL |
| 24377 | * thr->ptr_curr_pc so that it's not used if side effects occur |
| 24378 | * in augmentation or longjmp handling. |
| 24379 | */ |
| 24380 | duk_hthread_sync_and_null_currpc(thr); |
| 24381 | |
| 24382 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) |
| 24383 | DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)" , (duk_tval *) duk_get_tval(thr, -1))); |
| 24384 | duk_err_augment_error_throw(thr); |
| 24385 | #endif |
| 24386 | DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)" , (duk_tval *) duk_get_tval(thr, -1))); |
| 24387 | |
| 24388 | tv_val = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 24389 | duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val); |
| 24390 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 24391 | duk_err_check_debugger_integration(thr); |
| 24392 | #endif |
| 24393 | |
| 24394 | /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't |
| 24395 | * need to check that here. If the value is NULL, a fatal error occurs |
| 24396 | * because we can't return. |
| 24397 | */ |
| 24398 | |
| 24399 | duk_err_longjmp(thr); |
| 24400 | DUK_UNREACHABLE(); |
| 24401 | } |
| 24402 | |
| 24403 | DUK_EXTERNAL void duk_fatal_raw(duk_hthread *thr, const char *err_msg) { |
| 24404 | DUK_ASSERT_API_ENTRY(thr); |
| 24405 | DUK_ASSERT(thr != NULL); |
| 24406 | DUK_ASSERT(thr->heap != NULL); |
| 24407 | DUK_ASSERT(thr->heap->fatal_func != NULL); |
| 24408 | |
| 24409 | DUK_D(DUK_DPRINT("fatal error occurred: %s" , err_msg ? err_msg : "NULL" )); |
| 24410 | |
| 24411 | /* fatal_func should be noreturn, but noreturn declarations on function |
| 24412 | * pointers has a very spotty support apparently so it's not currently |
| 24413 | * done. |
| 24414 | */ |
| 24415 | thr->heap->fatal_func(thr->heap->heap_udata, err_msg); |
| 24416 | |
| 24417 | /* If the fatal handler returns, all bets are off. It'd be nice to |
| 24418 | * print something here but since we don't want to depend on stdio, |
| 24419 | * there's no way to do so portably. |
| 24420 | */ |
| 24421 | DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!" )); |
| 24422 | for (;;) { |
| 24423 | /* loop forever, don't return (function marked noreturn) */ |
| 24424 | } |
| 24425 | } |
| 24426 | |
| 24427 | DUK_EXTERNAL void duk_error_va_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) { |
| 24428 | DUK_ASSERT_API_ENTRY(thr); |
| 24429 | |
| 24430 | duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); |
| 24431 | (void) duk_throw(thr); |
| 24432 | DUK_WO_NORETURN(return;); |
| 24433 | } |
| 24434 | |
| 24435 | DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) { |
| 24436 | va_list ap; |
| 24437 | |
| 24438 | DUK_ASSERT_API_ENTRY(thr); |
| 24439 | |
| 24440 | va_start(ap, fmt); |
| 24441 | duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); |
| 24442 | va_end(ap); |
| 24443 | (void) duk_throw(thr); |
| 24444 | DUK_WO_NORETURN(return;); |
| 24445 | } |
| 24446 | |
| 24447 | #if defined(DUK_USE_GCC_PRAGMAS) |
| 24448 | #pragma GCC diagnostic pop |
| 24449 | #elif defined(DUK_USE_CLANG_PRAGMAS) |
| 24450 | #pragma clang diagnostic pop |
| 24451 | #endif |
| 24452 | |
| 24453 | #if !defined(DUK_USE_VARIADIC_MACROS) |
| 24454 | DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap)); |
| 24455 | |
| 24456 | DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap) { |
| 24457 | const char *filename; |
| 24458 | duk_int_t line; |
| 24459 | |
| 24460 | DUK_CTX_ASSERT_VALID(thr); |
| 24461 | |
| 24462 | filename = duk_api_global_filename; |
| 24463 | line = duk_api_global_line; |
| 24464 | duk_api_global_filename = NULL; |
| 24465 | duk_api_global_line = 0; |
| 24466 | |
| 24467 | duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap); |
| 24468 | (void) duk_throw(thr); |
| 24469 | DUK_WO_NORETURN(return;); |
| 24470 | } |
| 24471 | |
| 24472 | #define DUK__ERROR_STASH_SHARED(code) do { \ |
| 24473 | va_list ap; \ |
| 24474 | va_start(ap, fmt); \ |
| 24475 | duk__throw_error_from_stash(thr, (code), fmt, ap); \ |
| 24476 | va_end(ap); \ |
| 24477 | DUK_WO_NORETURN(return 0;); \ |
| 24478 | } while (0) |
| 24479 | |
| 24480 | DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) { |
| 24481 | DUK_ASSERT_API_ENTRY(thr); |
| 24482 | DUK__ERROR_STASH_SHARED(err_code); |
| 24483 | } |
| 24484 | DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_hthread *thr, const char *fmt, ...) { |
| 24485 | DUK_ASSERT_API_ENTRY(thr); |
| 24486 | DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR); |
| 24487 | } |
| 24488 | DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_hthread *thr, const char *fmt, ...) { |
| 24489 | DUK_ASSERT_API_ENTRY(thr); |
| 24490 | DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR); |
| 24491 | } |
| 24492 | DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_hthread *thr, const char *fmt, ...) { |
| 24493 | DUK_ASSERT_API_ENTRY(thr); |
| 24494 | DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR); |
| 24495 | } |
| 24496 | DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_hthread *thr, const char *fmt, ...) { |
| 24497 | DUK_ASSERT_API_ENTRY(thr); |
| 24498 | DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR); |
| 24499 | } |
| 24500 | DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_hthread *thr, const char *fmt, ...) { |
| 24501 | DUK_ASSERT_API_ENTRY(thr); |
| 24502 | DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR); |
| 24503 | } |
| 24504 | DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_hthread *thr, const char *fmt, ...) { |
| 24505 | DUK_ASSERT_API_ENTRY(thr); |
| 24506 | DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR); |
| 24507 | } |
| 24508 | DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_hthread *thr, const char *fmt, ...) { |
| 24509 | DUK_ASSERT_API_ENTRY(thr); |
| 24510 | DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR); |
| 24511 | } |
| 24512 | #endif /* DUK_USE_VARIADIC_MACROS */ |
| 24513 | |
| 24514 | /* |
| 24515 | * Comparison |
| 24516 | */ |
| 24517 | |
| 24518 | DUK_EXTERNAL duk_bool_t duk_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { |
| 24519 | duk_tval *tv1, *tv2; |
| 24520 | |
| 24521 | DUK_ASSERT_API_ENTRY(thr); |
| 24522 | |
| 24523 | tv1 = duk_get_tval(thr, idx1); |
| 24524 | tv2 = duk_get_tval(thr, idx2); |
| 24525 | if ((tv1 == NULL) || (tv2 == NULL)) { |
| 24526 | return 0; |
| 24527 | } |
| 24528 | |
| 24529 | /* Coercion may be needed, the helper handles that by pushing the |
| 24530 | * tagged values to the stack. |
| 24531 | */ |
| 24532 | return duk_js_equals(thr, tv1, tv2); |
| 24533 | } |
| 24534 | |
| 24535 | DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { |
| 24536 | duk_tval *tv1, *tv2; |
| 24537 | |
| 24538 | DUK_ASSERT_API_ENTRY(thr); |
| 24539 | |
| 24540 | tv1 = duk_get_tval(thr, idx1); |
| 24541 | tv2 = duk_get_tval(thr, idx2); |
| 24542 | if ((tv1 == NULL) || (tv2 == NULL)) { |
| 24543 | return 0; |
| 24544 | } |
| 24545 | |
| 24546 | /* No coercions or other side effects, so safe */ |
| 24547 | return duk_js_strict_equals(tv1, tv2); |
| 24548 | } |
| 24549 | |
| 24550 | DUK_EXTERNAL duk_bool_t duk_samevalue(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { |
| 24551 | duk_tval *tv1, *tv2; |
| 24552 | |
| 24553 | DUK_ASSERT_API_ENTRY(thr); |
| 24554 | |
| 24555 | tv1 = duk_get_tval(thr, idx1); |
| 24556 | tv2 = duk_get_tval(thr, idx2); |
| 24557 | if ((tv1 == NULL) || (tv2 == NULL)) { |
| 24558 | return 0; |
| 24559 | } |
| 24560 | |
| 24561 | /* No coercions or other side effects, so safe */ |
| 24562 | return duk_js_samevalue(tv1, tv2); |
| 24563 | } |
| 24564 | |
| 24565 | /* |
| 24566 | * instanceof |
| 24567 | */ |
| 24568 | |
| 24569 | DUK_EXTERNAL duk_bool_t duk_instanceof(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) { |
| 24570 | duk_tval *tv1, *tv2; |
| 24571 | |
| 24572 | DUK_ASSERT_API_ENTRY(thr); |
| 24573 | |
| 24574 | /* Index validation is strict, which differs from duk_equals(). |
| 24575 | * The strict behavior mimics how instanceof itself works, e.g. |
| 24576 | * it is a TypeError if rval is not a -callable- object. It would |
| 24577 | * be somewhat inconsistent if rval would be allowed to be |
| 24578 | * non-existent without a TypeError. |
| 24579 | */ |
| 24580 | tv1 = duk_require_tval(thr, idx1); |
| 24581 | DUK_ASSERT(tv1 != NULL); |
| 24582 | tv2 = duk_require_tval(thr, idx2); |
| 24583 | DUK_ASSERT(tv2 != NULL); |
| 24584 | |
| 24585 | return duk_js_instanceof(thr, tv1, tv2); |
| 24586 | } |
| 24587 | |
| 24588 | /* |
| 24589 | * Lightfunc |
| 24590 | */ |
| 24591 | |
| 24592 | DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) { |
| 24593 | /* Lightfunc name, includes Duktape/C native function pointer, which |
| 24594 | * can often be used to locate the function from a symbol table. |
| 24595 | * The name also includes the 16-bit duk_tval flags field because it |
| 24596 | * includes the magic value. Because a single native function often |
| 24597 | * provides different functionality depending on the magic value, it |
| 24598 | * seems reasonably to include it in the name. |
| 24599 | * |
| 24600 | * On the other hand, a complicated name increases string table |
| 24601 | * pressure in low memory environments (but only when function name |
| 24602 | * is accessed). |
| 24603 | */ |
| 24604 | |
| 24605 | DUK_ASSERT_API_ENTRY(thr); |
| 24606 | |
| 24607 | duk_push_literal(thr, "light_" ); |
| 24608 | duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func)); |
| 24609 | duk_push_sprintf(thr, "_%04x" , (unsigned int) lf_flags); |
| 24610 | duk_concat(thr, 3); |
| 24611 | } |
| 24612 | |
| 24613 | DUK_INTERNAL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv) { |
| 24614 | duk_c_function func; |
| 24615 | duk_small_uint_t lf_flags; |
| 24616 | |
| 24617 | DUK_ASSERT_API_ENTRY(thr); |
| 24618 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); |
| 24619 | |
| 24620 | DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); |
| 24621 | duk_push_lightfunc_name_raw(thr, func, lf_flags); |
| 24622 | } |
| 24623 | |
| 24624 | DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) { |
| 24625 | duk_c_function func; |
| 24626 | duk_small_uint_t lf_flags; |
| 24627 | |
| 24628 | DUK_ASSERT_API_ENTRY(thr); |
| 24629 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv)); |
| 24630 | |
| 24631 | DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */ |
| 24632 | duk_push_literal(thr, "function " ); |
| 24633 | duk_push_lightfunc_name_raw(thr, func, lf_flags); |
| 24634 | duk_push_literal(thr, "() { [lightfunc code] }" ); |
| 24635 | duk_concat(thr, 3); |
| 24636 | } |
| 24637 | |
| 24638 | /* |
| 24639 | * Function pointers |
| 24640 | * |
| 24641 | * Printing function pointers is non-portable, so we do that by hex printing |
| 24642 | * bytes from memory. |
| 24643 | */ |
| 24644 | |
| 24645 | DUK_INTERNAL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz) { |
| 24646 | duk_uint8_t buf[32 * 2]; |
| 24647 | duk_uint8_t *p, *q; |
| 24648 | duk_small_uint_t i; |
| 24649 | duk_small_uint_t t; |
| 24650 | |
| 24651 | DUK_ASSERT_API_ENTRY(thr); |
| 24652 | DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */ |
| 24653 | |
| 24654 | p = buf; |
| 24655 | #if defined(DUK_USE_INTEGER_LE) |
| 24656 | q = ptr + sz; |
| 24657 | #else |
| 24658 | q = ptr; |
| 24659 | #endif |
| 24660 | for (i = 0; i < sz; i++) { |
| 24661 | #if defined(DUK_USE_INTEGER_LE) |
| 24662 | t = *(--q); |
| 24663 | #else |
| 24664 | t = *(q++); |
| 24665 | #endif |
| 24666 | *p++ = duk_lc_digits[t >> 4]; |
| 24667 | *p++ = duk_lc_digits[t & 0x0f]; |
| 24668 | } |
| 24669 | |
| 24670 | duk_push_lstring(thr, (const char *) buf, sz * 2); |
| 24671 | } |
| 24672 | |
| 24673 | /* |
| 24674 | * Push readable string summarizing duk_tval. The operation is side effect |
| 24675 | * free and will only throw from internal errors (e.g. out of memory). |
| 24676 | * This is used by e.g. property access code to summarize a key/base safely, |
| 24677 | * and is not intended to be fast (but small and safe). |
| 24678 | */ |
| 24679 | |
| 24680 | /* String limits for summary strings. */ |
| 24681 | #define DUK__READABLE_SUMMARY_MAXCHARS 96 /* maximum supported by helper */ |
| 24682 | #define DUK__READABLE_STRING_MAXCHARS 32 /* for strings/symbols */ |
| 24683 | #define DUK__READABLE_ERRMSG_MAXCHARS 96 /* for error messages */ |
| 24684 | |
| 24685 | /* String sanitizer which escapes ASCII control characters and a few other |
| 24686 | * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with |
| 24687 | * question marks. No errors are thrown for any input string, except in out |
| 24688 | * of memory situations. |
| 24689 | */ |
| 24690 | DUK_LOCAL void duk__push_hstring_readable_unicode(duk_hthread *thr, duk_hstring *h_input, duk_small_uint_t maxchars) { |
| 24691 | const duk_uint8_t *p, *p_start, *p_end; |
| 24692 | duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_SUMMARY_MAXCHARS + |
| 24693 | 2 /*quotes*/ + 3 /*periods*/]; |
| 24694 | duk_uint8_t *q; |
| 24695 | duk_ucodepoint_t cp; |
| 24696 | duk_small_uint_t nchars; |
| 24697 | |
| 24698 | DUK_CTX_ASSERT_VALID(thr); |
| 24699 | DUK_ASSERT(h_input != NULL); |
| 24700 | DUK_ASSERT(maxchars <= DUK__READABLE_SUMMARY_MAXCHARS); |
| 24701 | |
| 24702 | p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); |
| 24703 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); |
| 24704 | p = p_start; |
| 24705 | q = buf; |
| 24706 | |
| 24707 | nchars = 0; |
| 24708 | *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; |
| 24709 | for (;;) { |
| 24710 | if (p >= p_end) { |
| 24711 | break; |
| 24712 | } |
| 24713 | if (nchars == maxchars) { |
| 24714 | *q++ = (duk_uint8_t) DUK_ASC_PERIOD; |
| 24715 | *q++ = (duk_uint8_t) DUK_ASC_PERIOD; |
| 24716 | *q++ = (duk_uint8_t) DUK_ASC_PERIOD; |
| 24717 | break; |
| 24718 | } |
| 24719 | if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) { |
| 24720 | if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) { |
| 24721 | DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */ |
| 24722 | DUK_ASSERT((cp >> 4) <= 0x0f); |
| 24723 | *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH; |
| 24724 | *q++ = (duk_uint8_t) DUK_ASC_LC_X; |
| 24725 | *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4]; |
| 24726 | *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f]; |
| 24727 | } else { |
| 24728 | q += duk_unicode_encode_xutf8(cp, q); |
| 24729 | } |
| 24730 | } else { |
| 24731 | p++; /* advance manually */ |
| 24732 | *q++ = (duk_uint8_t) DUK_ASC_QUESTION; |
| 24733 | } |
| 24734 | nchars++; |
| 24735 | } |
| 24736 | *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE; |
| 24737 | |
| 24738 | duk_push_lstring(thr, (const char *) buf, (duk_size_t) (q - buf)); |
| 24739 | } |
| 24740 | |
| 24741 | DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval *tv, duk_bool_t error_aware) { |
| 24742 | DUK_CTX_ASSERT_VALID(thr); |
| 24743 | /* 'tv' may be NULL */ |
| 24744 | |
| 24745 | if (tv == NULL) { |
| 24746 | duk_push_literal(thr, "none" ); |
| 24747 | } else { |
| 24748 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 24749 | case DUK_TAG_STRING: { |
| 24750 | duk_hstring *h = DUK_TVAL_GET_STRING(tv); |
| 24751 | if (DUK_HSTRING_HAS_SYMBOL(h)) { |
| 24752 | /* XXX: string summary produces question marks |
| 24753 | * so this is not very ideal. |
| 24754 | */ |
| 24755 | duk_push_literal(thr, "[Symbol " ); |
| 24756 | duk_push_string(thr, duk__get_symbol_type_string(h)); |
| 24757 | duk_push_literal(thr, " " ); |
| 24758 | duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS); |
| 24759 | duk_push_literal(thr, "]" ); |
| 24760 | duk_concat(thr, 5); |
| 24761 | break; |
| 24762 | } |
| 24763 | duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS); |
| 24764 | break; |
| 24765 | } |
| 24766 | case DUK_TAG_OBJECT: { |
| 24767 | duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); |
| 24768 | DUK_ASSERT(h != NULL); |
| 24769 | |
| 24770 | if (error_aware && |
| 24771 | duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) { |
| 24772 | /* Get error message in a side effect free way if |
| 24773 | * possible; if not, summarize as a generic object. |
| 24774 | * Error message currently gets quoted. |
| 24775 | */ |
| 24776 | /* XXX: better internal getprop call; get without side effects |
| 24777 | * but traverse inheritance chain. |
| 24778 | */ |
| 24779 | duk_tval *tv_msg; |
| 24780 | tv_msg = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, h, DUK_STRIDX_MESSAGE); |
| 24781 | if (tv_msg != NULL && DUK_TVAL_IS_STRING(tv_msg)) { |
| 24782 | /* It's critical to avoid recursion so |
| 24783 | * only summarize a string .message. |
| 24784 | */ |
| 24785 | duk__push_hstring_readable_unicode(thr, DUK_TVAL_GET_STRING(tv_msg), DUK__READABLE_ERRMSG_MAXCHARS); |
| 24786 | break; |
| 24787 | } |
| 24788 | } |
| 24789 | duk_push_class_string_tval(thr, tv, 1 /*avoid_side_effects*/); |
| 24790 | break; |
| 24791 | } |
| 24792 | case DUK_TAG_BUFFER: { |
| 24793 | /* While plain buffers mimic Uint8Arrays, they summarize differently. |
| 24794 | * This is useful so that the summarized string accurately reflects the |
| 24795 | * internal type which may matter for figuring out bugs etc. |
| 24796 | */ |
| 24797 | /* XXX: Hex encoded, length limited buffer summary here? */ |
| 24798 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); |
| 24799 | DUK_ASSERT(h != NULL); |
| 24800 | duk_push_sprintf(thr, "[buffer:%ld]" , (long) DUK_HBUFFER_GET_SIZE(h)); |
| 24801 | break; |
| 24802 | } |
| 24803 | case DUK_TAG_POINTER: { |
| 24804 | /* Surround with parentheses like in JX, ensures NULL pointer |
| 24805 | * is distinguishable from null value ("(null)" vs "null"). |
| 24806 | */ |
| 24807 | duk_push_tval(thr, tv); |
| 24808 | duk_push_sprintf(thr, "(%s)" , duk_to_string(thr, -1)); |
| 24809 | duk_remove_m2(thr); |
| 24810 | break; |
| 24811 | } |
| 24812 | default: { |
| 24813 | duk_push_tval(thr, tv); |
| 24814 | break; |
| 24815 | } |
| 24816 | } |
| 24817 | } |
| 24818 | |
| 24819 | return duk_to_string(thr, -1); |
| 24820 | } |
| 24821 | DUK_INTERNAL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv) { |
| 24822 | DUK_ASSERT_API_ENTRY(thr); |
| 24823 | return duk__push_string_tval_readable(thr, tv, 0 /*error_aware*/); |
| 24824 | } |
| 24825 | |
| 24826 | DUK_INTERNAL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx) { |
| 24827 | DUK_ASSERT_API_ENTRY(thr); |
| 24828 | return duk_push_string_tval_readable(thr, duk_get_tval(thr, idx)); |
| 24829 | } |
| 24830 | |
| 24831 | DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv) { |
| 24832 | DUK_ASSERT_API_ENTRY(thr); |
| 24833 | return duk__push_string_tval_readable(thr, tv, 1 /*error_aware*/); |
| 24834 | } |
| 24835 | |
| 24836 | DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h) { |
| 24837 | const duk_uint8_t *p; |
| 24838 | const duk_uint8_t *p_end; |
| 24839 | const duk_uint8_t *q; |
| 24840 | |
| 24841 | DUK_ASSERT_API_ENTRY(thr); |
| 24842 | |
| 24843 | /* .toString() */ |
| 24844 | duk_push_literal(thr, "Symbol(" ); |
| 24845 | p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); |
| 24846 | p_end = p + DUK_HSTRING_GET_BYTELEN(h); |
| 24847 | DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80); |
| 24848 | p++; |
| 24849 | for (q = p; q < p_end; q++) { |
| 24850 | if (*q == 0xffU) { |
| 24851 | /* Terminate either at end-of-string (but NUL MUST |
| 24852 | * be accepted without terminating description) or |
| 24853 | * 0xFF, which is used to mark start of unique trailer |
| 24854 | * (and cannot occur in CESU-8 / extended UTF-8). |
| 24855 | */ |
| 24856 | break; |
| 24857 | } |
| 24858 | } |
| 24859 | duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p)); |
| 24860 | duk_push_literal(thr, ")" ); |
| 24861 | duk_concat(thr, 3); |
| 24862 | } |
| 24863 | |
| 24864 | /* |
| 24865 | * Functions |
| 24866 | */ |
| 24867 | |
| 24868 | #if 0 /* not used yet */ |
| 24869 | DUK_INTERNAL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h) { |
| 24870 | duk_c_function func; |
| 24871 | |
| 24872 | DUK_ASSERT_API_ENTRY(thr); |
| 24873 | DUK_ASSERT(h != NULL); |
| 24874 | DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)); |
| 24875 | |
| 24876 | duk_push_sprintf(thr, "native_" ); |
| 24877 | func = h->func; |
| 24878 | duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func)); |
| 24879 | duk_push_sprintf(thr, "_%04x_%04x" , |
| 24880 | (unsigned int) (duk_uint16_t) h->nargs, |
| 24881 | (unsigned int) (duk_uint16_t) h->magic); |
| 24882 | duk_concat(thr, 3); |
| 24883 | } |
| 24884 | #endif |
| 24885 | |
| 24886 | /* |
| 24887 | * duk_tval slice copy |
| 24888 | */ |
| 24889 | |
| 24890 | DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count) { |
| 24891 | duk_tval *tv; |
| 24892 | |
| 24893 | DUK_ASSERT_API_ENTRY(thr); |
| 24894 | DUK_UNREF(thr); |
| 24895 | DUK_ASSERT(count * sizeof(duk_tval) >= count); /* no wrap */ |
| 24896 | |
| 24897 | duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval)); |
| 24898 | |
| 24899 | tv = tv_dst; |
| 24900 | while (count-- > 0) { |
| 24901 | DUK_TVAL_INCREF(thr, tv); |
| 24902 | tv++; |
| 24903 | } |
| 24904 | } |
| 24905 | |
| 24906 | /* automatic undefs */ |
| 24907 | #undef DUK__ASSERT_SPACE |
| 24908 | #undef DUK__CHECK_SPACE |
| 24909 | #undef DUK__ERROR_STASH_SHARED |
| 24910 | #undef DUK__PACK_ARGS |
| 24911 | #undef DUK__READABLE_ERRMSG_MAXCHARS |
| 24912 | #undef DUK__READABLE_STRING_MAXCHARS |
| 24913 | #undef DUK__READABLE_SUMMARY_MAXCHARS |
| 24914 | #line 1 "duk_api_string.c" |
| 24915 | /* |
| 24916 | * String manipulation |
| 24917 | */ |
| 24918 | |
| 24919 | /* #include duk_internal.h -> already included */ |
| 24920 | |
| 24921 | DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) { |
| 24922 | duk_uint_t count; |
| 24923 | duk_uint_t i; |
| 24924 | duk_size_t idx; |
| 24925 | duk_size_t len; |
| 24926 | duk_hstring *h; |
| 24927 | duk_uint8_t *buf; |
| 24928 | |
| 24929 | DUK_CTX_ASSERT_VALID(thr); |
| 24930 | |
| 24931 | if (DUK_UNLIKELY(count_in <= 0)) { |
| 24932 | if (count_in < 0) { |
| 24933 | DUK_ERROR_RANGE_INVALID_COUNT(thr); |
| 24934 | DUK_WO_NORETURN(return;); |
| 24935 | } |
| 24936 | DUK_ASSERT(count_in == 0); |
| 24937 | duk_push_hstring_empty(thr); |
| 24938 | return; |
| 24939 | } |
| 24940 | count = (duk_uint_t) count_in; |
| 24941 | |
| 24942 | if (is_join) { |
| 24943 | duk_size_t t1, t2, limit; |
| 24944 | h = duk_to_hstring(thr, -((duk_idx_t) count) - 1); |
| 24945 | DUK_ASSERT(h != NULL); |
| 24946 | |
| 24947 | /* A bit tricky overflow test, see doc/code-issues.rst. */ |
| 24948 | t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); |
| 24949 | t2 = (duk_size_t) (count - 1); |
| 24950 | limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN; |
| 24951 | if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) { |
| 24952 | /* Combined size of separators already overflows. */ |
| 24953 | goto error_overflow; |
| 24954 | } |
| 24955 | len = (duk_size_t) (t1 * t2); |
| 24956 | } else { |
| 24957 | len = (duk_size_t) 0; |
| 24958 | } |
| 24959 | |
| 24960 | for (i = count; i >= 1; i--) { |
| 24961 | duk_size_t new_len; |
| 24962 | h = duk_to_hstring(thr, -((duk_idx_t) i)); |
| 24963 | new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); |
| 24964 | |
| 24965 | /* Impose a string maximum length, need to handle overflow |
| 24966 | * correctly. |
| 24967 | */ |
| 24968 | if (new_len < len || /* wrapped */ |
| 24969 | new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) { |
| 24970 | goto error_overflow; |
| 24971 | } |
| 24972 | len = new_len; |
| 24973 | } |
| 24974 | |
| 24975 | DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes" , |
| 24976 | (unsigned long) count, (unsigned long) len)); |
| 24977 | |
| 24978 | /* Use stack allocated buffer to ensure reachability in errors |
| 24979 | * (e.g. intern error). |
| 24980 | */ |
| 24981 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len); |
| 24982 | DUK_ASSERT(buf != NULL); |
| 24983 | |
| 24984 | /* [ ... (sep) str1 str2 ... strN buf ] */ |
| 24985 | |
| 24986 | idx = 0; |
| 24987 | for (i = count; i >= 1; i--) { |
| 24988 | if (is_join && i != count) { |
| 24989 | h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */ |
| 24990 | duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); |
| 24991 | idx += DUK_HSTRING_GET_BYTELEN(h); |
| 24992 | } |
| 24993 | h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */ |
| 24994 | duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); |
| 24995 | idx += DUK_HSTRING_GET_BYTELEN(h); |
| 24996 | } |
| 24997 | |
| 24998 | DUK_ASSERT(idx == len); |
| 24999 | |
| 25000 | /* [ ... (sep) str1 str2 ... strN buf ] */ |
| 25001 | |
| 25002 | /* Get rid of the strings early to minimize memory use before intern. */ |
| 25003 | |
| 25004 | if (is_join) { |
| 25005 | duk_replace(thr, -((duk_idx_t) count) - 2); /* overwrite sep */ |
| 25006 | duk_pop_n(thr, (duk_idx_t) count); |
| 25007 | } else { |
| 25008 | duk_replace(thr, -((duk_idx_t) count) - 1); /* overwrite str1 */ |
| 25009 | duk_pop_n(thr, (duk_idx_t) (count - 1)); |
| 25010 | } |
| 25011 | |
| 25012 | /* [ ... buf ] */ |
| 25013 | |
| 25014 | (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */ |
| 25015 | |
| 25016 | /* [ ... res ] */ |
| 25017 | return; |
| 25018 | |
| 25019 | error_overflow: |
| 25020 | DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); |
| 25021 | DUK_WO_NORETURN(return;); |
| 25022 | } |
| 25023 | |
| 25024 | DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) { |
| 25025 | DUK_ASSERT_API_ENTRY(thr); |
| 25026 | |
| 25027 | duk__concat_and_join_helper(thr, count, 0 /*is_join*/); |
| 25028 | } |
| 25029 | |
| 25030 | #if defined(DUK_USE_PREFER_SIZE) |
| 25031 | DUK_INTERNAL void duk_concat_2(duk_hthread *thr) { |
| 25032 | DUK_ASSERT_API_ENTRY(thr); |
| 25033 | duk_concat(thr, 2); |
| 25034 | } |
| 25035 | #else /* DUK_USE_PREFER_SIZE */ |
| 25036 | DUK_INTERNAL void duk_concat_2(duk_hthread *thr) { |
| 25037 | duk_hstring *h1; |
| 25038 | duk_hstring *h2; |
| 25039 | duk_uint8_t *buf; |
| 25040 | duk_size_t len1; |
| 25041 | duk_size_t len2; |
| 25042 | duk_size_t len; |
| 25043 | |
| 25044 | DUK_ASSERT_API_ENTRY(thr); |
| 25045 | DUK_ASSERT(duk_get_top(thr) >= 2); /* Trusted caller. */ |
| 25046 | |
| 25047 | h1 = duk_to_hstring(thr, -2); |
| 25048 | h2 = duk_to_hstring(thr, -1); |
| 25049 | len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1); |
| 25050 | len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2); |
| 25051 | len = len1 + len2; |
| 25052 | if (DUK_UNLIKELY(len < len1 || /* wrapped */ |
| 25053 | len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) { |
| 25054 | goto error_overflow; |
| 25055 | } |
| 25056 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len); |
| 25057 | DUK_ASSERT(buf != NULL); |
| 25058 | |
| 25059 | duk_memcpy((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1); |
| 25060 | duk_memcpy((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2); |
| 25061 | (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */ |
| 25062 | |
| 25063 | /* [ ... str1 str2 buf ] */ |
| 25064 | |
| 25065 | duk_replace(thr, -3); |
| 25066 | duk_pop_unsafe(thr); |
| 25067 | return; |
| 25068 | |
| 25069 | error_overflow: |
| 25070 | DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG); |
| 25071 | DUK_WO_NORETURN(return;); |
| 25072 | } |
| 25073 | #endif /* DUK_USE_PREFER_SIZE */ |
| 25074 | |
| 25075 | DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) { |
| 25076 | DUK_ASSERT_API_ENTRY(thr); |
| 25077 | |
| 25078 | duk__concat_and_join_helper(thr, count, 1 /*is_join*/); |
| 25079 | } |
| 25080 | |
| 25081 | /* XXX: could map/decode be unified with duk_unicode_support.c code? |
| 25082 | * Case conversion needs also the character surroundings though. |
| 25083 | */ |
| 25084 | |
| 25085 | DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) { |
| 25086 | duk_hstring *h_input; |
| 25087 | const duk_uint8_t *p, *p_start, *p_end; |
| 25088 | duk_codepoint_t cp; |
| 25089 | |
| 25090 | DUK_ASSERT_API_ENTRY(thr); |
| 25091 | |
| 25092 | h_input = duk_require_hstring(thr, idx); /* Accept symbols. */ |
| 25093 | DUK_ASSERT(h_input != NULL); |
| 25094 | |
| 25095 | p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); |
| 25096 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); |
| 25097 | p = p_start; |
| 25098 | |
| 25099 | for (;;) { |
| 25100 | if (p >= p_end) { |
| 25101 | break; |
| 25102 | } |
| 25103 | cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); |
| 25104 | callback(udata, cp); |
| 25105 | } |
| 25106 | } |
| 25107 | |
| 25108 | DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) { |
| 25109 | duk_hstring *h_input; |
| 25110 | duk_bufwriter_ctx bw_alloc; |
| 25111 | duk_bufwriter_ctx *bw; |
| 25112 | const duk_uint8_t *p, *p_start, *p_end; |
| 25113 | duk_codepoint_t cp; |
| 25114 | |
| 25115 | DUK_ASSERT_API_ENTRY(thr); |
| 25116 | |
| 25117 | idx = duk_normalize_index(thr, idx); |
| 25118 | |
| 25119 | h_input = duk_require_hstring(thr, idx); /* Accept symbols. */ |
| 25120 | DUK_ASSERT(h_input != NULL); |
| 25121 | |
| 25122 | bw = &bw_alloc; |
| 25123 | DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */ |
| 25124 | |
| 25125 | p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); |
| 25126 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); |
| 25127 | p = p_start; |
| 25128 | |
| 25129 | for (;;) { |
| 25130 | /* XXX: could write output in chunks with fewer ensure calls, |
| 25131 | * but relative benefit would be small here. |
| 25132 | */ |
| 25133 | |
| 25134 | if (p >= p_end) { |
| 25135 | break; |
| 25136 | } |
| 25137 | cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end); |
| 25138 | cp = callback(udata, cp); |
| 25139 | |
| 25140 | DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp); |
| 25141 | } |
| 25142 | |
| 25143 | DUK_BW_COMPACT(thr, bw); |
| 25144 | (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 encoded. */ |
| 25145 | duk_replace(thr, idx); |
| 25146 | } |
| 25147 | |
| 25148 | DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) { |
| 25149 | duk_hstring *h; |
| 25150 | duk_hstring *res; |
| 25151 | duk_size_t start_byte_offset; |
| 25152 | duk_size_t end_byte_offset; |
| 25153 | duk_size_t charlen; |
| 25154 | |
| 25155 | DUK_ASSERT_API_ENTRY(thr); |
| 25156 | |
| 25157 | idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */ |
| 25158 | h = duk_require_hstring(thr, idx); |
| 25159 | DUK_ASSERT(h != NULL); |
| 25160 | |
| 25161 | charlen = DUK_HSTRING_GET_CHARLEN(h); |
| 25162 | if (end_offset >= charlen) { |
| 25163 | end_offset = charlen; |
| 25164 | } |
| 25165 | if (start_offset > end_offset) { |
| 25166 | start_offset = end_offset; |
| 25167 | } |
| 25168 | |
| 25169 | DUK_ASSERT_DISABLE(start_offset >= 0); |
| 25170 | DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h)); |
| 25171 | DUK_ASSERT_DISABLE(end_offset >= 0); |
| 25172 | DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h)); |
| 25173 | |
| 25174 | /* Guaranteed by string limits. */ |
| 25175 | DUK_ASSERT(start_offset <= DUK_UINT32_MAX); |
| 25176 | DUK_ASSERT(end_offset <= DUK_UINT32_MAX); |
| 25177 | |
| 25178 | start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset); |
| 25179 | end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset); |
| 25180 | |
| 25181 | DUK_ASSERT(end_byte_offset >= start_byte_offset); |
| 25182 | DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */ |
| 25183 | |
| 25184 | /* No size check is necessary. */ |
| 25185 | res = duk_heap_strtable_intern_checked(thr, |
| 25186 | DUK_HSTRING_GET_DATA(h) + start_byte_offset, |
| 25187 | (duk_uint32_t) (end_byte_offset - start_byte_offset)); |
| 25188 | |
| 25189 | duk_push_hstring(thr, res); |
| 25190 | duk_replace(thr, idx); |
| 25191 | } |
| 25192 | |
| 25193 | /* XXX: this is quite clunky. Add Unicode helpers to scan backwards and |
| 25194 | * forwards with a callback to process codepoints? |
| 25195 | */ |
| 25196 | DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) { |
| 25197 | duk_hstring *h; |
| 25198 | const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */ |
| 25199 | const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */ |
| 25200 | duk_codepoint_t cp; |
| 25201 | |
| 25202 | DUK_ASSERT_API_ENTRY(thr); |
| 25203 | |
| 25204 | idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */ |
| 25205 | h = duk_require_hstring(thr, idx); |
| 25206 | DUK_ASSERT(h != NULL); |
| 25207 | |
| 25208 | p_start = DUK_HSTRING_GET_DATA(h); |
| 25209 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h); |
| 25210 | |
| 25211 | p = p_start; |
| 25212 | while (p < p_end) { |
| 25213 | p_tmp1 = p; |
| 25214 | cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end); |
| 25215 | if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) { |
| 25216 | break; |
| 25217 | } |
| 25218 | p = p_tmp1; |
| 25219 | } |
| 25220 | q_start = p; |
| 25221 | if (p == p_end) { |
| 25222 | /* Entire string is whitespace. */ |
| 25223 | q_end = p; |
| 25224 | goto scan_done; |
| 25225 | } |
| 25226 | |
| 25227 | p = p_end; |
| 25228 | while (p > p_start) { |
| 25229 | p_tmp1 = p; |
| 25230 | while (p > p_start) { |
| 25231 | p--; |
| 25232 | if (((*p) & 0xc0) != 0x80) { |
| 25233 | break; |
| 25234 | } |
| 25235 | } |
| 25236 | p_tmp2 = p; |
| 25237 | |
| 25238 | cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end); |
| 25239 | if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) { |
| 25240 | p = p_tmp1; |
| 25241 | break; |
| 25242 | } |
| 25243 | } |
| 25244 | q_end = p; |
| 25245 | |
| 25246 | scan_done: |
| 25247 | /* This may happen when forward and backward scanning disagree |
| 25248 | * (possible for non-extended-UTF-8 strings). |
| 25249 | */ |
| 25250 | if (q_end < q_start) { |
| 25251 | q_end = q_start; |
| 25252 | } |
| 25253 | |
| 25254 | DUK_ASSERT(q_start >= p_start && q_start <= p_end); |
| 25255 | DUK_ASSERT(q_end >= p_start && q_end <= p_end); |
| 25256 | DUK_ASSERT(q_end >= q_start); |
| 25257 | |
| 25258 | DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p" , |
| 25259 | (const void *) p_start, (const void *) p_end, |
| 25260 | (const void *) q_start, (const void *) q_end)); |
| 25261 | |
| 25262 | if (q_start == p_start && q_end == p_end) { |
| 25263 | DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)" )); |
| 25264 | return; |
| 25265 | } |
| 25266 | |
| 25267 | duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start)); |
| 25268 | duk_replace(thr, idx); |
| 25269 | } |
| 25270 | |
| 25271 | DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) { |
| 25272 | duk_hstring *h; |
| 25273 | duk_ucodepoint_t cp; |
| 25274 | |
| 25275 | DUK_ASSERT_API_ENTRY(thr); |
| 25276 | |
| 25277 | /* XXX: Share code with String.prototype.charCodeAt? Main difference |
| 25278 | * is handling of clamped offsets. |
| 25279 | */ |
| 25280 | |
| 25281 | h = duk_require_hstring(thr, idx); /* Accept symbols. */ |
| 25282 | DUK_ASSERT(h != NULL); |
| 25283 | |
| 25284 | DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */ |
| 25285 | if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) { |
| 25286 | return 0; |
| 25287 | } |
| 25288 | |
| 25289 | DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */ |
| 25290 | cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/); |
| 25291 | return (duk_codepoint_t) cp; |
| 25292 | } |
| 25293 | #line 1 "duk_api_time.c" |
| 25294 | /* |
| 25295 | * Date/time. |
| 25296 | */ |
| 25297 | |
| 25298 | /* #include duk_internal.h -> already included */ |
| 25299 | |
| 25300 | DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) { |
| 25301 | /* ECMAScript time, with millisecond fractions. Exposed via |
| 25302 | * duk_get_now() for example. |
| 25303 | */ |
| 25304 | DUK_UNREF(thr); |
| 25305 | return (duk_double_t) DUK_USE_DATE_GET_NOW(thr); |
| 25306 | } |
| 25307 | |
| 25308 | DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) { |
| 25309 | /* ECMAScript time without millisecond fractions. Exposed via |
| 25310 | * the Date built-in which doesn't allow fractions. |
| 25311 | */ |
| 25312 | DUK_UNREF(thr); |
| 25313 | return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr)); |
| 25314 | } |
| 25315 | |
| 25316 | DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) { |
| 25317 | DUK_UNREF(thr); |
| 25318 | #if defined(DUK_USE_GET_MONOTONIC_TIME) |
| 25319 | return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr); |
| 25320 | #else |
| 25321 | return (duk_double_t) DUK_USE_DATE_GET_NOW(thr); |
| 25322 | #endif |
| 25323 | } |
| 25324 | |
| 25325 | DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) { |
| 25326 | DUK_ASSERT_API_ENTRY(thr); |
| 25327 | DUK_UNREF(thr); |
| 25328 | |
| 25329 | /* This API intentionally allows millisecond fractions. */ |
| 25330 | return duk_time_get_ecmascript_time(thr); |
| 25331 | } |
| 25332 | |
| 25333 | #if 0 /* XXX: worth exposing? */ |
| 25334 | DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) { |
| 25335 | DUK_ASSERT_API_ENTRY(thr); |
| 25336 | DUK_UNREF(thr); |
| 25337 | |
| 25338 | return duk_time_get_monotonic_time(thr); |
| 25339 | } |
| 25340 | #endif |
| 25341 | |
| 25342 | DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) { |
| 25343 | duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; |
| 25344 | duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; |
| 25345 | duk_uint_t flags; |
| 25346 | |
| 25347 | DUK_ASSERT_API_ENTRY(thr); |
| 25348 | DUK_ASSERT(comp != NULL); /* XXX: or check? */ |
| 25349 | DUK_UNREF(thr); |
| 25350 | |
| 25351 | /* Convert as one-based, but change month to zero-based to match the |
| 25352 | * ECMAScript Date built-in behavior 1:1. |
| 25353 | */ |
| 25354 | flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO; |
| 25355 | |
| 25356 | duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags); |
| 25357 | |
| 25358 | /* XXX: sub-millisecond accuracy for the API */ |
| 25359 | |
| 25360 | DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0); |
| 25361 | comp->year = dparts[DUK_DATE_IDX_YEAR]; |
| 25362 | comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0; |
| 25363 | comp->day = dparts[DUK_DATE_IDX_DAY]; |
| 25364 | comp->hours = dparts[DUK_DATE_IDX_HOUR]; |
| 25365 | comp->minutes = dparts[DUK_DATE_IDX_MINUTE]; |
| 25366 | comp->seconds = dparts[DUK_DATE_IDX_SECOND]; |
| 25367 | comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND]; |
| 25368 | comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY]; |
| 25369 | } |
| 25370 | |
| 25371 | DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) { |
| 25372 | duk_double_t d; |
| 25373 | duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; |
| 25374 | duk_uint_t flags; |
| 25375 | |
| 25376 | DUK_ASSERT_API_ENTRY(thr); |
| 25377 | DUK_ASSERT(comp != NULL); /* XXX: or check? */ |
| 25378 | DUK_UNREF(thr); |
| 25379 | |
| 25380 | /* Match Date constructor behavior (with UTC time). Month is given |
| 25381 | * as zero-based. Day-of-month is given as one-based so normalize |
| 25382 | * it to zero-based as the internal conversion helpers expects all |
| 25383 | * components to be zero-based. |
| 25384 | */ |
| 25385 | flags = 0; |
| 25386 | |
| 25387 | /* XXX: expensive conversion; use array format in API instead, or unify |
| 25388 | * time provider and time API to use same struct? |
| 25389 | */ |
| 25390 | |
| 25391 | dparts[DUK_DATE_IDX_YEAR] = comp->year; |
| 25392 | dparts[DUK_DATE_IDX_MONTH] = comp->month; |
| 25393 | dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0; |
| 25394 | dparts[DUK_DATE_IDX_HOUR] = comp->hours; |
| 25395 | dparts[DUK_DATE_IDX_MINUTE] = comp->minutes; |
| 25396 | dparts[DUK_DATE_IDX_SECOND] = comp->seconds; |
| 25397 | dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds; |
| 25398 | dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */ |
| 25399 | |
| 25400 | d = duk_bi_date_get_timeval_from_dparts(dparts, flags); |
| 25401 | |
| 25402 | return d; |
| 25403 | } |
| 25404 | #line 1 "duk_bi_array.c" |
| 25405 | /* |
| 25406 | * Array built-ins |
| 25407 | * |
| 25408 | * Most Array built-ins are intentionally generic in ECMAScript, and are |
| 25409 | * intended to work even when the 'this' binding is not an Array instance. |
| 25410 | * This ECMAScript feature is also used by much real world code. For this |
| 25411 | * reason the implementations here don't assume exotic Array behavior or |
| 25412 | * e.g. presence of a .length property. However, some algorithms have a |
| 25413 | * fast path for duk_harray backed actual Array instances, enabled when |
| 25414 | * footprint is not a concern. |
| 25415 | * |
| 25416 | * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and |
| 25417 | * [[Delete]] operations, but it's currently false throughout. Go through |
| 25418 | * all put/delete cases and check throw flag use. Need a new API primitive |
| 25419 | * which allows throws flag to be specified. |
| 25420 | * |
| 25421 | * XXX: array lengths above 2G won't work reliably. There are many places |
| 25422 | * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff], |
| 25423 | * i.e. -33- bits). Although array 'length' cannot be written to be outside |
| 25424 | * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so) |
| 25425 | * some intermediate values may be above 0xffffffff and this may not be always |
| 25426 | * correctly handled now (duk_uint32_t is not enough for all algorithms). |
| 25427 | * For instance, push() can legitimately write entries beyond length 0xffffffff |
| 25428 | * and cause a RangeError only at the end. To do this properly, the current |
| 25429 | * push() implementation tracks the array index using a 'double' instead of a |
| 25430 | * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js. |
| 25431 | * |
| 25432 | * On using "put" vs. "def" prop |
| 25433 | * ============================= |
| 25434 | * |
| 25435 | * Code below must be careful to use the appropriate primitive as it matters |
| 25436 | * for compliance. When using "put" there may be inherited properties in |
| 25437 | * Array.prototype which cause side effects when values are written. When |
| 25438 | * using "define" there are no such side effects, and many test262 test cases |
| 25439 | * check for this (for real world code, such side effects are very rare). |
| 25440 | * Both "put" and "define" are used in the E5.1 specification; as a rule, |
| 25441 | * "put" is used when modifying an existing array (or a non-array 'this' |
| 25442 | * binding) and "define" for setting values into a fresh result array. |
| 25443 | */ |
| 25444 | |
| 25445 | /* #include duk_internal.h -> already included */ |
| 25446 | |
| 25447 | /* Perform an intermediate join when this many elements have been pushed |
| 25448 | * on the value stack. |
| 25449 | */ |
| 25450 | #define DUK__ARRAY_MID_JOIN_LIMIT 4096 |
| 25451 | |
| 25452 | #if defined(DUK_USE_ARRAY_BUILTIN) |
| 25453 | |
| 25454 | /* |
| 25455 | * Shared helpers. |
| 25456 | */ |
| 25457 | |
| 25458 | /* Shared entry code for many Array built-ins: the 'this' binding is pushed |
| 25459 | * on the value stack and object coerced, and the current .length is returned. |
| 25460 | * Note that length is left on stack (it could be popped, but that's not |
| 25461 | * usually necessary because call handling will clean it up automatically). |
| 25462 | */ |
| 25463 | DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_hthread *thr) { |
| 25464 | duk_uint32_t len; |
| 25465 | |
| 25466 | /* XXX: push more directly? */ |
| 25467 | (void) duk_push_this_coercible_to_object(thr); |
| 25468 | DUK_HOBJECT_ASSERT_VALID(duk_get_hobject(thr, -1)); |
| 25469 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_LENGTH); |
| 25470 | len = duk_to_uint32(thr, -1); |
| 25471 | |
| 25472 | /* -> [ ... ToObject(this) ToUint32(length) ] */ |
| 25473 | return len; |
| 25474 | } |
| 25475 | |
| 25476 | DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) { |
| 25477 | /* Range limited to [0, 0x7fffffff] range, i.e. range that can be |
| 25478 | * represented with duk_int32_t. Use this when the method doesn't |
| 25479 | * handle the full 32-bit unsigned range correctly. |
| 25480 | */ |
| 25481 | duk_uint32_t ret = duk__push_this_obj_len_u32(thr); |
| 25482 | if (DUK_UNLIKELY(ret >= 0x80000000UL)) { |
| 25483 | DUK_ERROR_RANGE_INVALID_LENGTH(thr); |
| 25484 | DUK_WO_NORETURN(return 0U;); |
| 25485 | } |
| 25486 | return ret; |
| 25487 | } |
| 25488 | |
| 25489 | #if defined(DUK_USE_ARRAY_FASTPATH) |
| 25490 | /* Check if 'this' binding is an Array instance (duk_harray) which satisfies |
| 25491 | * a few other guarantees for fast path operation. The fast path doesn't |
| 25492 | * need to handle all operations, even for duk_harrays, but must handle a |
| 25493 | * significant fraction to improve performance. Return a non-NULL duk_harray |
| 25494 | * pointer when all fast path criteria are met, NULL otherwise. |
| 25495 | */ |
| 25496 | DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_hthread *thr) { |
| 25497 | duk_tval *tv; |
| 25498 | duk_hobject *h; |
| 25499 | duk_uint_t flags_mask, flags_bits, flags_value; |
| 25500 | |
| 25501 | DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */ |
| 25502 | tv = DUK_GET_THIS_TVAL_PTR(thr); |
| 25503 | |
| 25504 | /* Fast path requires that 'this' is a duk_harray. Read only arrays |
| 25505 | * (ROM backed) are also rejected for simplicity. |
| 25506 | */ |
| 25507 | if (!DUK_TVAL_IS_OBJECT(tv)) { |
| 25508 | DUK_DD(DUK_DDPRINT("reject array fast path: not an object" )); |
| 25509 | return NULL; |
| 25510 | } |
| 25511 | h = DUK_TVAL_GET_OBJECT(tv); |
| 25512 | DUK_ASSERT(h != NULL); |
| 25513 | flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \ |
| 25514 | DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \ |
| 25515 | DUK_HEAPHDR_FLAG_READONLY; |
| 25516 | flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \ |
| 25517 | DUK_HOBJECT_FLAG_EXOTIC_ARRAY; |
| 25518 | flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h); |
| 25519 | if ((flags_value & flags_mask) != flags_bits) { |
| 25520 | DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed" )); |
| 25521 | return NULL; |
| 25522 | } |
| 25523 | |
| 25524 | /* In some cases a duk_harray's 'length' may be larger than the |
| 25525 | * current array part allocation. Avoid the fast path in these |
| 25526 | * cases, so that all fast path code can safely assume that all |
| 25527 | * items in the range [0,length[ are backed by the current array |
| 25528 | * part allocation. |
| 25529 | */ |
| 25530 | if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) { |
| 25531 | DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size" )); |
| 25532 | return NULL; |
| 25533 | } |
| 25534 | |
| 25535 | /* Guarantees for fast path. */ |
| 25536 | DUK_ASSERT(h != NULL); |
| 25537 | DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL); |
| 25538 | DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h)); |
| 25539 | |
| 25540 | DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O" , (duk_heaphdr *) h)); |
| 25541 | return (duk_harray *) h; |
| 25542 | } |
| 25543 | #endif /* DUK_USE_ARRAY_FASTPATH */ |
| 25544 | |
| 25545 | /* |
| 25546 | * Constructor |
| 25547 | */ |
| 25548 | |
| 25549 | DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_hthread *thr) { |
| 25550 | duk_idx_t nargs; |
| 25551 | duk_harray *a; |
| 25552 | duk_double_t d; |
| 25553 | duk_uint32_t len; |
| 25554 | duk_uint32_t len_prealloc; |
| 25555 | |
| 25556 | nargs = duk_get_top(thr); |
| 25557 | |
| 25558 | if (nargs == 1 && duk_is_number(thr, 0)) { |
| 25559 | /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */ |
| 25560 | d = duk_get_number(thr, 0); |
| 25561 | len = duk_to_uint32(thr, 0); |
| 25562 | if (!duk_double_equals((duk_double_t) len, d)) { |
| 25563 | DUK_DCERROR_RANGE_INVALID_LENGTH(thr); |
| 25564 | } |
| 25565 | |
| 25566 | /* For small lengths create a dense preallocated array. |
| 25567 | * For large arrays preallocate an initial part. |
| 25568 | */ |
| 25569 | len_prealloc = len < 64 ? len : 64; |
| 25570 | a = duk_push_harray_with_size(thr, len_prealloc); |
| 25571 | DUK_ASSERT(a != NULL); |
| 25572 | DUK_ASSERT(!duk_is_bare_object(thr, -1)); |
| 25573 | a->length = len; |
| 25574 | return 1; |
| 25575 | } |
| 25576 | |
| 25577 | duk_pack(thr, nargs); |
| 25578 | return 1; |
| 25579 | } |
| 25580 | |
| 25581 | /* |
| 25582 | * isArray() |
| 25583 | */ |
| 25584 | |
| 25585 | DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_hthread *thr) { |
| 25586 | DUK_ASSERT_TOP(thr, 1); |
| 25587 | duk_push_boolean(thr, duk_js_isarray(DUK_GET_TVAL_POSIDX(thr, 0))); |
| 25588 | return 1; |
| 25589 | } |
| 25590 | |
| 25591 | /* |
| 25592 | * toString() |
| 25593 | */ |
| 25594 | |
| 25595 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) { |
| 25596 | (void) duk_push_this_coercible_to_object(thr); |
| 25597 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_JOIN); |
| 25598 | |
| 25599 | /* [ ... this func ] */ |
| 25600 | if (!duk_is_callable(thr, -1)) { |
| 25601 | /* Fall back to the initial (original) Object.toString(). We don't |
| 25602 | * currently have pointers to the built-in functions, only the top |
| 25603 | * level global objects (like "Array") so this is now done in a bit |
| 25604 | * of a hacky manner. It would be cleaner to push the (original) |
| 25605 | * function and use duk_call_method(). |
| 25606 | */ |
| 25607 | |
| 25608 | /* XXX: 'this' will be ToObject() coerced twice, which is incorrect |
| 25609 | * but should have no visible side effects. |
| 25610 | */ |
| 25611 | DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString" )); |
| 25612 | duk_set_top(thr, 0); |
| 25613 | return duk_bi_object_prototype_to_string(thr); /* has access to 'this' binding */ |
| 25614 | } |
| 25615 | |
| 25616 | /* [ ... this func ] */ |
| 25617 | |
| 25618 | duk_insert(thr, -2); |
| 25619 | |
| 25620 | /* [ ... func this ] */ |
| 25621 | |
| 25622 | DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT" , |
| 25623 | (duk_tval *) duk_get_tval(thr, -2), |
| 25624 | (duk_tval *) duk_get_tval(thr, -1))); |
| 25625 | duk_call_method(thr, 0); |
| 25626 | |
| 25627 | return 1; |
| 25628 | } |
| 25629 | |
| 25630 | /* |
| 25631 | * concat() |
| 25632 | */ |
| 25633 | |
| 25634 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) { |
| 25635 | duk_idx_t i, n; |
| 25636 | duk_uint32_t j, idx, len; |
| 25637 | duk_hobject *h; |
| 25638 | duk_size_t tmp_len; |
| 25639 | |
| 25640 | /* XXX: In ES2015 Array .length can be up to 2^53-1. The current |
| 25641 | * implementation is limited to 2^32-1. |
| 25642 | */ |
| 25643 | |
| 25644 | /* XXX: Fast path for array 'this' and array element. */ |
| 25645 | |
| 25646 | /* XXX: The insert here is a bit expensive if there are a lot of items. |
| 25647 | * It could also be special cased in the outermost for loop quite easily |
| 25648 | * (as the element is dup()'d anyway). |
| 25649 | */ |
| 25650 | |
| 25651 | (void) duk_push_this_coercible_to_object(thr); |
| 25652 | duk_insert(thr, 0); |
| 25653 | n = duk_get_top(thr); |
| 25654 | duk_push_array(thr); /* -> [ ToObject(this) item1 ... itemN arr ] */ |
| 25655 | |
| 25656 | /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index() |
| 25657 | * (which differs from the official algorithm). If no error is thrown, this |
| 25658 | * doesn't matter as the length is updated at the end. However, if an error |
| 25659 | * is thrown, the length will be unset. That shouldn't matter because the |
| 25660 | * caller won't get a reference to the intermediate value. |
| 25661 | */ |
| 25662 | |
| 25663 | idx = 0; |
| 25664 | for (i = 0; i < n; i++) { |
| 25665 | duk_bool_t spreadable; |
| 25666 | duk_bool_t need_has_check; |
| 25667 | |
| 25668 | DUK_ASSERT_TOP(thr, n + 1); |
| 25669 | |
| 25670 | /* [ ToObject(this) item1 ... itemN arr ] */ |
| 25671 | |
| 25672 | h = duk_get_hobject(thr, i); |
| 25673 | |
| 25674 | if (h == NULL) { |
| 25675 | spreadable = 0; |
| 25676 | } else { |
| 25677 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 25678 | duk_get_prop_stridx(thr, i, DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE); |
| 25679 | if (duk_is_undefined(thr, -1)) { |
| 25680 | spreadable = duk_js_isarray_hobject(h); |
| 25681 | } else { |
| 25682 | spreadable = duk_to_boolean(thr, -1); |
| 25683 | } |
| 25684 | duk_pop_nodecref_unsafe(thr); |
| 25685 | #else |
| 25686 | spreadable = duk_js_isarray_hobject(h); |
| 25687 | #endif |
| 25688 | } |
| 25689 | |
| 25690 | if (!spreadable) { |
| 25691 | duk_dup(thr, i); |
| 25692 | duk_xdef_prop_index_wec(thr, -2, idx); |
| 25693 | idx++; |
| 25694 | if (DUK_UNLIKELY(idx == 0U)) { |
| 25695 | /* Index after update is 0, and index written |
| 25696 | * was 0xffffffffUL which is no longer a valid |
| 25697 | * array index. |
| 25698 | */ |
| 25699 | goto fail_wrap; |
| 25700 | } |
| 25701 | continue; |
| 25702 | } |
| 25703 | |
| 25704 | DUK_ASSERT(duk_is_object(thr, i)); |
| 25705 | need_has_check = (DUK_HOBJECT_IS_PROXY(h) != 0); /* Always 0 w/o Proxy support. */ |
| 25706 | |
| 25707 | /* [ ToObject(this) item1 ... itemN arr ] */ |
| 25708 | |
| 25709 | tmp_len = duk_get_length(thr, i); |
| 25710 | len = (duk_uint32_t) tmp_len; |
| 25711 | if (DUK_UNLIKELY(tmp_len != (duk_size_t) len)) { |
| 25712 | goto fail_wrap; |
| 25713 | } |
| 25714 | if (DUK_UNLIKELY(idx + len < idx)) { |
| 25715 | /* Result length must be at most 0xffffffffUL to be |
| 25716 | * a valid 32-bit array index. |
| 25717 | */ |
| 25718 | goto fail_wrap; |
| 25719 | } |
| 25720 | for (j = 0; j < len; j++) { |
| 25721 | /* For a Proxy element, an explicit 'has' check is |
| 25722 | * needed to allow the Proxy to present gaps. |
| 25723 | */ |
| 25724 | if (need_has_check) { |
| 25725 | if (duk_has_prop_index(thr, i, j)) { |
| 25726 | duk_get_prop_index(thr, i, j); |
| 25727 | duk_xdef_prop_index_wec(thr, -2, idx); |
| 25728 | } |
| 25729 | } else { |
| 25730 | if (duk_get_prop_index(thr, i, j)) { |
| 25731 | duk_xdef_prop_index_wec(thr, -2, idx); |
| 25732 | } else { |
| 25733 | duk_pop_undefined(thr); |
| 25734 | } |
| 25735 | } |
| 25736 | idx++; |
| 25737 | DUK_ASSERT(idx != 0U); /* Wrap check above. */ |
| 25738 | } |
| 25739 | } |
| 25740 | |
| 25741 | /* ES5.1 has a specification "bug" in that nonexistent trailing |
| 25742 | * elements don't affect the result .length. Test262 and other |
| 25743 | * engines disagree, and the specification bug was fixed in ES2015 |
| 25744 | * (see NOTE 1 in https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat). |
| 25745 | */ |
| 25746 | duk_push_uarridx(thr, idx); |
| 25747 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); |
| 25748 | |
| 25749 | DUK_ASSERT_TOP(thr, n + 1); |
| 25750 | return 1; |
| 25751 | |
| 25752 | fail_wrap: |
| 25753 | DUK_ERROR_RANGE_INVALID_LENGTH(thr); |
| 25754 | DUK_WO_NORETURN(return 0;); |
| 25755 | } |
| 25756 | |
| 25757 | /* |
| 25758 | * join(), toLocaleString() |
| 25759 | * |
| 25760 | * Note: checking valstack is necessary, but only in the per-element loop. |
| 25761 | * |
| 25762 | * Note: the trivial approach of pushing all the elements on the value stack |
| 25763 | * and then calling duk_join() fails when the array contains a large number |
| 25764 | * of elements. This problem can't be offloaded to duk_join() because the |
| 25765 | * elements to join must be handled here and have special handling. Current |
| 25766 | * approach is to do intermediate joins with very large number of elements. |
| 25767 | * There is no fancy handling; the prefix gets re-joined multiple times. |
| 25768 | */ |
| 25769 | |
| 25770 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_hthread *thr) { |
| 25771 | duk_uint32_t len, count; |
| 25772 | duk_uint32_t idx; |
| 25773 | duk_small_int_t to_locale_string = duk_get_current_magic(thr); |
| 25774 | duk_idx_t valstack_required; |
| 25775 | |
| 25776 | /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and |
| 25777 | * setting the top essentially pushes an undefined to the stack, |
| 25778 | * thus defaulting to a comma separator. |
| 25779 | */ |
| 25780 | duk_set_top(thr, 1); |
| 25781 | if (duk_is_undefined(thr, 0)) { |
| 25782 | duk_pop_undefined(thr); |
| 25783 | duk_push_hstring_stridx(thr, DUK_STRIDX_COMMA); |
| 25784 | } else { |
| 25785 | duk_to_string(thr, 0); |
| 25786 | } |
| 25787 | |
| 25788 | len = duk__push_this_obj_len_u32(thr); |
| 25789 | |
| 25790 | /* [ sep ToObject(this) len ] */ |
| 25791 | |
| 25792 | DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu" , |
| 25793 | (duk_tval *) duk_get_tval(thr, 0), |
| 25794 | (duk_tval *) duk_get_tval(thr, 1), |
| 25795 | (unsigned long) len)); |
| 25796 | |
| 25797 | /* The extra (+4) is tight. */ |
| 25798 | valstack_required = (duk_idx_t) ((len >= DUK__ARRAY_MID_JOIN_LIMIT ? |
| 25799 | DUK__ARRAY_MID_JOIN_LIMIT : len) + 4); |
| 25800 | duk_require_stack(thr, valstack_required); |
| 25801 | |
| 25802 | duk_dup_0(thr); |
| 25803 | |
| 25804 | /* [ sep ToObject(this) len sep ] */ |
| 25805 | |
| 25806 | count = 0; |
| 25807 | idx = 0; |
| 25808 | for (;;) { |
| 25809 | DUK_DDD(DUK_DDDPRINT("join idx=%ld" , (long) idx)); |
| 25810 | if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */ |
| 25811 | idx >= len) { /* end of loop (careful with len==0) */ |
| 25812 | /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */ |
| 25813 | DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld" , |
| 25814 | (long) count, (long) idx, (long) len)); |
| 25815 | duk_join(thr, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */ |
| 25816 | duk_dup_0(thr); /* -> [ sep ToObject(this) len str sep ] */ |
| 25817 | duk_insert(thr, -2); /* -> [ sep ToObject(this) len sep str ] */ |
| 25818 | count = 1; |
| 25819 | } |
| 25820 | if (idx >= len) { |
| 25821 | /* if true, the stack already contains the final result */ |
| 25822 | break; |
| 25823 | } |
| 25824 | |
| 25825 | duk_get_prop_index(thr, 1, (duk_uarridx_t) idx); |
| 25826 | if (duk_is_null_or_undefined(thr, -1)) { |
| 25827 | duk_pop_nodecref_unsafe(thr); |
| 25828 | duk_push_hstring_empty(thr); |
| 25829 | } else { |
| 25830 | if (to_locale_string) { |
| 25831 | duk_to_object(thr, -1); |
| 25832 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_LOCALE_STRING); |
| 25833 | duk_insert(thr, -2); /* -> [ ... toLocaleString ToObject(val) ] */ |
| 25834 | duk_call_method(thr, 0); |
| 25835 | } |
| 25836 | duk_to_string(thr, -1); |
| 25837 | } |
| 25838 | |
| 25839 | count++; |
| 25840 | idx++; |
| 25841 | } |
| 25842 | |
| 25843 | /* [ sep ToObject(this) len sep result ] */ |
| 25844 | |
| 25845 | return 1; |
| 25846 | } |
| 25847 | |
| 25848 | /* |
| 25849 | * pop(), push() |
| 25850 | */ |
| 25851 | |
| 25852 | #if defined(DUK_USE_ARRAY_FASTPATH) |
| 25853 | DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_hthread *thr, duk_harray *h_arr) { |
| 25854 | duk_tval *tv_arraypart; |
| 25855 | duk_tval *tv_val; |
| 25856 | duk_uint32_t len; |
| 25857 | |
| 25858 | tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr); |
| 25859 | len = h_arr->length; |
| 25860 | if (len <= 0) { |
| 25861 | /* nop, return undefined */ |
| 25862 | return 0; |
| 25863 | } |
| 25864 | |
| 25865 | len--; |
| 25866 | h_arr->length = len; |
| 25867 | |
| 25868 | /* Fast path doesn't check for an index property inherited from |
| 25869 | * Array.prototype. This is quite often acceptable; if not, |
| 25870 | * disable fast path. |
| 25871 | */ |
| 25872 | DUK_ASSERT_VS_SPACE(thr); |
| 25873 | tv_val = tv_arraypart + len; |
| 25874 | if (DUK_TVAL_IS_UNUSED(tv_val)) { |
| 25875 | /* No net refcount change. Value stack already has |
| 25876 | * 'undefined' based on value stack init policy. |
| 25877 | */ |
| 25878 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); |
| 25879 | DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val)); |
| 25880 | } else { |
| 25881 | /* No net refcount change. */ |
| 25882 | DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val); |
| 25883 | DUK_TVAL_SET_UNUSED(tv_val); |
| 25884 | } |
| 25885 | thr->valstack_top++; |
| 25886 | |
| 25887 | /* XXX: there's no shrink check in the fast path now */ |
| 25888 | |
| 25889 | return 1; |
| 25890 | } |
| 25891 | #endif /* DUK_USE_ARRAY_FASTPATH */ |
| 25892 | |
| 25893 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_hthread *thr) { |
| 25894 | duk_uint32_t len; |
| 25895 | duk_uint32_t idx; |
| 25896 | #if defined(DUK_USE_ARRAY_FASTPATH) |
| 25897 | duk_harray *h_arr; |
| 25898 | #endif |
| 25899 | |
| 25900 | DUK_ASSERT_TOP(thr, 0); |
| 25901 | |
| 25902 | #if defined(DUK_USE_ARRAY_FASTPATH) |
| 25903 | h_arr = duk__arraypart_fastpath_this(thr); |
| 25904 | if (h_arr) { |
| 25905 | return duk__array_pop_fastpath(thr, h_arr); |
| 25906 | } |
| 25907 | #endif |
| 25908 | |
| 25909 | /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */ |
| 25910 | |
| 25911 | len = duk__push_this_obj_len_u32(thr); |
| 25912 | if (len == 0) { |
| 25913 | duk_push_int(thr, 0); |
| 25914 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); |
| 25915 | return 0; |
| 25916 | } |
| 25917 | idx = len - 1; |
| 25918 | |
| 25919 | duk_get_prop_index(thr, 0, (duk_uarridx_t) idx); |
| 25920 | duk_del_prop_index(thr, 0, (duk_uarridx_t) idx); |
| 25921 | duk_push_u32(thr, idx); |
| 25922 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); |
| 25923 | return 1; |
| 25924 | } |
| 25925 | |
| 25926 | #if defined(DUK_USE_ARRAY_FASTPATH) |
| 25927 | DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_hthread *thr, duk_harray *h_arr) { |
| 25928 | duk_tval *tv_arraypart; |
| 25929 | duk_tval *tv_src; |
| 25930 | duk_tval *tv_dst; |
| 25931 | duk_uint32_t len; |
| 25932 | duk_idx_t i, n; |
| 25933 | |
| 25934 | len = h_arr->length; |
| 25935 | tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr); |
| 25936 | |
| 25937 | n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom); |
| 25938 | DUK_ASSERT(n >= 0); |
| 25939 | DUK_ASSERT((duk_uint32_t) n <= DUK_UINT32_MAX); |
| 25940 | if (DUK_UNLIKELY(len + (duk_uint32_t) n < len)) { |
| 25941 | DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw" )); |
| 25942 | DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */ |
| 25943 | } |
| 25944 | if (len + (duk_uint32_t) n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) { |
| 25945 | /* Array part would need to be extended. Rely on slow path |
| 25946 | * for now. |
| 25947 | * |
| 25948 | * XXX: Rework hobject code a bit and add extend support. |
| 25949 | */ |
| 25950 | return 0; |
| 25951 | } |
| 25952 | |
| 25953 | tv_src = thr->valstack_bottom; |
| 25954 | tv_dst = tv_arraypart + len; |
| 25955 | for (i = 0; i < n; i++) { |
| 25956 | /* No net refcount change; reset value stack values to |
| 25957 | * undefined to satisfy value stack init policy. |
| 25958 | */ |
| 25959 | DUK_TVAL_SET_TVAL(tv_dst, tv_src); |
| 25960 | DUK_TVAL_SET_UNDEFINED(tv_src); |
| 25961 | tv_src++; |
| 25962 | tv_dst++; |
| 25963 | } |
| 25964 | thr->valstack_top = thr->valstack_bottom; |
| 25965 | len += (duk_uint32_t) n; |
| 25966 | h_arr->length = len; |
| 25967 | |
| 25968 | DUK_ASSERT((duk_uint_t) len == len); |
| 25969 | duk_push_uint(thr, (duk_uint_t) len); |
| 25970 | return 1; |
| 25971 | } |
| 25972 | #endif /* DUK_USE_ARRAY_FASTPATH */ |
| 25973 | |
| 25974 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_hthread *thr) { |
| 25975 | /* Note: 'this' is not necessarily an Array object. The push() |
| 25976 | * algorithm is supposed to work for other kinds of objects too, |
| 25977 | * so the algorithm has e.g. an explicit update for the 'length' |
| 25978 | * property which is normally "magical" in arrays. |
| 25979 | */ |
| 25980 | |
| 25981 | duk_uint32_t len; |
| 25982 | duk_idx_t i, n; |
| 25983 | #if defined(DUK_USE_ARRAY_FASTPATH) |
| 25984 | duk_harray *h_arr; |
| 25985 | #endif |
| 25986 | |
| 25987 | #if defined(DUK_USE_ARRAY_FASTPATH) |
| 25988 | h_arr = duk__arraypart_fastpath_this(thr); |
| 25989 | if (h_arr) { |
| 25990 | duk_ret_t rc; |
| 25991 | rc = duk__array_push_fastpath(thr, h_arr); |
| 25992 | if (rc != 0) { |
| 25993 | return rc; |
| 25994 | } |
| 25995 | DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case" )); |
| 25996 | } |
| 25997 | #endif |
| 25998 | |
| 25999 | n = duk_get_top(thr); |
| 26000 | len = duk__push_this_obj_len_u32(thr); |
| 26001 | |
| 26002 | /* [ arg1 ... argN obj length ] */ |
| 26003 | |
| 26004 | /* Technically Array.prototype.push() can create an Array with length |
| 26005 | * longer than 2^32-1, i.e. outside the 32-bit range. The final length |
| 26006 | * is *not* wrapped to 32 bits in the specification. |
| 26007 | * |
| 26008 | * This implementation tracks length with a uint32 because it's much |
| 26009 | * more practical. |
| 26010 | * |
| 26011 | * See: test-bi-array-push-maxlen.js. |
| 26012 | */ |
| 26013 | |
| 26014 | if (len + (duk_uint32_t) n < len) { |
| 26015 | DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw" )); |
| 26016 | DUK_DCERROR_RANGE_INVALID_LENGTH(thr); |
| 26017 | } |
| 26018 | |
| 26019 | for (i = 0; i < n; i++) { |
| 26020 | duk_dup(thr, i); |
| 26021 | duk_put_prop_index(thr, -3, (duk_uarridx_t) (len + (duk_uint32_t) i)); |
| 26022 | } |
| 26023 | len += (duk_uint32_t) n; |
| 26024 | |
| 26025 | duk_push_u32(thr, len); |
| 26026 | duk_dup_top(thr); |
| 26027 | duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH); |
| 26028 | |
| 26029 | /* [ arg1 ... argN obj length new_length ] */ |
| 26030 | return 1; |
| 26031 | } |
| 26032 | |
| 26033 | /* |
| 26034 | * sort() |
| 26035 | * |
| 26036 | * Currently qsort with random pivot. This is now really, really slow, |
| 26037 | * because there is no fast path for array parts. |
| 26038 | * |
| 26039 | * Signed indices are used because qsort() leaves and degenerate cases |
| 26040 | * may use a negative offset. |
| 26041 | */ |
| 26042 | |
| 26043 | DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_hthread *thr, duk_int_t idx1, duk_int_t idx2) { |
| 26044 | duk_bool_t have1, have2; |
| 26045 | duk_bool_t undef1, undef2; |
| 26046 | duk_small_int_t ret; |
| 26047 | duk_idx_t idx_obj = 1; /* fixed offsets in valstack */ |
| 26048 | duk_idx_t idx_fn = 0; |
| 26049 | duk_hstring *h1, *h2; |
| 26050 | |
| 26051 | /* Fast exit if indices are identical. This is valid for a non-existent property, |
| 26052 | * for an undefined value, and almost always for ToString() coerced comparison of |
| 26053 | * arbitrary values (corner cases where this is not the case include e.g. a an |
| 26054 | * object with varying ToString() coercion). |
| 26055 | * |
| 26056 | * The specification does not prohibit "caching" of values read from the array, so |
| 26057 | * assuming equality for comparing an index with itself falls into the category of |
| 26058 | * "caching". |
| 26059 | * |
| 26060 | * Also, compareFn may be inconsistent, so skipping a call to compareFn here may |
| 26061 | * have an effect on the final result. The specification does not require any |
| 26062 | * specific behavior for inconsistent compare functions, so again, this fast path |
| 26063 | * is OK. |
| 26064 | */ |
| 26065 | |
| 26066 | if (idx1 == idx2) { |
| 26067 | DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit" , |
| 26068 | (long) idx1, (long) idx2)); |
| 26069 | return 0; |
| 26070 | } |
| 26071 | |
| 26072 | have1 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx1); |
| 26073 | have2 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx2); |
| 26074 | |
| 26075 | DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T" , |
| 26076 | (long) idx1, (long) idx2, (long) have1, (long) have2, |
| 26077 | (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); |
| 26078 | |
| 26079 | if (have1) { |
| 26080 | if (have2) { |
| 26081 | ; |
| 26082 | } else { |
| 26083 | ret = -1; |
| 26084 | goto pop_ret; |
| 26085 | } |
| 26086 | } else { |
| 26087 | if (have2) { |
| 26088 | ret = 1; |
| 26089 | goto pop_ret; |
| 26090 | } else { |
| 26091 | ret = 0; |
| 26092 | goto pop_ret; |
| 26093 | } |
| 26094 | } |
| 26095 | |
| 26096 | undef1 = duk_is_undefined(thr, -2); |
| 26097 | undef2 = duk_is_undefined(thr, -1); |
| 26098 | if (undef1) { |
| 26099 | if (undef2) { |
| 26100 | ret = 0; |
| 26101 | goto pop_ret; |
| 26102 | } else { |
| 26103 | ret = 1; |
| 26104 | goto pop_ret; |
| 26105 | } |
| 26106 | } else { |
| 26107 | if (undef2) { |
| 26108 | ret = -1; |
| 26109 | goto pop_ret; |
| 26110 | } else { |
| 26111 | ; |
| 26112 | } |
| 26113 | } |
| 26114 | |
| 26115 | if (!duk_is_undefined(thr, idx_fn)) { |
| 26116 | duk_double_t d; |
| 26117 | |
| 26118 | /* No need to check callable; duk_call() will do that. */ |
| 26119 | duk_dup(thr, idx_fn); /* -> [ ... x y fn ] */ |
| 26120 | duk_insert(thr, -3); /* -> [ ... fn x y ] */ |
| 26121 | duk_call(thr, 2); /* -> [ ... res ] */ |
| 26122 | |
| 26123 | /* ES5 is a bit vague about what to do if the return value is |
| 26124 | * not a number. ES2015 provides a concrete description: |
| 26125 | * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare. |
| 26126 | */ |
| 26127 | |
| 26128 | d = duk_to_number_m1(thr); |
| 26129 | if (d < 0.0) { |
| 26130 | ret = -1; |
| 26131 | } else if (d > 0.0) { |
| 26132 | ret = 1; |
| 26133 | } else { |
| 26134 | /* Because NaN compares to false, NaN is handled here |
| 26135 | * without an explicit check above. |
| 26136 | */ |
| 26137 | ret = 0; |
| 26138 | } |
| 26139 | |
| 26140 | duk_pop_nodecref_unsafe(thr); |
| 26141 | DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)" , (long) ret)); |
| 26142 | return ret; |
| 26143 | } |
| 26144 | |
| 26145 | /* string compare is the default (a bit oddly) */ |
| 26146 | |
| 26147 | /* XXX: any special handling for plain array; causes repeated coercion now? */ |
| 26148 | h1 = duk_to_hstring(thr, -2); |
| 26149 | h2 = duk_to_hstring_m1(thr); |
| 26150 | DUK_ASSERT(h1 != NULL); |
| 26151 | DUK_ASSERT(h2 != NULL); |
| 26152 | |
| 26153 | ret = duk_js_string_compare(h1, h2); /* retval is directly usable */ |
| 26154 | goto pop_ret; |
| 26155 | |
| 26156 | pop_ret: |
| 26157 | duk_pop_2_unsafe(thr); |
| 26158 | DUK_DDD(DUK_DDDPRINT("-> result %ld" , (long) ret)); |
| 26159 | return ret; |
| 26160 | } |
| 26161 | |
| 26162 | DUK_LOCAL void duk__array_sort_swap(duk_hthread *thr, duk_int_t l, duk_int_t r) { |
| 26163 | duk_bool_t have_l, have_r; |
| 26164 | duk_idx_t idx_obj = 1; /* fixed offset in valstack */ |
| 26165 | |
| 26166 | if (l == r) { |
| 26167 | return; |
| 26168 | } |
| 26169 | |
| 26170 | /* swap elements; deal with non-existent elements correctly */ |
| 26171 | have_l = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) l); |
| 26172 | have_r = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) r); |
| 26173 | |
| 26174 | if (have_r) { |
| 26175 | /* right exists, [[Put]] regardless whether or not left exists */ |
| 26176 | duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) l); |
| 26177 | } else { |
| 26178 | duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) l); |
| 26179 | duk_pop_undefined(thr); |
| 26180 | } |
| 26181 | |
| 26182 | if (have_l) { |
| 26183 | duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) r); |
| 26184 | } else { |
| 26185 | duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) r); |
| 26186 | duk_pop_undefined(thr); |
| 26187 | } |
| 26188 | } |
| 26189 | |
| 26190 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 26191 | /* Debug print which visualizes the qsort partitioning process. */ |
| 26192 | DUK_LOCAL void duk__debuglog_qsort_state(duk_hthread *thr, duk_int_t lo, duk_int_t hi, duk_int_t pivot) { |
| 26193 | char buf[4096]; |
| 26194 | char *ptr = buf; |
| 26195 | duk_int_t i, n; |
| 26196 | n = (duk_int_t) duk_get_length(thr, 1); |
| 26197 | if (n > 4000) { |
| 26198 | n = 4000; |
| 26199 | } |
| 26200 | *ptr++ = '['; |
| 26201 | for (i = 0; i < n; i++) { |
| 26202 | if (i == pivot) { |
| 26203 | *ptr++ = '|'; |
| 26204 | } else if (i == lo) { |
| 26205 | *ptr++ = '<'; |
| 26206 | } else if (i == hi) { |
| 26207 | *ptr++ = '>'; |
| 26208 | } else if (i >= lo && i <= hi) { |
| 26209 | *ptr++ = '-'; |
| 26210 | } else { |
| 26211 | *ptr++ = ' '; |
| 26212 | } |
| 26213 | } |
| 26214 | *ptr++ = ']'; |
| 26215 | *ptr++ = '\0'; |
| 26216 | |
| 26217 | DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)" , |
| 26218 | (const char *) buf, (long) lo, (long) hi, (long) pivot)); |
| 26219 | } |
| 26220 | #endif |
| 26221 | |
| 26222 | DUK_LOCAL void duk__array_qsort(duk_hthread *thr, duk_int_t lo, duk_int_t hi) { |
| 26223 | duk_int_t p, l, r; |
| 26224 | |
| 26225 | /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */ |
| 26226 | |
| 26227 | DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T" , |
| 26228 | (long) lo, (long) hi, (duk_tval *) duk_get_tval(thr, 1))); |
| 26229 | |
| 26230 | DUK_ASSERT_TOP(thr, 3); |
| 26231 | |
| 26232 | /* In some cases it may be that lo > hi, or hi < 0; these |
| 26233 | * degenerate cases happen e.g. for empty arrays, and in |
| 26234 | * recursion leaves. |
| 26235 | */ |
| 26236 | |
| 26237 | /* trivial cases */ |
| 26238 | if (hi - lo < 1) { |
| 26239 | DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately" )); |
| 26240 | return; |
| 26241 | } |
| 26242 | DUK_ASSERT(hi > lo); |
| 26243 | DUK_ASSERT(hi - lo + 1 >= 2); |
| 26244 | |
| 26245 | /* randomized pivot selection */ |
| 26246 | p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE(thr) * (duk_double_t) (hi - lo + 1)); |
| 26247 | DUK_ASSERT(p >= lo && p <= hi); |
| 26248 | DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld" , (long) lo, (long) hi, (long) p)); |
| 26249 | |
| 26250 | /* move pivot out of the way */ |
| 26251 | duk__array_sort_swap(thr, p, lo); |
| 26252 | p = lo; |
| 26253 | DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T" , (duk_tval *) duk_get_tval(thr, 1))); |
| 26254 | |
| 26255 | l = lo + 1; |
| 26256 | r = hi; |
| 26257 | for (;;) { |
| 26258 | /* find elements to swap */ |
| 26259 | for (;;) { |
| 26260 | DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld" , |
| 26261 | (long) l, (long) r, (long) p)); |
| 26262 | if (l >= hi) { |
| 26263 | break; |
| 26264 | } |
| 26265 | if (duk__array_sort_compare(thr, l, p) >= 0) { /* !(l < p) */ |
| 26266 | break; |
| 26267 | } |
| 26268 | l++; |
| 26269 | } |
| 26270 | for (;;) { |
| 26271 | DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld" , |
| 26272 | (long) l, (long) r, (long) p)); |
| 26273 | if (r <= lo) { |
| 26274 | break; |
| 26275 | } |
| 26276 | if (duk__array_sort_compare(thr, p, r) >= 0) { /* !(p < r) */ |
| 26277 | break; |
| 26278 | } |
| 26279 | r--; |
| 26280 | } |
| 26281 | if (l >= r) { |
| 26282 | goto done; |
| 26283 | } |
| 26284 | DUK_ASSERT(l < r); |
| 26285 | |
| 26286 | DUK_DDD(DUK_DDDPRINT("swap %ld and %ld" , (long) l, (long) r)); |
| 26287 | |
| 26288 | duk__array_sort_swap(thr, l, r); |
| 26289 | |
| 26290 | DUK_DDD(DUK_DDDPRINT("after swap: %!T" , (duk_tval *) duk_get_tval(thr, 1))); |
| 26291 | l++; |
| 26292 | r--; |
| 26293 | } |
| 26294 | done: |
| 26295 | /* Note that 'l' and 'r' may cross, i.e. r < l */ |
| 26296 | DUK_ASSERT(l >= lo && l <= hi); |
| 26297 | DUK_ASSERT(r >= lo && r <= hi); |
| 26298 | |
| 26299 | /* XXX: there's no explicit recursion bound here now. For the average |
| 26300 | * qsort recursion depth O(log n) that's not really necessary: e.g. for |
| 26301 | * 2**32 recursion depth would be about 32 which is OK. However, qsort |
| 26302 | * worst case recursion depth is O(n) which may be a problem. |
| 26303 | */ |
| 26304 | |
| 26305 | /* move pivot to its final place */ |
| 26306 | DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T" , (duk_tval *) duk_get_tval(thr, 1))); |
| 26307 | duk__array_sort_swap(thr, lo, r); |
| 26308 | |
| 26309 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 26310 | duk__debuglog_qsort_state(thr, lo, hi, r); |
| 26311 | #endif |
| 26312 | |
| 26313 | DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T" , (long) r, (duk_tval *) duk_get_tval(thr, 1))); |
| 26314 | duk__array_qsort(thr, lo, r - 1); |
| 26315 | duk__array_qsort(thr, r + 1, hi); |
| 26316 | } |
| 26317 | |
| 26318 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_hthread *thr) { |
| 26319 | duk_uint32_t len; |
| 26320 | |
| 26321 | /* XXX: len >= 0x80000000 won't work below because a signed type |
| 26322 | * is needed by qsort. |
| 26323 | */ |
| 26324 | len = duk__push_this_obj_len_u32_limited(thr); |
| 26325 | |
| 26326 | /* stack[0] = compareFn |
| 26327 | * stack[1] = ToObject(this) |
| 26328 | * stack[2] = ToUint32(length) |
| 26329 | */ |
| 26330 | |
| 26331 | if (len > 0) { |
| 26332 | /* avoid degenerate cases, so that (len - 1) won't underflow */ |
| 26333 | duk__array_qsort(thr, (duk_int_t) 0, (duk_int_t) (len - 1)); |
| 26334 | } |
| 26335 | |
| 26336 | DUK_ASSERT_TOP(thr, 3); |
| 26337 | duk_pop_nodecref_unsafe(thr); |
| 26338 | return 1; /* return ToObject(this) */ |
| 26339 | } |
| 26340 | |
| 26341 | /* |
| 26342 | * splice() |
| 26343 | */ |
| 26344 | |
| 26345 | /* XXX: this compiles to over 500 bytes now, even without special handling |
| 26346 | * for an array part. Uses signed ints so does not handle full array range correctly. |
| 26347 | */ |
| 26348 | |
| 26349 | /* XXX: can shift() / unshift() use the same helper? |
| 26350 | * shift() is (close to?) <--> splice(0, 1) |
| 26351 | * unshift is (close to?) <--> splice(0, 0, [items])? |
| 26352 | */ |
| 26353 | |
| 26354 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_hthread *thr) { |
| 26355 | duk_idx_t nargs; |
| 26356 | duk_uint32_t len_u32; |
| 26357 | duk_int_t len; |
| 26358 | duk_bool_t have_delcount; |
| 26359 | duk_int_t item_count; |
| 26360 | duk_int_t act_start; |
| 26361 | duk_int_t del_count; |
| 26362 | duk_int_t i, n; |
| 26363 | |
| 26364 | DUK_UNREF(have_delcount); |
| 26365 | |
| 26366 | nargs = duk_get_top(thr); |
| 26367 | if (nargs < 2) { |
| 26368 | duk_set_top(thr, 2); |
| 26369 | nargs = 2; |
| 26370 | have_delcount = 0; |
| 26371 | } else { |
| 26372 | have_delcount = 1; |
| 26373 | } |
| 26374 | |
| 26375 | /* XXX: len >= 0x80000000 won't work below because we need to be |
| 26376 | * able to represent -len. |
| 26377 | */ |
| 26378 | len_u32 = duk__push_this_obj_len_u32_limited(thr); |
| 26379 | len = (duk_int_t) len_u32; |
| 26380 | DUK_ASSERT(len >= 0); |
| 26381 | |
| 26382 | act_start = duk_to_int_clamped(thr, 0, -len, len); |
| 26383 | if (act_start < 0) { |
| 26384 | act_start = len + act_start; |
| 26385 | } |
| 26386 | DUK_ASSERT(act_start >= 0 && act_start <= len); |
| 26387 | |
| 26388 | #if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT) |
| 26389 | if (have_delcount) { |
| 26390 | #endif |
| 26391 | del_count = duk_to_int_clamped(thr, 1, 0, len - act_start); |
| 26392 | #if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT) |
| 26393 | } else { |
| 26394 | /* E5.1 standard behavior when deleteCount is not given would be |
| 26395 | * to treat it just like if 'undefined' was given, which coerces |
| 26396 | * ultimately to 0. Real world behavior is to splice to the end |
| 26397 | * of array, see test-bi-array-proto-splice-no-delcount.js. |
| 26398 | */ |
| 26399 | del_count = len - act_start; |
| 26400 | } |
| 26401 | #endif |
| 26402 | |
| 26403 | DUK_ASSERT(nargs >= 2); |
| 26404 | item_count = (duk_int_t) (nargs - 2); |
| 26405 | |
| 26406 | DUK_ASSERT(del_count >= 0 && del_count <= len - act_start); |
| 26407 | DUK_ASSERT(del_count + act_start <= len); |
| 26408 | |
| 26409 | /* For now, restrict result array into 32-bit length range. */ |
| 26410 | if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) { |
| 26411 | DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw" )); |
| 26412 | DUK_DCERROR_RANGE_INVALID_LENGTH(thr); |
| 26413 | } |
| 26414 | |
| 26415 | duk_push_array(thr); |
| 26416 | |
| 26417 | /* stack[0] = start |
| 26418 | * stack[1] = deleteCount |
| 26419 | * stack[2...nargs-1] = items |
| 26420 | * stack[nargs] = ToObject(this) -3 |
| 26421 | * stack[nargs+1] = ToUint32(length) -2 |
| 26422 | * stack[nargs+2] = result array -1 |
| 26423 | */ |
| 26424 | |
| 26425 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26426 | |
| 26427 | /* Step 9: copy elements-to-be-deleted into the result array */ |
| 26428 | |
| 26429 | for (i = 0; i < del_count; i++) { |
| 26430 | if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (act_start + i))) { |
| 26431 | duk_xdef_prop_index_wec(thr, -2, (duk_uarridx_t) i); /* throw flag irrelevant (false in std alg) */ |
| 26432 | } else { |
| 26433 | duk_pop_undefined(thr); |
| 26434 | } |
| 26435 | } |
| 26436 | duk_push_u32(thr, (duk_uint32_t) del_count); |
| 26437 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); |
| 26438 | |
| 26439 | /* Steps 12 and 13: reorganize elements to make room for itemCount elements */ |
| 26440 | |
| 26441 | if (item_count < del_count) { |
| 26442 | /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1 |
| 26443 | * -> [ A B F G H ] (conceptual intermediate step) |
| 26444 | * -> [ A B . F G H ] (placeholder marked) |
| 26445 | * [ A B C F G H ] (actual result at this point, C will be replaced) |
| 26446 | */ |
| 26447 | |
| 26448 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26449 | |
| 26450 | n = len - del_count; |
| 26451 | for (i = act_start; i < n; i++) { |
| 26452 | if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) { |
| 26453 | duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count)); |
| 26454 | } else { |
| 26455 | duk_pop_undefined(thr); |
| 26456 | duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count)); |
| 26457 | } |
| 26458 | } |
| 26459 | |
| 26460 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26461 | |
| 26462 | /* loop iterator init and limit changed from standard algorithm */ |
| 26463 | n = len - del_count + item_count; |
| 26464 | for (i = len - 1; i >= n; i--) { |
| 26465 | duk_del_prop_index(thr, -3, (duk_uarridx_t) i); |
| 26466 | } |
| 26467 | |
| 26468 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26469 | } else if (item_count > del_count) { |
| 26470 | /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4 |
| 26471 | * -> [ A B F G H ] (conceptual intermediate step) |
| 26472 | * -> [ A B . . . . F G H ] (placeholder marked) |
| 26473 | * [ A B C D E F F G H ] (actual result at this point) |
| 26474 | */ |
| 26475 | |
| 26476 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26477 | |
| 26478 | /* loop iterator init and limit changed from standard algorithm */ |
| 26479 | for (i = len - del_count - 1; i >= act_start; i--) { |
| 26480 | if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) { |
| 26481 | duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count)); |
| 26482 | } else { |
| 26483 | duk_pop_undefined(thr); |
| 26484 | duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count)); |
| 26485 | } |
| 26486 | } |
| 26487 | |
| 26488 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26489 | } else { |
| 26490 | /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3 |
| 26491 | * -> [ A B F G H ] (conceptual intermediate step) |
| 26492 | * -> [ A B . . . F G H ] (placeholder marked) |
| 26493 | * [ A B C D E F G H ] (actual result at this point) |
| 26494 | */ |
| 26495 | } |
| 26496 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26497 | |
| 26498 | /* Step 15: insert itemCount elements into the hole made above */ |
| 26499 | |
| 26500 | for (i = 0; i < item_count; i++) { |
| 26501 | duk_dup(thr, i + 2); /* args start at index 2 */ |
| 26502 | duk_put_prop_index(thr, -4, (duk_uarridx_t) (act_start + i)); |
| 26503 | } |
| 26504 | |
| 26505 | /* Step 16: update length; note that the final length may be above 32 bit range |
| 26506 | * (but we checked above that this isn't the case here) |
| 26507 | */ |
| 26508 | |
| 26509 | duk_push_u32(thr, (duk_uint32_t) (len - del_count + item_count)); |
| 26510 | duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH); |
| 26511 | |
| 26512 | /* result array is already at the top of stack */ |
| 26513 | DUK_ASSERT_TOP(thr, nargs + 3); |
| 26514 | return 1; |
| 26515 | } |
| 26516 | |
| 26517 | /* |
| 26518 | * reverse() |
| 26519 | */ |
| 26520 | |
| 26521 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_hthread *thr) { |
| 26522 | duk_uint32_t len; |
| 26523 | duk_uint32_t middle; |
| 26524 | duk_uint32_t lower, upper; |
| 26525 | duk_bool_t have_lower, have_upper; |
| 26526 | |
| 26527 | len = duk__push_this_obj_len_u32(thr); |
| 26528 | middle = len / 2; |
| 26529 | |
| 26530 | /* If len <= 1, middle will be 0 and for-loop bails out |
| 26531 | * immediately (0 < 0 -> false). |
| 26532 | */ |
| 26533 | |
| 26534 | for (lower = 0; lower < middle; lower++) { |
| 26535 | DUK_ASSERT(len >= 2); |
| 26536 | DUK_ASSERT_TOP(thr, 2); |
| 26537 | |
| 26538 | DUK_ASSERT(len >= lower + 1); |
| 26539 | upper = len - lower - 1; |
| 26540 | |
| 26541 | have_lower = duk_get_prop_index(thr, -2, (duk_uarridx_t) lower); |
| 26542 | have_upper = duk_get_prop_index(thr, -3, (duk_uarridx_t) upper); |
| 26543 | |
| 26544 | /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */ |
| 26545 | |
| 26546 | if (have_upper) { |
| 26547 | duk_put_prop_index(thr, -4, (duk_uarridx_t) lower); |
| 26548 | } else { |
| 26549 | duk_del_prop_index(thr, -4, (duk_uarridx_t) lower); |
| 26550 | duk_pop_undefined(thr); |
| 26551 | } |
| 26552 | |
| 26553 | if (have_lower) { |
| 26554 | duk_put_prop_index(thr, -3, (duk_uarridx_t) upper); |
| 26555 | } else { |
| 26556 | duk_del_prop_index(thr, -3, (duk_uarridx_t) upper); |
| 26557 | duk_pop_undefined(thr); |
| 26558 | } |
| 26559 | |
| 26560 | DUK_ASSERT_TOP(thr, 2); |
| 26561 | } |
| 26562 | |
| 26563 | DUK_ASSERT_TOP(thr, 2); |
| 26564 | duk_pop_unsafe(thr); /* -> [ ToObject(this) ] */ |
| 26565 | return 1; |
| 26566 | } |
| 26567 | |
| 26568 | /* |
| 26569 | * slice() |
| 26570 | */ |
| 26571 | |
| 26572 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_hthread *thr) { |
| 26573 | duk_uint32_t len_u32; |
| 26574 | duk_int_t len; |
| 26575 | duk_int_t start, end; |
| 26576 | duk_int_t i; |
| 26577 | duk_uarridx_t idx; |
| 26578 | duk_uint32_t res_length = 0; |
| 26579 | |
| 26580 | /* XXX: len >= 0x80000000 won't work below because we need to be |
| 26581 | * able to represent -len. |
| 26582 | */ |
| 26583 | len_u32 = duk__push_this_obj_len_u32_limited(thr); |
| 26584 | len = (duk_int_t) len_u32; |
| 26585 | DUK_ASSERT(len >= 0); |
| 26586 | |
| 26587 | duk_push_array(thr); |
| 26588 | |
| 26589 | /* stack[0] = start |
| 26590 | * stack[1] = end |
| 26591 | * stack[2] = ToObject(this) |
| 26592 | * stack[3] = ToUint32(length) |
| 26593 | * stack[4] = result array |
| 26594 | */ |
| 26595 | |
| 26596 | start = duk_to_int_clamped(thr, 0, -len, len); |
| 26597 | if (start < 0) { |
| 26598 | start = len + start; |
| 26599 | } |
| 26600 | /* XXX: could duk_is_undefined() provide defaulting undefined to 'len' |
| 26601 | * (the upper limit)? |
| 26602 | */ |
| 26603 | if (duk_is_undefined(thr, 1)) { |
| 26604 | end = len; |
| 26605 | } else { |
| 26606 | end = duk_to_int_clamped(thr, 1, -len, len); |
| 26607 | if (end < 0) { |
| 26608 | end = len + end; |
| 26609 | } |
| 26610 | } |
| 26611 | DUK_ASSERT(start >= 0 && start <= len); |
| 26612 | DUK_ASSERT(end >= 0 && end <= len); |
| 26613 | |
| 26614 | idx = 0; |
| 26615 | for (i = start; i < end; i++) { |
| 26616 | DUK_ASSERT_TOP(thr, 5); |
| 26617 | if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) { |
| 26618 | duk_xdef_prop_index_wec(thr, 4, idx); |
| 26619 | res_length = idx + 1; |
| 26620 | } else { |
| 26621 | duk_pop_undefined(thr); |
| 26622 | } |
| 26623 | idx++; |
| 26624 | DUK_ASSERT_TOP(thr, 5); |
| 26625 | } |
| 26626 | |
| 26627 | duk_push_u32(thr, res_length); |
| 26628 | duk_xdef_prop_stridx_short(thr, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); |
| 26629 | |
| 26630 | DUK_ASSERT_TOP(thr, 5); |
| 26631 | return 1; |
| 26632 | } |
| 26633 | |
| 26634 | /* |
| 26635 | * shift() |
| 26636 | */ |
| 26637 | |
| 26638 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_hthread *thr) { |
| 26639 | duk_uint32_t len; |
| 26640 | duk_uint32_t i; |
| 26641 | |
| 26642 | len = duk__push_this_obj_len_u32(thr); |
| 26643 | if (len == 0) { |
| 26644 | duk_push_int(thr, 0); |
| 26645 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); |
| 26646 | return 0; |
| 26647 | } |
| 26648 | |
| 26649 | duk_get_prop_index(thr, 0, 0); |
| 26650 | |
| 26651 | /* stack[0] = object (this) |
| 26652 | * stack[1] = ToUint32(length) |
| 26653 | * stack[2] = elem at index 0 (retval) |
| 26654 | */ |
| 26655 | |
| 26656 | for (i = 1; i < len; i++) { |
| 26657 | DUK_ASSERT_TOP(thr, 3); |
| 26658 | if (duk_get_prop_index(thr, 0, (duk_uarridx_t) i)) { |
| 26659 | /* fromPresent = true */ |
| 26660 | duk_put_prop_index(thr, 0, (duk_uarridx_t) (i - 1)); |
| 26661 | } else { |
| 26662 | /* fromPresent = false */ |
| 26663 | duk_del_prop_index(thr, 0, (duk_uarridx_t) (i - 1)); |
| 26664 | duk_pop_undefined(thr); |
| 26665 | } |
| 26666 | } |
| 26667 | duk_del_prop_index(thr, 0, (duk_uarridx_t) (len - 1)); |
| 26668 | |
| 26669 | duk_push_u32(thr, (duk_uint32_t) (len - 1)); |
| 26670 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); |
| 26671 | |
| 26672 | DUK_ASSERT_TOP(thr, 3); |
| 26673 | return 1; |
| 26674 | } |
| 26675 | |
| 26676 | /* |
| 26677 | * unshift() |
| 26678 | */ |
| 26679 | |
| 26680 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_hthread *thr) { |
| 26681 | duk_idx_t nargs; |
| 26682 | duk_uint32_t len; |
| 26683 | duk_uint32_t i; |
| 26684 | |
| 26685 | nargs = duk_get_top(thr); |
| 26686 | len = duk__push_this_obj_len_u32(thr); |
| 26687 | |
| 26688 | /* stack[0...nargs-1] = unshift args (vararg) |
| 26689 | * stack[nargs] = ToObject(this) |
| 26690 | * stack[nargs+1] = ToUint32(length) |
| 26691 | */ |
| 26692 | |
| 26693 | DUK_ASSERT_TOP(thr, nargs + 2); |
| 26694 | |
| 26695 | /* Note: unshift() may operate on indices above unsigned 32-bit range |
| 26696 | * and the final length may be >= 2**32. However, we restrict the |
| 26697 | * final result to 32-bit range for practicality. |
| 26698 | */ |
| 26699 | |
| 26700 | if (len + (duk_uint32_t) nargs < len) { |
| 26701 | DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw" )); |
| 26702 | DUK_DCERROR_RANGE_INVALID_LENGTH(thr); |
| 26703 | } |
| 26704 | |
| 26705 | i = len; |
| 26706 | while (i > 0) { |
| 26707 | DUK_ASSERT_TOP(thr, nargs + 2); |
| 26708 | i--; |
| 26709 | /* k+argCount-1; note that may be above 32-bit range */ |
| 26710 | |
| 26711 | if (duk_get_prop_index(thr, -2, (duk_uarridx_t) i)) { |
| 26712 | /* fromPresent = true */ |
| 26713 | /* [ ... ToObject(this) ToUint32(length) val ] */ |
| 26714 | duk_put_prop_index(thr, -3, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ |
| 26715 | } else { |
| 26716 | /* fromPresent = false */ |
| 26717 | /* [ ... ToObject(this) ToUint32(length) val ] */ |
| 26718 | duk_pop_undefined(thr); |
| 26719 | duk_del_prop_index(thr, -2, (duk_uarridx_t) (i + (duk_uint32_t) nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */ |
| 26720 | } |
| 26721 | DUK_ASSERT_TOP(thr, nargs + 2); |
| 26722 | } |
| 26723 | |
| 26724 | for (i = 0; i < (duk_uint32_t) nargs; i++) { |
| 26725 | DUK_ASSERT_TOP(thr, nargs + 2); |
| 26726 | duk_dup(thr, (duk_idx_t) i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */ |
| 26727 | duk_put_prop_index(thr, -3, (duk_uarridx_t) i); |
| 26728 | DUK_ASSERT_TOP(thr, nargs + 2); |
| 26729 | } |
| 26730 | |
| 26731 | DUK_ASSERT_TOP(thr, nargs + 2); |
| 26732 | duk_push_u32(thr, len + (duk_uint32_t) nargs); |
| 26733 | duk_dup_top(thr); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */ |
| 26734 | duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH); |
| 26735 | return 1; |
| 26736 | } |
| 26737 | |
| 26738 | /* |
| 26739 | * indexOf(), lastIndexOf() |
| 26740 | */ |
| 26741 | |
| 26742 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_hthread *thr) { |
| 26743 | duk_idx_t nargs; |
| 26744 | duk_int_t i, len; |
| 26745 | duk_int_t from_idx; |
| 26746 | duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for indexOf, -1 for lastIndexOf */ |
| 26747 | |
| 26748 | /* lastIndexOf() needs to be a vararg function because we must distinguish |
| 26749 | * between an undefined fromIndex and a "not given" fromIndex; indexOf() is |
| 26750 | * made vararg for symmetry although it doesn't strictly need to be. |
| 26751 | */ |
| 26752 | |
| 26753 | nargs = duk_get_top(thr); |
| 26754 | duk_set_top(thr, 2); |
| 26755 | |
| 26756 | /* XXX: must be able to represent -len */ |
| 26757 | len = (duk_int_t) duk__push_this_obj_len_u32_limited(thr); |
| 26758 | if (len == 0) { |
| 26759 | goto not_found; |
| 26760 | } |
| 26761 | |
| 26762 | /* Index clamping is a bit tricky, we must ensure that we'll only iterate |
| 26763 | * through elements that exist and that the specific requirements from E5.1 |
| 26764 | * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially: |
| 26765 | * |
| 26766 | * - indexOf: clamp to [-len,len], negative handling -> [0,len], |
| 26767 | * if clamped result is len, for-loop bails out immediately |
| 26768 | * |
| 26769 | * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1], |
| 26770 | * if clamped result is -1, for-loop bails out immediately |
| 26771 | * |
| 26772 | * If fromIndex is not given, ToInteger(undefined) = 0, which is correct |
| 26773 | * for indexOf() but incorrect for lastIndexOf(). Hence special handling, |
| 26774 | * and why lastIndexOf() needs to be a vararg function. |
| 26775 | */ |
| 26776 | |
| 26777 | if (nargs >= 2) { |
| 26778 | /* indexOf: clamp fromIndex to [-len, len] |
| 26779 | * (if fromIndex == len, for-loop terminates directly) |
| 26780 | * |
| 26781 | * lastIndexOf: clamp fromIndex to [-len - 1, len - 1] |
| 26782 | * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly) |
| 26783 | */ |
| 26784 | from_idx = duk_to_int_clamped(thr, |
| 26785 | 1, |
| 26786 | (idx_step > 0 ? -len : -len - 1), |
| 26787 | (idx_step > 0 ? len : len - 1)); |
| 26788 | if (from_idx < 0) { |
| 26789 | /* for lastIndexOf, result may be -1 (mark immediate termination) */ |
| 26790 | from_idx = len + from_idx; |
| 26791 | } |
| 26792 | } else { |
| 26793 | /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but |
| 26794 | * handle both indexOf and lastIndexOf specially here. |
| 26795 | */ |
| 26796 | if (idx_step > 0) { |
| 26797 | from_idx = 0; |
| 26798 | } else { |
| 26799 | from_idx = len - 1; |
| 26800 | } |
| 26801 | } |
| 26802 | |
| 26803 | /* stack[0] = searchElement |
| 26804 | * stack[1] = fromIndex |
| 26805 | * stack[2] = object |
| 26806 | * stack[3] = length (not needed, but not popped above) |
| 26807 | */ |
| 26808 | |
| 26809 | for (i = from_idx; i >= 0 && i < len; i += idx_step) { |
| 26810 | DUK_ASSERT_TOP(thr, 4); |
| 26811 | |
| 26812 | if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) { |
| 26813 | DUK_ASSERT_TOP(thr, 5); |
| 26814 | if (duk_strict_equals(thr, 0, 4)) { |
| 26815 | duk_push_int(thr, i); |
| 26816 | return 1; |
| 26817 | } |
| 26818 | } |
| 26819 | |
| 26820 | duk_pop_unsafe(thr); |
| 26821 | } |
| 26822 | |
| 26823 | not_found: |
| 26824 | duk_push_int(thr, -1); |
| 26825 | return 1; |
| 26826 | } |
| 26827 | |
| 26828 | /* |
| 26829 | * every(), some(), forEach(), map(), filter() |
| 26830 | */ |
| 26831 | |
| 26832 | #define DUK__ITER_EVERY 0 |
| 26833 | #define DUK__ITER_SOME 1 |
| 26834 | #define DUK__ITER_FOREACH 2 |
| 26835 | #define DUK__ITER_MAP 3 |
| 26836 | #define DUK__ITER_FILTER 4 |
| 26837 | |
| 26838 | /* XXX: This helper is a bit awkward because the handling for the different iteration |
| 26839 | * callers is quite different. This now compiles to a bit less than 500 bytes, so with |
| 26840 | * 5 callers the net result is about 100 bytes / caller. |
| 26841 | */ |
| 26842 | |
| 26843 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) { |
| 26844 | duk_uint32_t len; |
| 26845 | duk_uint32_t i; |
| 26846 | duk_uarridx_t k; |
| 26847 | duk_bool_t bval; |
| 26848 | duk_small_int_t iter_type = duk_get_current_magic(thr); |
| 26849 | duk_uint32_t res_length = 0; |
| 26850 | |
| 26851 | /* each call this helper serves has nargs==2 */ |
| 26852 | DUK_ASSERT_TOP(thr, 2); |
| 26853 | |
| 26854 | len = duk__push_this_obj_len_u32(thr); |
| 26855 | duk_require_callable(thr, 0); |
| 26856 | /* if thisArg not supplied, behave as if undefined was supplied */ |
| 26857 | |
| 26858 | if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) { |
| 26859 | duk_push_array(thr); |
| 26860 | } else { |
| 26861 | duk_push_undefined(thr); |
| 26862 | } |
| 26863 | |
| 26864 | /* stack[0] = callback |
| 26865 | * stack[1] = thisArg |
| 26866 | * stack[2] = object |
| 26867 | * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop) |
| 26868 | * stack[4] = result array (or undefined) |
| 26869 | */ |
| 26870 | |
| 26871 | k = 0; /* result index for filter() */ |
| 26872 | for (i = 0; i < len; i++) { |
| 26873 | DUK_ASSERT_TOP(thr, 5); |
| 26874 | |
| 26875 | if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) { |
| 26876 | /* For 'map' trailing missing elements don't invoke the |
| 26877 | * callback but count towards the result length. |
| 26878 | */ |
| 26879 | if (iter_type == DUK__ITER_MAP) { |
| 26880 | res_length = i + 1; |
| 26881 | } |
| 26882 | duk_pop_undefined(thr); |
| 26883 | continue; |
| 26884 | } |
| 26885 | |
| 26886 | /* The original value needs to be preserved for filter(), hence |
| 26887 | * this funny order. We can't re-get the value because of side |
| 26888 | * effects. |
| 26889 | */ |
| 26890 | |
| 26891 | duk_dup_0(thr); |
| 26892 | duk_dup_1(thr); |
| 26893 | duk_dup_m3(thr); |
| 26894 | duk_push_u32(thr, i); |
| 26895 | duk_dup_2(thr); /* [ ... val callback thisArg val i obj ] */ |
| 26896 | duk_call_method(thr, 3); /* -> [ ... val retval ] */ |
| 26897 | |
| 26898 | switch (iter_type) { |
| 26899 | case DUK__ITER_EVERY: |
| 26900 | bval = duk_to_boolean(thr, -1); |
| 26901 | if (!bval) { |
| 26902 | /* stack top contains 'false' */ |
| 26903 | return 1; |
| 26904 | } |
| 26905 | break; |
| 26906 | case DUK__ITER_SOME: |
| 26907 | bval = duk_to_boolean(thr, -1); |
| 26908 | if (bval) { |
| 26909 | /* stack top contains 'true' */ |
| 26910 | return 1; |
| 26911 | } |
| 26912 | break; |
| 26913 | case DUK__ITER_FOREACH: |
| 26914 | /* nop */ |
| 26915 | break; |
| 26916 | case DUK__ITER_MAP: |
| 26917 | duk_dup_top(thr); |
| 26918 | duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) i); /* retval to result[i] */ |
| 26919 | res_length = i + 1; |
| 26920 | break; |
| 26921 | case DUK__ITER_FILTER: |
| 26922 | bval = duk_to_boolean(thr, -1); |
| 26923 | if (bval) { |
| 26924 | duk_dup_m2(thr); /* orig value */ |
| 26925 | duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) k); |
| 26926 | k++; |
| 26927 | res_length = k; |
| 26928 | } |
| 26929 | break; |
| 26930 | default: |
| 26931 | DUK_UNREACHABLE(); |
| 26932 | break; |
| 26933 | } |
| 26934 | duk_pop_2_unsafe(thr); |
| 26935 | |
| 26936 | DUK_ASSERT_TOP(thr, 5); |
| 26937 | } |
| 26938 | |
| 26939 | switch (iter_type) { |
| 26940 | case DUK__ITER_EVERY: |
| 26941 | duk_push_true(thr); |
| 26942 | break; |
| 26943 | case DUK__ITER_SOME: |
| 26944 | duk_push_false(thr); |
| 26945 | break; |
| 26946 | case DUK__ITER_FOREACH: |
| 26947 | duk_push_undefined(thr); |
| 26948 | break; |
| 26949 | case DUK__ITER_MAP: |
| 26950 | case DUK__ITER_FILTER: |
| 26951 | DUK_ASSERT_TOP(thr, 5); |
| 26952 | DUK_ASSERT(duk_is_array(thr, -1)); /* topmost element is the result array already */ |
| 26953 | duk_push_u32(thr, res_length); |
| 26954 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); |
| 26955 | break; |
| 26956 | default: |
| 26957 | DUK_UNREACHABLE(); |
| 26958 | break; |
| 26959 | } |
| 26960 | |
| 26961 | return 1; |
| 26962 | } |
| 26963 | |
| 26964 | /* |
| 26965 | * reduce(), reduceRight() |
| 26966 | */ |
| 26967 | |
| 26968 | DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_hthread *thr) { |
| 26969 | duk_idx_t nargs; |
| 26970 | duk_bool_t have_acc; |
| 26971 | duk_uint32_t i, len; |
| 26972 | duk_small_int_t idx_step = duk_get_current_magic(thr); /* idx_step is +1 for reduce, -1 for reduceRight */ |
| 26973 | |
| 26974 | /* We're a varargs function because we need to detect whether |
| 26975 | * initialValue was given or not. |
| 26976 | */ |
| 26977 | nargs = duk_get_top(thr); |
| 26978 | DUK_DDD(DUK_DDDPRINT("nargs=%ld" , (long) nargs)); |
| 26979 | |
| 26980 | duk_set_top(thr, 2); |
| 26981 | len = duk__push_this_obj_len_u32(thr); |
| 26982 | duk_require_callable(thr, 0); |
| 26983 | |
| 26984 | /* stack[0] = callback fn |
| 26985 | * stack[1] = initialValue |
| 26986 | * stack[2] = object (coerced this) |
| 26987 | * stack[3] = length (not needed, but not popped above) |
| 26988 | * stack[4] = accumulator |
| 26989 | */ |
| 26990 | |
| 26991 | have_acc = 0; |
| 26992 | if (nargs >= 2) { |
| 26993 | duk_dup_1(thr); |
| 26994 | have_acc = 1; |
| 26995 | } |
| 26996 | DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T" , |
| 26997 | (long) have_acc, (duk_tval *) duk_get_tval(thr, 3))); |
| 26998 | |
| 26999 | /* For len == 0, i is initialized to len - 1 which underflows. |
| 27000 | * The condition (i < len) will then exit the for-loop on the |
| 27001 | * first round which is correct. Similarly, loop termination |
| 27002 | * happens by i underflowing. |
| 27003 | */ |
| 27004 | |
| 27005 | for (i = (idx_step >= 0 ? 0 : len - 1); |
| 27006 | i < len; /* i >= 0 would always be true */ |
| 27007 | i += (duk_uint32_t) idx_step) { |
| 27008 | DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T" , |
| 27009 | (long) i, (long) len, (long) have_acc, |
| 27010 | (long) duk_get_top(thr), |
| 27011 | (duk_tval *) duk_get_tval(thr, 4))); |
| 27012 | |
| 27013 | DUK_ASSERT((have_acc && duk_get_top(thr) == 5) || |
| 27014 | (!have_acc && duk_get_top(thr) == 4)); |
| 27015 | |
| 27016 | if (!duk_has_prop_index(thr, 2, (duk_uarridx_t) i)) { |
| 27017 | continue; |
| 27018 | } |
| 27019 | |
| 27020 | if (!have_acc) { |
| 27021 | DUK_ASSERT_TOP(thr, 4); |
| 27022 | duk_get_prop_index(thr, 2, (duk_uarridx_t) i); |
| 27023 | have_acc = 1; |
| 27024 | DUK_ASSERT_TOP(thr, 5); |
| 27025 | } else { |
| 27026 | DUK_ASSERT_TOP(thr, 5); |
| 27027 | duk_dup_0(thr); |
| 27028 | duk_dup(thr, 4); |
| 27029 | duk_get_prop_index(thr, 2, (duk_uarridx_t) i); |
| 27030 | duk_push_u32(thr, i); |
| 27031 | duk_dup_2(thr); |
| 27032 | DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T" , |
| 27033 | (duk_tval *) duk_get_tval(thr, -5), (duk_tval *) duk_get_tval(thr, -4), |
| 27034 | (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2), |
| 27035 | (duk_tval *) duk_get_tval(thr, -1))); |
| 27036 | duk_call(thr, 4); |
| 27037 | DUK_DDD(DUK_DDDPRINT("-> result: %!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 27038 | duk_replace(thr, 4); |
| 27039 | DUK_ASSERT_TOP(thr, 5); |
| 27040 | } |
| 27041 | } |
| 27042 | |
| 27043 | if (!have_acc) { |
| 27044 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 27045 | } |
| 27046 | |
| 27047 | DUK_ASSERT_TOP(thr, 5); |
| 27048 | return 1; |
| 27049 | } |
| 27050 | |
| 27051 | #endif /* DUK_USE_ARRAY_BUILTIN */ |
| 27052 | |
| 27053 | /* automatic undefs */ |
| 27054 | #undef DUK__ARRAY_MID_JOIN_LIMIT |
| 27055 | #undef DUK__ITER_EVERY |
| 27056 | #undef DUK__ITER_FILTER |
| 27057 | #undef DUK__ITER_FOREACH |
| 27058 | #undef DUK__ITER_MAP |
| 27059 | #undef DUK__ITER_SOME |
| 27060 | #line 1 "duk_bi_boolean.c" |
| 27061 | /* |
| 27062 | * Boolean built-ins |
| 27063 | */ |
| 27064 | |
| 27065 | /* #include duk_internal.h -> already included */ |
| 27066 | |
| 27067 | #if defined(DUK_USE_BOOLEAN_BUILTIN) |
| 27068 | |
| 27069 | /* Shared helper to provide toString() and valueOf(). Checks 'this', gets |
| 27070 | * the primitive value to stack top, and optionally coerces with ToString(). |
| 27071 | */ |
| 27072 | DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) { |
| 27073 | duk_tval *tv; |
| 27074 | duk_hobject *h; |
| 27075 | duk_small_int_t coerce_tostring = duk_get_current_magic(thr); |
| 27076 | |
| 27077 | /* XXX: there is room to use a shared helper here, many built-ins |
| 27078 | * check the 'this' type, and if it's an object, check its class, |
| 27079 | * then get its internal value, etc. |
| 27080 | */ |
| 27081 | |
| 27082 | duk_push_this(thr); |
| 27083 | tv = duk_get_tval(thr, -1); |
| 27084 | DUK_ASSERT(tv != NULL); |
| 27085 | |
| 27086 | if (DUK_TVAL_IS_BOOLEAN(tv)) { |
| 27087 | goto type_ok; |
| 27088 | } else if (DUK_TVAL_IS_OBJECT(tv)) { |
| 27089 | h = DUK_TVAL_GET_OBJECT(tv); |
| 27090 | DUK_ASSERT(h != NULL); |
| 27091 | |
| 27092 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) { |
| 27093 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); |
| 27094 | DUK_ASSERT(duk_is_boolean(thr, -1)); |
| 27095 | goto type_ok; |
| 27096 | } |
| 27097 | } |
| 27098 | |
| 27099 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 27100 | /* never here */ |
| 27101 | |
| 27102 | type_ok: |
| 27103 | if (coerce_tostring) { |
| 27104 | duk_to_string(thr, -1); |
| 27105 | } |
| 27106 | return 1; |
| 27107 | } |
| 27108 | |
| 27109 | DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) { |
| 27110 | duk_hobject *h_this; |
| 27111 | |
| 27112 | duk_to_boolean(thr, 0); |
| 27113 | |
| 27114 | if (duk_is_constructor_call(thr)) { |
| 27115 | /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */ |
| 27116 | duk_push_this(thr); |
| 27117 | h_this = duk_known_hobject(thr, -1); |
| 27118 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]); |
| 27119 | |
| 27120 | DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN); |
| 27121 | |
| 27122 | duk_dup_0(thr); /* -> [ val obj val ] */ |
| 27123 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */ |
| 27124 | } /* unbalanced stack */ |
| 27125 | |
| 27126 | return 1; |
| 27127 | } |
| 27128 | |
| 27129 | #endif /* DUK_USE_BOOLEAN_BUILTIN */ |
| 27130 | #line 1 "duk_bi_buffer.c" |
| 27131 | /* |
| 27132 | * ES2015 TypedArray and Node.js Buffer built-ins |
| 27133 | */ |
| 27134 | |
| 27135 | /* #include duk_internal.h -> already included */ |
| 27136 | |
| 27137 | /* |
| 27138 | * Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT. |
| 27139 | */ |
| 27140 | |
| 27141 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 27142 | /* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the |
| 27143 | * default internal prototype. |
| 27144 | */ |
| 27145 | static const duk_uint8_t duk__buffer_proto_from_classnum[] = { |
| 27146 | DUK_BIDX_ARRAYBUFFER_PROTOTYPE, |
| 27147 | DUK_BIDX_DATAVIEW_PROTOTYPE, |
| 27148 | DUK_BIDX_INT8ARRAY_PROTOTYPE, |
| 27149 | DUK_BIDX_UINT8ARRAY_PROTOTYPE, |
| 27150 | DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, |
| 27151 | DUK_BIDX_INT16ARRAY_PROTOTYPE, |
| 27152 | DUK_BIDX_UINT16ARRAY_PROTOTYPE, |
| 27153 | DUK_BIDX_INT32ARRAY_PROTOTYPE, |
| 27154 | DUK_BIDX_UINT32ARRAY_PROTOTYPE, |
| 27155 | DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, |
| 27156 | DUK_BIDX_FLOAT64ARRAY_PROTOTYPE |
| 27157 | }; |
| 27158 | |
| 27159 | /* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number. |
| 27160 | * Sync with duk_hbufobj.h and duk_hobject.h. |
| 27161 | */ |
| 27162 | static const duk_uint8_t duk__buffer_class_from_elemtype[9] = { |
| 27163 | DUK_HOBJECT_CLASS_UINT8ARRAY, |
| 27164 | DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, |
| 27165 | DUK_HOBJECT_CLASS_INT8ARRAY, |
| 27166 | DUK_HOBJECT_CLASS_UINT16ARRAY, |
| 27167 | DUK_HOBJECT_CLASS_INT16ARRAY, |
| 27168 | DUK_HOBJECT_CLASS_UINT32ARRAY, |
| 27169 | DUK_HOBJECT_CLASS_INT32ARRAY, |
| 27170 | DUK_HOBJECT_CLASS_FLOAT32ARRAY, |
| 27171 | DUK_HOBJECT_CLASS_FLOAT64ARRAY |
| 27172 | }; |
| 27173 | |
| 27174 | /* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index. |
| 27175 | * Sync with duk_hbufobj.h. |
| 27176 | */ |
| 27177 | static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = { |
| 27178 | DUK_BIDX_UINT8ARRAY_PROTOTYPE, |
| 27179 | DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, |
| 27180 | DUK_BIDX_INT8ARRAY_PROTOTYPE, |
| 27181 | DUK_BIDX_UINT16ARRAY_PROTOTYPE, |
| 27182 | DUK_BIDX_INT16ARRAY_PROTOTYPE, |
| 27183 | DUK_BIDX_UINT32ARRAY_PROTOTYPE, |
| 27184 | DUK_BIDX_INT32ARRAY_PROTOTYPE, |
| 27185 | DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, |
| 27186 | DUK_BIDX_FLOAT64ARRAY_PROTOTYPE |
| 27187 | }; |
| 27188 | |
| 27189 | /* Map DUK__FLD_xxx to byte size. */ |
| 27190 | static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = { |
| 27191 | 1, /* DUK__FLD_8BIT */ |
| 27192 | 2, /* DUK__FLD_16BIT */ |
| 27193 | 4, /* DUK__FLD_32BIT */ |
| 27194 | 4, /* DUK__FLD_FLOAT */ |
| 27195 | 8, /* DUK__FLD_DOUBLE */ |
| 27196 | 0 /* DUK__FLD_VARINT; not relevant here */ |
| 27197 | }; |
| 27198 | |
| 27199 | /* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types |
| 27200 | * are compatible with a blind byte copy for the TypedArray set() method (also |
| 27201 | * used for TypedArray constructor). Array index is target buffer elem type, |
| 27202 | * bitfield indicates compatible source types. The types must have same byte |
| 27203 | * size and they must be coercion compatible. |
| 27204 | */ |
| 27205 | #if !defined(DUK_USE_PREFER_SIZE) |
| 27206 | static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = { |
| 27207 | /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */ |
| 27208 | (1U << DUK_HBUFOBJ_ELEM_UINT8) | |
| 27209 | (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) | |
| 27210 | (1U << DUK_HBUFOBJ_ELEM_INT8), |
| 27211 | |
| 27212 | /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED |
| 27213 | * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00. |
| 27214 | */ |
| 27215 | (1U << DUK_HBUFOBJ_ELEM_UINT8) | |
| 27216 | (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED), |
| 27217 | |
| 27218 | /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */ |
| 27219 | (1U << DUK_HBUFOBJ_ELEM_UINT8) | |
| 27220 | (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) | |
| 27221 | (1U << DUK_HBUFOBJ_ELEM_INT8), |
| 27222 | |
| 27223 | /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */ |
| 27224 | (1U << DUK_HBUFOBJ_ELEM_UINT16) | |
| 27225 | (1U << DUK_HBUFOBJ_ELEM_INT16), |
| 27226 | |
| 27227 | /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */ |
| 27228 | (1U << DUK_HBUFOBJ_ELEM_UINT16) | |
| 27229 | (1U << DUK_HBUFOBJ_ELEM_INT16), |
| 27230 | |
| 27231 | /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */ |
| 27232 | (1U << DUK_HBUFOBJ_ELEM_UINT32) | |
| 27233 | (1U << DUK_HBUFOBJ_ELEM_INT32), |
| 27234 | |
| 27235 | /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */ |
| 27236 | (1U << DUK_HBUFOBJ_ELEM_UINT32) | |
| 27237 | (1U << DUK_HBUFOBJ_ELEM_INT32), |
| 27238 | |
| 27239 | /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */ |
| 27240 | (1U << DUK_HBUFOBJ_ELEM_FLOAT32), |
| 27241 | |
| 27242 | /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */ |
| 27243 | (1U << DUK_HBUFOBJ_ELEM_FLOAT64) |
| 27244 | }; |
| 27245 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 27246 | |
| 27247 | DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_hthread *thr) { |
| 27248 | duk_tval *tv_dst; |
| 27249 | duk_hbufobj *res; |
| 27250 | |
| 27251 | duk_push_this(thr); |
| 27252 | DUK_ASSERT(duk_is_buffer(thr, -1)); |
| 27253 | res = (duk_hbufobj *) duk_to_hobject(thr, -1); |
| 27254 | DUK_HBUFOBJ_ASSERT_VALID(res); |
| 27255 | DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT" , duk_get_tval(thr, -1))); |
| 27256 | |
| 27257 | tv_dst = duk_get_borrowed_this_tval(thr); |
| 27258 | DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res); |
| 27259 | duk_pop(thr); |
| 27260 | |
| 27261 | return res; |
| 27262 | } |
| 27263 | |
| 27264 | #define DUK__BUFOBJ_FLAG_THROW (1 << 0) |
| 27265 | #define DUK__BUFOBJ_FLAG_PROMOTE (1 << 1) |
| 27266 | |
| 27267 | /* Shared helper. When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is |
| 27268 | * always a duk_hbufobj *. Without the flag the return value can also be a |
| 27269 | * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER(). |
| 27270 | */ |
| 27271 | DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_uint_t flags) { |
| 27272 | duk_tval *tv; |
| 27273 | duk_hbufobj *h_this; |
| 27274 | |
| 27275 | DUK_ASSERT(thr != NULL); |
| 27276 | |
| 27277 | tv = duk_get_borrowed_this_tval(thr); |
| 27278 | DUK_ASSERT(tv != NULL); |
| 27279 | |
| 27280 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 27281 | h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv); |
| 27282 | DUK_ASSERT(h_this != NULL); |
| 27283 | if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) { |
| 27284 | DUK_HBUFOBJ_ASSERT_VALID(h_this); |
| 27285 | return (duk_heaphdr *) h_this; |
| 27286 | } |
| 27287 | } else if (DUK_TVAL_IS_BUFFER(tv)) { |
| 27288 | if (flags & DUK__BUFOBJ_FLAG_PROMOTE) { |
| 27289 | /* Promote a plain buffer to a Uint8Array. This is very |
| 27290 | * inefficient but allows plain buffer to be used wherever an |
| 27291 | * Uint8Array is used with very small cost; hot path functions |
| 27292 | * like index read/write calls should provide direct buffer |
| 27293 | * support to avoid promotion. |
| 27294 | */ |
| 27295 | /* XXX: make this conditional to a flag if call sites need it? */ |
| 27296 | h_this = duk__hbufobj_promote_this(thr); |
| 27297 | DUK_ASSERT(h_this != NULL); |
| 27298 | DUK_HBUFOBJ_ASSERT_VALID(h_this); |
| 27299 | return (duk_heaphdr *) h_this; |
| 27300 | } else { |
| 27301 | /* XXX: ugly, share return pointer for duk_hbuffer. */ |
| 27302 | return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv); |
| 27303 | } |
| 27304 | } |
| 27305 | |
| 27306 | if (flags & DUK__BUFOBJ_FLAG_THROW) { |
| 27307 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); |
| 27308 | DUK_WO_NORETURN(return NULL;); |
| 27309 | } |
| 27310 | return NULL; |
| 27311 | } |
| 27312 | |
| 27313 | /* Check that 'this' is a duk_hbufobj and return a pointer to it. */ |
| 27314 | DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_hthread *thr) { |
| 27315 | return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_PROMOTE); |
| 27316 | } |
| 27317 | |
| 27318 | /* Check that 'this' is a duk_hbufobj and return a pointer to it |
| 27319 | * (NULL if not). |
| 27320 | */ |
| 27321 | DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_hthread *thr) { |
| 27322 | return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE); |
| 27323 | } |
| 27324 | |
| 27325 | /* Check that value is a duk_hbufobj and return a pointer to it. */ |
| 27326 | DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx) { |
| 27327 | duk_tval *tv; |
| 27328 | duk_hbufobj *h_obj; |
| 27329 | |
| 27330 | /* Don't accept relative indices now. */ |
| 27331 | DUK_ASSERT(idx >= 0); |
| 27332 | |
| 27333 | tv = duk_require_tval(thr, idx); |
| 27334 | DUK_ASSERT(tv != NULL); |
| 27335 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 27336 | h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv); |
| 27337 | DUK_ASSERT(h_obj != NULL); |
| 27338 | if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) { |
| 27339 | DUK_HBUFOBJ_ASSERT_VALID(h_obj); |
| 27340 | return h_obj; |
| 27341 | } |
| 27342 | } else if (DUK_TVAL_IS_BUFFER(tv)) { |
| 27343 | h_obj = (duk_hbufobj *) duk_to_hobject(thr, idx); |
| 27344 | DUK_ASSERT(h_obj != NULL); |
| 27345 | DUK_HBUFOBJ_ASSERT_VALID(h_obj); |
| 27346 | return h_obj; |
| 27347 | } |
| 27348 | |
| 27349 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER); |
| 27350 | DUK_WO_NORETURN(return NULL;); |
| 27351 | } |
| 27352 | |
| 27353 | DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) { |
| 27354 | DUK_ASSERT(thr != NULL); |
| 27355 | DUK_ASSERT(h_bufobj != NULL); |
| 27356 | DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */ |
| 27357 | DUK_ASSERT(h_val != NULL); |
| 27358 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 27359 | DUK_UNREF(thr); |
| 27360 | |
| 27361 | h_bufobj->buf = h_val; |
| 27362 | DUK_HBUFFER_INCREF(thr, h_val); |
| 27363 | h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val); |
| 27364 | DUK_ASSERT(h_bufobj->shift == 0); |
| 27365 | DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8); |
| 27366 | DUK_ASSERT(h_bufobj->is_typedarray == 0); |
| 27367 | |
| 27368 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 27369 | } |
| 27370 | |
| 27371 | /* Shared offset/length coercion helper. */ |
| 27372 | DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr, |
| 27373 | duk_hbufobj *h_bufarg, |
| 27374 | duk_idx_t idx_offset, |
| 27375 | duk_idx_t idx_length, |
| 27376 | duk_uint_t *out_offset, |
| 27377 | duk_uint_t *out_length, |
| 27378 | duk_bool_t throw_flag) { |
| 27379 | duk_int_t offset_signed; |
| 27380 | duk_int_t length_signed; |
| 27381 | duk_uint_t offset; |
| 27382 | duk_uint_t length; |
| 27383 | |
| 27384 | offset_signed = duk_to_int(thr, idx_offset); |
| 27385 | if (offset_signed < 0) { |
| 27386 | goto fail_range; |
| 27387 | } |
| 27388 | offset = (duk_uint_t) offset_signed; |
| 27389 | if (offset > h_bufarg->length) { |
| 27390 | goto fail_range; |
| 27391 | } |
| 27392 | DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */ |
| 27393 | DUK_ASSERT(offset <= h_bufarg->length); |
| 27394 | |
| 27395 | if (duk_is_undefined(thr, idx_length)) { |
| 27396 | DUK_ASSERT(h_bufarg->length >= offset); |
| 27397 | length = h_bufarg->length - offset; /* >= 0 */ |
| 27398 | } else { |
| 27399 | length_signed = duk_to_int(thr, idx_length); |
| 27400 | if (length_signed < 0) { |
| 27401 | goto fail_range; |
| 27402 | } |
| 27403 | length = (duk_uint_t) length_signed; |
| 27404 | DUK_ASSERT(h_bufarg->length >= offset); |
| 27405 | if (length > h_bufarg->length - offset) { |
| 27406 | /* Unlike for negative arguments, some call sites |
| 27407 | * want length to be clamped if it's positive. |
| 27408 | */ |
| 27409 | if (throw_flag) { |
| 27410 | goto fail_range; |
| 27411 | } else { |
| 27412 | length = h_bufarg->length - offset; |
| 27413 | } |
| 27414 | } |
| 27415 | } |
| 27416 | DUK_ASSERT_DISABLE(length >= 0); /* unsigned */ |
| 27417 | DUK_ASSERT(offset + length <= h_bufarg->length); |
| 27418 | |
| 27419 | *out_offset = offset; |
| 27420 | *out_length = length; |
| 27421 | return; |
| 27422 | |
| 27423 | fail_range: |
| 27424 | DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS); |
| 27425 | DUK_WO_NORETURN(return;); |
| 27426 | } |
| 27427 | |
| 27428 | /* Shared lenient buffer length clamping helper. No negative indices, no |
| 27429 | * element/byte shifting. |
| 27430 | */ |
| 27431 | DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_hthread *thr, |
| 27432 | duk_int_t buffer_length, |
| 27433 | duk_idx_t idx_start, |
| 27434 | duk_idx_t idx_end, |
| 27435 | duk_int_t *out_start_offset, |
| 27436 | duk_int_t *out_end_offset) { |
| 27437 | duk_int_t start_offset; |
| 27438 | duk_int_t end_offset; |
| 27439 | |
| 27440 | DUK_ASSERT(out_start_offset != NULL); |
| 27441 | DUK_ASSERT(out_end_offset != NULL); |
| 27442 | |
| 27443 | /* undefined coerces to zero which is correct */ |
| 27444 | start_offset = duk_to_int_clamped(thr, idx_start, 0, buffer_length); |
| 27445 | if (duk_is_undefined(thr, idx_end)) { |
| 27446 | end_offset = buffer_length; |
| 27447 | } else { |
| 27448 | end_offset = duk_to_int_clamped(thr, idx_end, start_offset, buffer_length); |
| 27449 | } |
| 27450 | |
| 27451 | DUK_ASSERT(start_offset >= 0); |
| 27452 | DUK_ASSERT(start_offset <= buffer_length); |
| 27453 | DUK_ASSERT(end_offset >= 0); |
| 27454 | DUK_ASSERT(end_offset <= buffer_length); |
| 27455 | DUK_ASSERT(start_offset <= end_offset); |
| 27456 | |
| 27457 | *out_start_offset = start_offset; |
| 27458 | *out_end_offset = end_offset; |
| 27459 | } |
| 27460 | |
| 27461 | /* Shared lenient buffer length clamping helper. Indices are treated as |
| 27462 | * element indices (though output values are byte offsets) which only |
| 27463 | * really matters for TypedArray views as other buffer object have a zero |
| 27464 | * shift. Negative indices are counted from end of input slice; crossed |
| 27465 | * indices are clamped to zero length; and final indices are clamped |
| 27466 | * against input slice. Used for e.g. ArrayBuffer slice(). |
| 27467 | */ |
| 27468 | DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_hthread *thr, |
| 27469 | duk_int_t buffer_length, |
| 27470 | duk_uint8_t buffer_shift, |
| 27471 | duk_idx_t idx_start, |
| 27472 | duk_idx_t idx_end, |
| 27473 | duk_int_t *out_start_offset, |
| 27474 | duk_int_t *out_end_offset) { |
| 27475 | duk_int_t start_offset; |
| 27476 | duk_int_t end_offset; |
| 27477 | |
| 27478 | DUK_ASSERT(out_start_offset != NULL); |
| 27479 | DUK_ASSERT(out_end_offset != NULL); |
| 27480 | |
| 27481 | buffer_length >>= buffer_shift; /* as (full) elements */ |
| 27482 | |
| 27483 | /* Resolve start/end offset as element indices first; arguments |
| 27484 | * at idx_start/idx_end are element offsets. Working with element |
| 27485 | * indices first also avoids potential for wrapping. |
| 27486 | */ |
| 27487 | |
| 27488 | start_offset = duk_to_int(thr, idx_start); |
| 27489 | if (start_offset < 0) { |
| 27490 | start_offset = buffer_length + start_offset; |
| 27491 | } |
| 27492 | if (duk_is_undefined(thr, idx_end)) { |
| 27493 | end_offset = buffer_length; |
| 27494 | } else { |
| 27495 | end_offset = duk_to_int(thr, idx_end); |
| 27496 | if (end_offset < 0) { |
| 27497 | end_offset = buffer_length + end_offset; |
| 27498 | } |
| 27499 | } |
| 27500 | /* Note: start_offset/end_offset can still be < 0 here. */ |
| 27501 | |
| 27502 | if (start_offset < 0) { |
| 27503 | start_offset = 0; |
| 27504 | } else if (start_offset > buffer_length) { |
| 27505 | start_offset = buffer_length; |
| 27506 | } |
| 27507 | if (end_offset < start_offset) { |
| 27508 | end_offset = start_offset; |
| 27509 | } else if (end_offset > buffer_length) { |
| 27510 | end_offset = buffer_length; |
| 27511 | } |
| 27512 | DUK_ASSERT(start_offset >= 0); |
| 27513 | DUK_ASSERT(start_offset <= buffer_length); |
| 27514 | DUK_ASSERT(end_offset >= 0); |
| 27515 | DUK_ASSERT(end_offset <= buffer_length); |
| 27516 | DUK_ASSERT(start_offset <= end_offset); |
| 27517 | |
| 27518 | /* Convert indices to byte offsets. */ |
| 27519 | start_offset <<= buffer_shift; |
| 27520 | end_offset <<= buffer_shift; |
| 27521 | |
| 27522 | *out_start_offset = start_offset; |
| 27523 | *out_end_offset = end_offset; |
| 27524 | } |
| 27525 | |
| 27526 | DUK_INTERNAL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx) { |
| 27527 | if (duk_is_buffer(thr, idx)) { |
| 27528 | duk_to_object(thr, idx); |
| 27529 | } |
| 27530 | } |
| 27531 | |
| 27532 | DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) { |
| 27533 | /* Push Uint8Array which will share the same underlying buffer as |
| 27534 | * the plain buffer argument. Also create an ArrayBuffer with the |
| 27535 | * same backing for the result .buffer property. |
| 27536 | */ |
| 27537 | |
| 27538 | duk_push_hbuffer(thr, h_buf); |
| 27539 | duk_push_buffer_object(thr, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY); |
| 27540 | duk_remove_m2(thr); |
| 27541 | |
| 27542 | #if 0 |
| 27543 | /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */ |
| 27544 | h_bufobj = duk_push_bufobj_raw(thr, |
| 27545 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 27546 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 27547 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY), |
| 27548 | DUK_BIDX_UINT8ARRAY_PROTOTYPE); |
| 27549 | DUK_ASSERT(h_bufobj != NULL); |
| 27550 | duk__set_bufobj_buffer(thr, h_bufobj, h_buf); |
| 27551 | h_bufobj->is_typedarray = 1; |
| 27552 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 27553 | |
| 27554 | h_arrbuf = duk_push_bufobj_raw(thr, |
| 27555 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 27556 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 27557 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), |
| 27558 | DUK_BIDX_ARRAYBUFFER_PROTOTYPE); |
| 27559 | DUK_ASSERT(h_arrbuf != NULL); |
| 27560 | duk__set_bufobj_buffer(thr, h_arrbuf, h_buf); |
| 27561 | DUK_ASSERT(h_arrbuf->is_typedarray == 0); |
| 27562 | DUK_HBUFOBJ_ASSERT_VALID(h_arrbuf); |
| 27563 | |
| 27564 | DUK_ASSERT(h_bufobj->buf_prop == NULL); |
| 27565 | h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; |
| 27566 | DUK_ASSERT(h_arrbuf != NULL); |
| 27567 | DUK_HBUFOBJ_INCREF(thr, h_arrbuf); |
| 27568 | duk_pop(thr); |
| 27569 | #endif |
| 27570 | } |
| 27571 | |
| 27572 | /* Indexed read helper for buffer objects, also called from outside this file. */ |
| 27573 | DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { |
| 27574 | duk_double_union du; |
| 27575 | |
| 27576 | DUK_ASSERT(elem_size > 0); |
| 27577 | duk_memcpy((void *) du.uc, (const void *) p, (size_t) elem_size); |
| 27578 | |
| 27579 | switch (h_bufobj->elem_type) { |
| 27580 | case DUK_HBUFOBJ_ELEM_UINT8: |
| 27581 | case DUK_HBUFOBJ_ELEM_UINT8CLAMPED: |
| 27582 | duk_push_uint(thr, (duk_uint_t) du.uc[0]); |
| 27583 | break; |
| 27584 | case DUK_HBUFOBJ_ELEM_INT8: |
| 27585 | duk_push_int(thr, (duk_int_t) (duk_int8_t) du.uc[0]); |
| 27586 | break; |
| 27587 | case DUK_HBUFOBJ_ELEM_UINT16: |
| 27588 | duk_push_uint(thr, (duk_uint_t) du.us[0]); |
| 27589 | break; |
| 27590 | case DUK_HBUFOBJ_ELEM_INT16: |
| 27591 | duk_push_int(thr, (duk_int_t) (duk_int16_t) du.us[0]); |
| 27592 | break; |
| 27593 | case DUK_HBUFOBJ_ELEM_UINT32: |
| 27594 | duk_push_uint(thr, (duk_uint_t) du.ui[0]); |
| 27595 | break; |
| 27596 | case DUK_HBUFOBJ_ELEM_INT32: |
| 27597 | duk_push_int(thr, (duk_int_t) (duk_int32_t) du.ui[0]); |
| 27598 | break; |
| 27599 | case DUK_HBUFOBJ_ELEM_FLOAT32: |
| 27600 | duk_push_number(thr, (duk_double_t) du.f[0]); |
| 27601 | break; |
| 27602 | case DUK_HBUFOBJ_ELEM_FLOAT64: |
| 27603 | duk_push_number(thr, (duk_double_t) du.d); |
| 27604 | break; |
| 27605 | default: |
| 27606 | DUK_UNREACHABLE(); |
| 27607 | } |
| 27608 | } |
| 27609 | |
| 27610 | /* Indexed write helper for buffer objects, also called from outside this file. */ |
| 27611 | DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) { |
| 27612 | duk_double_union du; |
| 27613 | |
| 27614 | /* NOTE! Caller must ensure that any side effects from the |
| 27615 | * coercions below are safe. If that cannot be guaranteed |
| 27616 | * (which is normally the case), caller must coerce the |
| 27617 | * argument using duk_to_number() before any pointer |
| 27618 | * validations; the result of duk_to_number() always coerces |
| 27619 | * without side effects here. |
| 27620 | */ |
| 27621 | |
| 27622 | switch (h_bufobj->elem_type) { |
| 27623 | case DUK_HBUFOBJ_ELEM_UINT8: |
| 27624 | du.uc[0] = (duk_uint8_t) duk_to_uint32(thr, -1); |
| 27625 | break; |
| 27626 | case DUK_HBUFOBJ_ELEM_UINT8CLAMPED: |
| 27627 | du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(thr, -1); |
| 27628 | break; |
| 27629 | case DUK_HBUFOBJ_ELEM_INT8: |
| 27630 | du.uc[0] = (duk_uint8_t) duk_to_int32(thr, -1); |
| 27631 | break; |
| 27632 | case DUK_HBUFOBJ_ELEM_UINT16: |
| 27633 | du.us[0] = (duk_uint16_t) duk_to_uint32(thr, -1); |
| 27634 | break; |
| 27635 | case DUK_HBUFOBJ_ELEM_INT16: |
| 27636 | du.us[0] = (duk_uint16_t) duk_to_int32(thr, -1); |
| 27637 | break; |
| 27638 | case DUK_HBUFOBJ_ELEM_UINT32: |
| 27639 | du.ui[0] = (duk_uint32_t) duk_to_uint32(thr, -1); |
| 27640 | break; |
| 27641 | case DUK_HBUFOBJ_ELEM_INT32: |
| 27642 | du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1); |
| 27643 | break; |
| 27644 | case DUK_HBUFOBJ_ELEM_FLOAT32: |
| 27645 | /* A double-to-float cast is undefined behavior in C99 if |
| 27646 | * the cast is out-of-range, so use a helper. Example: |
| 27647 | * runtime error: value -1e+100 is outside the range of representable values of type 'float' |
| 27648 | */ |
| 27649 | du.f[0] = duk_double_to_float_t(duk_to_number_m1(thr)); |
| 27650 | break; |
| 27651 | case DUK_HBUFOBJ_ELEM_FLOAT64: |
| 27652 | du.d = (duk_double_t) duk_to_number_m1(thr); |
| 27653 | break; |
| 27654 | default: |
| 27655 | DUK_UNREACHABLE(); |
| 27656 | } |
| 27657 | |
| 27658 | DUK_ASSERT(elem_size > 0); |
| 27659 | duk_memcpy((void *) p, (const void *) du.uc, (size_t) elem_size); |
| 27660 | } |
| 27661 | |
| 27662 | /* Helper to create a fixed buffer from argument value at index 0. |
| 27663 | * Node.js and allocPlain() compatible. |
| 27664 | */ |
| 27665 | DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) { |
| 27666 | duk_int_t len; |
| 27667 | duk_int_t i; |
| 27668 | duk_size_t buf_size; |
| 27669 | duk_uint8_t *buf; |
| 27670 | |
| 27671 | switch (duk_get_type(thr, 0)) { |
| 27672 | case DUK_TYPE_NUMBER: { |
| 27673 | len = duk_to_int_clamped(thr, 0, 0, DUK_INT_MAX); |
| 27674 | (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len); |
| 27675 | break; |
| 27676 | } |
| 27677 | case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */ |
| 27678 | goto slow_copy; |
| 27679 | } |
| 27680 | case DUK_TYPE_OBJECT: { |
| 27681 | duk_hobject *h; |
| 27682 | duk_hbufobj *h_bufobj; |
| 27683 | |
| 27684 | /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer |
| 27685 | * that shares allocated memory with the given ArrayBuffer." |
| 27686 | * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe |
| 27687 | */ |
| 27688 | |
| 27689 | h = duk_known_hobject(thr, 0); |
| 27690 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) { |
| 27691 | DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h)); |
| 27692 | h_bufobj = (duk_hbufobj *) h; |
| 27693 | if (DUK_UNLIKELY(h_bufobj->buf == NULL)) { |
| 27694 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 27695 | DUK_WO_NORETURN(return NULL;); |
| 27696 | } |
| 27697 | if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) { |
| 27698 | /* No support for ArrayBuffers with slice |
| 27699 | * offset/length. |
| 27700 | */ |
| 27701 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 27702 | DUK_WO_NORETURN(return NULL;); |
| 27703 | } |
| 27704 | duk_push_hbuffer(thr, h_bufobj->buf); |
| 27705 | return h_bufobj->buf; |
| 27706 | } |
| 27707 | goto slow_copy; |
| 27708 | } |
| 27709 | case DUK_TYPE_STRING: { |
| 27710 | /* ignore encoding for now */ |
| 27711 | duk_require_hstring_notsymbol(thr, 0); |
| 27712 | duk_dup_0(thr); |
| 27713 | (void) duk_to_buffer(thr, -1, &buf_size); |
| 27714 | break; |
| 27715 | } |
| 27716 | default: |
| 27717 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 27718 | DUK_WO_NORETURN(return NULL;); |
| 27719 | } |
| 27720 | |
| 27721 | done: |
| 27722 | DUK_ASSERT(duk_is_buffer(thr, -1)); |
| 27723 | return duk_known_hbuffer(thr, -1); |
| 27724 | |
| 27725 | slow_copy: |
| 27726 | /* XXX: fast path for typed arrays and other buffer objects? */ |
| 27727 | |
| 27728 | (void) duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH); |
| 27729 | len = duk_to_int_clamped(thr, -1, 0, DUK_INT_MAX); |
| 27730 | duk_pop(thr); |
| 27731 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len); /* no zeroing, all indices get initialized */ |
| 27732 | for (i = 0; i < len; i++) { |
| 27733 | /* XXX: fast path for array or buffer arguments? */ |
| 27734 | duk_get_prop_index(thr, 0, (duk_uarridx_t) i); |
| 27735 | buf[i] = (duk_uint8_t) (duk_to_uint32(thr, -1) & 0xffU); |
| 27736 | duk_pop(thr); |
| 27737 | } |
| 27738 | goto done; |
| 27739 | } |
| 27740 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 27741 | |
| 27742 | /* |
| 27743 | * Node.js Buffer constructor |
| 27744 | * |
| 27745 | * Node.js Buffers are just Uint8Arrays with internal prototype set to |
| 27746 | * Buffer.prototype so they're handled otherwise the same as Uint8Array. |
| 27747 | * However, the constructor arguments are very different so a separate |
| 27748 | * constructor entry point is used. |
| 27749 | */ |
| 27750 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 27751 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) { |
| 27752 | duk_hbuffer *h_buf; |
| 27753 | |
| 27754 | h_buf = duk__hbufobj_fixed_from_argvalue(thr); |
| 27755 | DUK_ASSERT(h_buf != NULL); |
| 27756 | |
| 27757 | duk_push_buffer_object(thr, |
| 27758 | -1, |
| 27759 | 0, |
| 27760 | DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) (void *) h_buf), |
| 27761 | DUK_BUFOBJ_UINT8ARRAY); |
| 27762 | duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); |
| 27763 | duk_set_prototype(thr, -2); |
| 27764 | |
| 27765 | /* XXX: a more direct implementation */ |
| 27766 | |
| 27767 | return 1; |
| 27768 | } |
| 27769 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 27770 | |
| 27771 | /* |
| 27772 | * ArrayBuffer, DataView, and TypedArray constructors |
| 27773 | */ |
| 27774 | |
| 27775 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 27776 | DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_hthread *thr) { |
| 27777 | duk_hbufobj *h_bufobj; |
| 27778 | duk_hbuffer *h_val; |
| 27779 | duk_int_t len; |
| 27780 | |
| 27781 | DUK_CTX_ASSERT_VALID(thr); |
| 27782 | |
| 27783 | duk_require_constructor_call(thr); |
| 27784 | |
| 27785 | len = duk_to_int(thr, 0); |
| 27786 | if (len < 0) { |
| 27787 | goto fail_length; |
| 27788 | } |
| 27789 | (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len); |
| 27790 | h_val = (duk_hbuffer *) duk_known_hbuffer(thr, -1); |
| 27791 | |
| 27792 | h_bufobj = duk_push_bufobj_raw(thr, |
| 27793 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 27794 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 27795 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), |
| 27796 | DUK_BIDX_ARRAYBUFFER_PROTOTYPE); |
| 27797 | DUK_ASSERT(h_bufobj != NULL); |
| 27798 | |
| 27799 | duk__set_bufobj_buffer(thr, h_bufobj, h_val); |
| 27800 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 27801 | |
| 27802 | return 1; |
| 27803 | |
| 27804 | fail_length: |
| 27805 | DUK_DCERROR_RANGE_INVALID_LENGTH(thr); |
| 27806 | } |
| 27807 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 27808 | |
| 27809 | |
| 27810 | /* Format of magic, bits: |
| 27811 | * 0...1: elem size shift (0-3) |
| 27812 | * 2...5: elem type (DUK_HBUFOBJ_ELEM_xxx) |
| 27813 | * |
| 27814 | * XXX: add prototype bidx explicitly to magic instead of using a mapping? |
| 27815 | */ |
| 27816 | |
| 27817 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 27818 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) { |
| 27819 | duk_tval *tv; |
| 27820 | duk_hobject *h_obj; |
| 27821 | duk_hbufobj *h_bufobj = NULL; |
| 27822 | duk_hbufobj *h_bufarg = NULL; |
| 27823 | duk_hbuffer *h_val; |
| 27824 | duk_small_uint_t magic; |
| 27825 | duk_small_uint_t shift; |
| 27826 | duk_small_uint_t elem_type; |
| 27827 | duk_small_uint_t elem_size; |
| 27828 | duk_small_uint_t class_num; |
| 27829 | duk_small_uint_t proto_bidx; |
| 27830 | duk_uint_t align_mask; |
| 27831 | duk_uint_t elem_length; |
| 27832 | duk_int_t elem_length_signed; |
| 27833 | duk_uint_t byte_length; |
| 27834 | duk_small_uint_t copy_mode; |
| 27835 | |
| 27836 | /* XXX: The same copy helpers could be shared with at least some |
| 27837 | * buffer functions. |
| 27838 | */ |
| 27839 | |
| 27840 | duk_require_constructor_call(thr); |
| 27841 | |
| 27842 | /* We could fit built-in index into magic but that'd make the magic |
| 27843 | * number dependent on built-in numbering (genbuiltins.py doesn't |
| 27844 | * handle that yet). So map both class and prototype from the |
| 27845 | * element type. |
| 27846 | */ |
| 27847 | magic = (duk_small_uint_t) duk_get_current_magic(thr); |
| 27848 | shift = magic & 0x03U; /* bits 0...1: shift */ |
| 27849 | elem_type = (magic >> 2) & 0x0fU; /* bits 2...5: type */ |
| 27850 | elem_size = 1U << shift; |
| 27851 | align_mask = elem_size - 1; |
| 27852 | DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t)); |
| 27853 | proto_bidx = duk__buffer_proto_from_elemtype[elem_type]; |
| 27854 | DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS); |
| 27855 | DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t)); |
| 27856 | class_num = duk__buffer_class_from_elemtype[elem_type]; |
| 27857 | |
| 27858 | DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, " |
| 27859 | "elem_size=%d, proto_bidx=%d, class_num=%d" , |
| 27860 | (int) magic, (int) shift, (int) elem_type, (int) elem_size, |
| 27861 | (int) proto_bidx, (int) class_num)); |
| 27862 | |
| 27863 | /* Argument variants. When the argument is an ArrayBuffer a view to |
| 27864 | * the same buffer is created; otherwise a new ArrayBuffer is always |
| 27865 | * created. |
| 27866 | */ |
| 27867 | |
| 27868 | /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer: |
| 27869 | * coerce to an ArrayBuffer object and use that as .buffer. The underlying |
| 27870 | * buffer will be the same but result .buffer !== inputPlainBuffer. |
| 27871 | */ |
| 27872 | duk_hbufobj_promote_plain(thr, 0); |
| 27873 | |
| 27874 | tv = duk_get_tval(thr, 0); |
| 27875 | DUK_ASSERT(tv != NULL); /* arg count */ |
| 27876 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 27877 | h_obj = DUK_TVAL_GET_OBJECT(tv); |
| 27878 | DUK_ASSERT(h_obj != NULL); |
| 27879 | |
| 27880 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) { |
| 27881 | /* ArrayBuffer: unlike any other argument variant, create |
| 27882 | * a view into the existing buffer. |
| 27883 | */ |
| 27884 | |
| 27885 | duk_int_t byte_offset_signed; |
| 27886 | duk_uint_t byte_offset; |
| 27887 | |
| 27888 | h_bufarg = (duk_hbufobj *) h_obj; |
| 27889 | |
| 27890 | byte_offset_signed = duk_to_int(thr, 1); |
| 27891 | if (byte_offset_signed < 0) { |
| 27892 | goto fail_arguments; |
| 27893 | } |
| 27894 | byte_offset = (duk_uint_t) byte_offset_signed; |
| 27895 | if (byte_offset > h_bufarg->length || |
| 27896 | (byte_offset & align_mask) != 0) { |
| 27897 | /* Must be >= 0 and multiple of element size. */ |
| 27898 | goto fail_arguments; |
| 27899 | } |
| 27900 | if (duk_is_undefined(thr, 2)) { |
| 27901 | DUK_ASSERT(h_bufarg->length >= byte_offset); |
| 27902 | byte_length = h_bufarg->length - byte_offset; |
| 27903 | if ((byte_length & align_mask) != 0) { |
| 27904 | /* Must be element size multiple from |
| 27905 | * start offset to end of buffer. |
| 27906 | */ |
| 27907 | goto fail_arguments; |
| 27908 | } |
| 27909 | elem_length = (byte_length >> shift); |
| 27910 | } else { |
| 27911 | elem_length_signed = duk_to_int(thr, 2); |
| 27912 | if (elem_length_signed < 0) { |
| 27913 | goto fail_arguments; |
| 27914 | } |
| 27915 | elem_length = (duk_uint_t) elem_length_signed; |
| 27916 | byte_length = elem_length << shift; |
| 27917 | if ((byte_length >> shift) != elem_length) { |
| 27918 | /* Byte length would overflow. */ |
| 27919 | /* XXX: easier check with less code? */ |
| 27920 | goto fail_arguments; |
| 27921 | } |
| 27922 | DUK_ASSERT(h_bufarg->length >= byte_offset); |
| 27923 | if (byte_length > h_bufarg->length - byte_offset) { |
| 27924 | /* Not enough data. */ |
| 27925 | goto fail_arguments; |
| 27926 | } |
| 27927 | } |
| 27928 | DUK_UNREF(elem_length); |
| 27929 | DUK_ASSERT_DISABLE(byte_offset >= 0); |
| 27930 | DUK_ASSERT(byte_offset <= h_bufarg->length); |
| 27931 | DUK_ASSERT_DISABLE(byte_length >= 0); |
| 27932 | DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length); |
| 27933 | DUK_ASSERT((elem_length << shift) == byte_length); |
| 27934 | |
| 27935 | h_bufobj = duk_push_bufobj_raw(thr, |
| 27936 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 27937 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 27938 | DUK_HOBJECT_CLASS_AS_FLAGS(class_num), |
| 27939 | (duk_small_int_t) proto_bidx); |
| 27940 | h_val = h_bufarg->buf; |
| 27941 | if (h_val == NULL) { |
| 27942 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 27943 | } |
| 27944 | h_bufobj->buf = h_val; |
| 27945 | DUK_HBUFFER_INCREF(thr, h_val); |
| 27946 | h_bufobj->offset = h_bufarg->offset + byte_offset; |
| 27947 | h_bufobj->length = byte_length; |
| 27948 | h_bufobj->shift = (duk_uint8_t) shift; |
| 27949 | h_bufobj->elem_type = (duk_uint8_t) elem_type; |
| 27950 | h_bufobj->is_typedarray = 1; |
| 27951 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 27952 | |
| 27953 | /* Set .buffer to the argument ArrayBuffer. */ |
| 27954 | DUK_ASSERT(h_bufobj->buf_prop == NULL); |
| 27955 | h_bufobj->buf_prop = (duk_hobject *) h_bufarg; |
| 27956 | DUK_ASSERT(h_bufarg != NULL); |
| 27957 | DUK_HBUFOBJ_INCREF(thr, h_bufarg); |
| 27958 | return 1; |
| 27959 | } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { |
| 27960 | /* TypedArray (or other non-ArrayBuffer duk_hbufobj). |
| 27961 | * Conceptually same behavior as for an Array-like argument, |
| 27962 | * with a few fast paths. |
| 27963 | */ |
| 27964 | |
| 27965 | h_bufarg = (duk_hbufobj *) h_obj; |
| 27966 | DUK_HBUFOBJ_ASSERT_VALID(h_bufarg); |
| 27967 | elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift); |
| 27968 | if (h_bufarg->buf == NULL) { |
| 27969 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 27970 | } |
| 27971 | |
| 27972 | /* Select copy mode. Must take into account element |
| 27973 | * compatibility and validity of the underlying source |
| 27974 | * buffer. |
| 27975 | */ |
| 27976 | |
| 27977 | DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, " |
| 27978 | "src byte_length=%ld, src shift=%d, " |
| 27979 | "src/dst elem_length=%ld; " |
| 27980 | "dst shift=%d -> dst byte_length=%ld" , |
| 27981 | (long) h_bufarg->length, (int) h_bufarg->shift, |
| 27982 | (long) elem_length_signed, (int) shift, |
| 27983 | (long) (elem_length_signed << shift))); |
| 27984 | |
| 27985 | copy_mode = 2; /* default is explicit index read/write copy */ |
| 27986 | #if !defined(DUK_USE_PREFER_SIZE) |
| 27987 | /* With a size optimized build copy_mode 2 is enough. |
| 27988 | * Modes 0 and 1 are faster but conceptually the same. |
| 27989 | */ |
| 27990 | DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); |
| 27991 | if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) { |
| 27992 | if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) { |
| 27993 | DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy" )); |
| 27994 | DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */ |
| 27995 | copy_mode = 0; |
| 27996 | } else { |
| 27997 | DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy" )); |
| 27998 | copy_mode = 1; |
| 27999 | } |
| 28000 | } |
| 28001 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 28002 | } else { |
| 28003 | /* Array or Array-like */ |
| 28004 | elem_length_signed = (duk_int_t) duk_get_length(thr, 0); |
| 28005 | copy_mode = 2; |
| 28006 | } |
| 28007 | } else { |
| 28008 | /* Non-object argument is simply int coerced, matches |
| 28009 | * V8 behavior (except for "null", which we coerce to |
| 28010 | * 0 but V8 TypeErrors). |
| 28011 | */ |
| 28012 | elem_length_signed = duk_to_int(thr, 0); |
| 28013 | copy_mode = 3; |
| 28014 | } |
| 28015 | if (elem_length_signed < 0) { |
| 28016 | goto fail_arguments; |
| 28017 | } |
| 28018 | elem_length = (duk_uint_t) elem_length_signed; |
| 28019 | byte_length = (duk_uint_t) (elem_length << shift); |
| 28020 | if ((byte_length >> shift) != elem_length) { |
| 28021 | /* Byte length would overflow. */ |
| 28022 | /* XXX: easier check with less code? */ |
| 28023 | goto fail_arguments; |
| 28024 | } |
| 28025 | |
| 28026 | DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld" , |
| 28027 | (long) elem_length, (long) byte_length)); |
| 28028 | |
| 28029 | /* ArrayBuffer argument is handled specially above; the rest of the |
| 28030 | * argument variants are handled by shared code below. |
| 28031 | * |
| 28032 | * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset. |
| 28033 | * It will be automatically created by the .buffer accessor on |
| 28034 | * first access. |
| 28035 | */ |
| 28036 | |
| 28037 | /* Push the resulting view object on top of a plain fixed buffer. */ |
| 28038 | (void) duk_push_fixed_buffer(thr, byte_length); |
| 28039 | h_val = duk_known_hbuffer(thr, -1); |
| 28040 | DUK_ASSERT(h_val != NULL); |
| 28041 | |
| 28042 | h_bufobj = duk_push_bufobj_raw(thr, |
| 28043 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 28044 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 28045 | DUK_HOBJECT_CLASS_AS_FLAGS(class_num), |
| 28046 | (duk_small_int_t) proto_bidx); |
| 28047 | |
| 28048 | h_bufobj->buf = h_val; |
| 28049 | DUK_HBUFFER_INCREF(thr, h_val); |
| 28050 | DUK_ASSERT(h_bufobj->offset == 0); |
| 28051 | h_bufobj->length = byte_length; |
| 28052 | h_bufobj->shift = (duk_uint8_t) shift; |
| 28053 | h_bufobj->elem_type = (duk_uint8_t) elem_type; |
| 28054 | h_bufobj->is_typedarray = 1; |
| 28055 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 28056 | |
| 28057 | /* Copy values, the copy method depends on the arguments. |
| 28058 | * |
| 28059 | * Copy mode decision may depend on the validity of the underlying |
| 28060 | * buffer of the source argument; there must be no harmful side effects |
| 28061 | * from there to here for copy_mode to still be valid. |
| 28062 | */ |
| 28063 | DUK_DDD(DUK_DDDPRINT("copy mode: %d" , (int) copy_mode)); |
| 28064 | switch (copy_mode) { |
| 28065 | /* Copy modes 0 and 1 can be omitted in size optimized build, |
| 28066 | * copy mode 2 handles them (but more slowly). |
| 28067 | */ |
| 28068 | #if !defined(DUK_USE_PREFER_SIZE) |
| 28069 | case 0: { |
| 28070 | /* Use byte copy. */ |
| 28071 | |
| 28072 | duk_uint8_t *p_src; |
| 28073 | duk_uint8_t *p_dst; |
| 28074 | |
| 28075 | DUK_ASSERT(h_bufobj != NULL); |
| 28076 | DUK_ASSERT(h_bufobj->buf != NULL); |
| 28077 | DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj)); |
| 28078 | DUK_ASSERT(h_bufarg != NULL); |
| 28079 | DUK_ASSERT(h_bufarg->buf != NULL); |
| 28080 | DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg)); |
| 28081 | |
| 28082 | p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj); |
| 28083 | p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); |
| 28084 | |
| 28085 | DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld" , |
| 28086 | (void *) p_src, (void *) p_dst, (long) byte_length)); |
| 28087 | |
| 28088 | duk_memcpy_unsafe((void *) p_dst, (const void *) p_src, (size_t) byte_length); |
| 28089 | break; |
| 28090 | } |
| 28091 | case 1: { |
| 28092 | /* Copy values through direct validated reads and writes. */ |
| 28093 | |
| 28094 | duk_small_uint_t src_elem_size; |
| 28095 | duk_small_uint_t dst_elem_size; |
| 28096 | duk_uint8_t *p_src; |
| 28097 | duk_uint8_t *p_src_end; |
| 28098 | duk_uint8_t *p_dst; |
| 28099 | |
| 28100 | DUK_ASSERT(h_bufobj != NULL); |
| 28101 | DUK_ASSERT(h_bufobj->buf != NULL); |
| 28102 | DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj)); |
| 28103 | DUK_ASSERT(h_bufarg != NULL); |
| 28104 | DUK_ASSERT(h_bufarg->buf != NULL); |
| 28105 | DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg)); |
| 28106 | |
| 28107 | src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift); |
| 28108 | dst_elem_size = elem_size; |
| 28109 | |
| 28110 | p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); |
| 28111 | p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj); |
| 28112 | p_src_end = p_src + h_bufarg->length; |
| 28113 | |
| 28114 | DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, " |
| 28115 | "src_elem_size=%d, dst_elem_size=%d" , |
| 28116 | (void *) p_src, (void *) p_src_end, (void *) p_dst, |
| 28117 | (int) src_elem_size, (int) dst_elem_size)); |
| 28118 | |
| 28119 | while (p_src != p_src_end) { |
| 28120 | DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: " |
| 28121 | "p_src=%p, p_src_end=%p, p_dst=%p" , |
| 28122 | (void *) p_src, (void *) p_src_end, (void *) p_dst)); |
| 28123 | /* A validated read() is always a number, so it's write coercion |
| 28124 | * is always side effect free an won't invalidate pointers etc. |
| 28125 | */ |
| 28126 | duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size); |
| 28127 | duk_hbufobj_validated_write(thr, h_bufobj, p_dst, dst_elem_size); |
| 28128 | duk_pop(thr); |
| 28129 | p_src += src_elem_size; |
| 28130 | p_dst += dst_elem_size; |
| 28131 | } |
| 28132 | break; |
| 28133 | } |
| 28134 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 28135 | case 2: { |
| 28136 | /* Copy values by index reads and writes. Let virtual |
| 28137 | * property handling take care of coercion. |
| 28138 | */ |
| 28139 | duk_uint_t i; |
| 28140 | |
| 28141 | DUK_DDD(DUK_DDDPRINT("using slow copy" )); |
| 28142 | |
| 28143 | for (i = 0; i < elem_length; i++) { |
| 28144 | duk_get_prop_index(thr, 0, (duk_uarridx_t) i); |
| 28145 | duk_put_prop_index(thr, -2, (duk_uarridx_t) i); |
| 28146 | } |
| 28147 | break; |
| 28148 | } |
| 28149 | default: |
| 28150 | case 3: { |
| 28151 | /* No copy, leave zero bytes in the buffer. There's no |
| 28152 | * ambiguity with Float32/Float64 because zero bytes also |
| 28153 | * represent 0.0. |
| 28154 | */ |
| 28155 | |
| 28156 | DUK_DDD(DUK_DDDPRINT("using no copy" )); |
| 28157 | break; |
| 28158 | } |
| 28159 | } |
| 28160 | |
| 28161 | return 1; |
| 28162 | |
| 28163 | fail_arguments: |
| 28164 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 28165 | } |
| 28166 | #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28167 | /* When bufferobject support is disabled, new Uint8Array() could still be |
| 28168 | * supported to create a plain fixed buffer. Disabled for now. |
| 28169 | */ |
| 28170 | #if 0 |
| 28171 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) { |
| 28172 | duk_int_t elem_length_signed; |
| 28173 | duk_uint_t byte_length; |
| 28174 | |
| 28175 | /* XXX: The same copy helpers could be shared with at least some |
| 28176 | * buffer functions. |
| 28177 | */ |
| 28178 | |
| 28179 | duk_require_constructor_call(thr); |
| 28180 | |
| 28181 | elem_length_signed = duk_require_int(thr, 0); |
| 28182 | if (elem_length_signed < 0) { |
| 28183 | goto fail_arguments; |
| 28184 | } |
| 28185 | byte_length = (duk_uint_t) elem_length_signed; |
| 28186 | |
| 28187 | (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) byte_length); |
| 28188 | return 1; |
| 28189 | |
| 28190 | fail_arguments: |
| 28191 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 28192 | } |
| 28193 | #endif /* 0 */ |
| 28194 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28195 | |
| 28196 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28197 | DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_hthread *thr) { |
| 28198 | duk_hbufobj *h_bufarg; |
| 28199 | duk_hbufobj *h_bufobj; |
| 28200 | duk_hbuffer *h_val; |
| 28201 | duk_uint_t offset; |
| 28202 | duk_uint_t length; |
| 28203 | |
| 28204 | duk_require_constructor_call(thr); |
| 28205 | |
| 28206 | h_bufarg = duk__require_bufobj_value(thr, 0); |
| 28207 | DUK_ASSERT(h_bufarg != NULL); |
| 28208 | if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) { |
| 28209 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 28210 | } |
| 28211 | |
| 28212 | duk__resolve_offset_opt_length(thr, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/); |
| 28213 | DUK_ASSERT(offset <= h_bufarg->length); |
| 28214 | DUK_ASSERT(offset + length <= h_bufarg->length); |
| 28215 | |
| 28216 | h_bufobj = duk_push_bufobj_raw(thr, |
| 28217 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 28218 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 28219 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW), |
| 28220 | DUK_BIDX_DATAVIEW_PROTOTYPE); |
| 28221 | |
| 28222 | h_val = h_bufarg->buf; |
| 28223 | if (h_val == NULL) { |
| 28224 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 28225 | } |
| 28226 | h_bufobj->buf = h_val; |
| 28227 | DUK_HBUFFER_INCREF(thr, h_val); |
| 28228 | h_bufobj->offset = h_bufarg->offset + offset; |
| 28229 | h_bufobj->length = length; |
| 28230 | DUK_ASSERT(h_bufobj->shift == 0); |
| 28231 | DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8); |
| 28232 | DUK_ASSERT(h_bufobj->is_typedarray == 0); |
| 28233 | |
| 28234 | DUK_ASSERT(h_bufobj->buf_prop == NULL); |
| 28235 | h_bufobj->buf_prop = (duk_hobject *) h_bufarg; |
| 28236 | DUK_ASSERT(h_bufarg != NULL); |
| 28237 | DUK_HBUFOBJ_INCREF(thr, h_bufarg); |
| 28238 | |
| 28239 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 28240 | return 1; |
| 28241 | } |
| 28242 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28243 | |
| 28244 | /* |
| 28245 | * ArrayBuffer.isView() |
| 28246 | */ |
| 28247 | |
| 28248 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28249 | DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_hthread *thr) { |
| 28250 | duk_hobject *h_obj; |
| 28251 | duk_bool_t ret = 0; |
| 28252 | |
| 28253 | if (duk_is_buffer(thr, 0)) { |
| 28254 | ret = 1; |
| 28255 | } else { |
| 28256 | h_obj = duk_get_hobject(thr, 0); |
| 28257 | if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) { |
| 28258 | /* DataView needs special casing: ArrayBuffer.isView() is |
| 28259 | * true, but ->is_typedarray is 0. |
| 28260 | */ |
| 28261 | ret = ((duk_hbufobj *) h_obj)->is_typedarray || |
| 28262 | (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW); |
| 28263 | } |
| 28264 | } |
| 28265 | duk_push_boolean(thr, ret); |
| 28266 | return 1; |
| 28267 | } |
| 28268 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28269 | |
| 28270 | /* |
| 28271 | * Uint8Array.allocPlain() |
| 28272 | */ |
| 28273 | |
| 28274 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28275 | DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_hthread *thr) { |
| 28276 | duk__hbufobj_fixed_from_argvalue(thr); |
| 28277 | return 1; |
| 28278 | } |
| 28279 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28280 | |
| 28281 | /* |
| 28282 | * Uint8Array.plainOf() |
| 28283 | */ |
| 28284 | |
| 28285 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28286 | DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_hthread *thr) { |
| 28287 | duk_hbufobj *h_bufobj; |
| 28288 | |
| 28289 | #if !defined(DUK_USE_PREFER_SIZE) |
| 28290 | /* Avoid churn if argument is already a plain buffer. */ |
| 28291 | if (duk_is_buffer(thr, 0)) { |
| 28292 | return 1; |
| 28293 | } |
| 28294 | #endif |
| 28295 | |
| 28296 | /* Promotes plain buffers to ArrayBuffers, so for a plain buffer |
| 28297 | * argument we'll create a pointless temporary (but still work |
| 28298 | * correctly). |
| 28299 | */ |
| 28300 | h_bufobj = duk__require_bufobj_value(thr, 0); |
| 28301 | if (h_bufobj->buf == NULL) { |
| 28302 | duk_push_undefined(thr); |
| 28303 | } else { |
| 28304 | duk_push_hbuffer(thr, h_bufobj->buf); |
| 28305 | } |
| 28306 | return 1; |
| 28307 | } |
| 28308 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28309 | |
| 28310 | /* |
| 28311 | * Node.js Buffer: toString([encoding], [start], [end]) |
| 28312 | */ |
| 28313 | |
| 28314 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28315 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) { |
| 28316 | duk_hbufobj *h_this; |
| 28317 | duk_int_t start_offset, end_offset; |
| 28318 | duk_uint8_t *buf_slice; |
| 28319 | duk_size_t slice_length; |
| 28320 | |
| 28321 | h_this = duk__get_bufobj_this(thr); |
| 28322 | if (h_this == NULL) { |
| 28323 | /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */ |
| 28324 | duk_push_literal(thr, "[object Object]" ); |
| 28325 | return 1; |
| 28326 | } |
| 28327 | DUK_HBUFOBJ_ASSERT_VALID(h_this); |
| 28328 | |
| 28329 | /* Ignore encoding for now. */ |
| 28330 | |
| 28331 | duk__clamp_startend_nonegidx_noshift(thr, |
| 28332 | (duk_int_t) h_this->length, |
| 28333 | 1 /*idx_start*/, |
| 28334 | 2 /*idx_end*/, |
| 28335 | &start_offset, |
| 28336 | &end_offset); |
| 28337 | |
| 28338 | slice_length = (duk_size_t) (end_offset - start_offset); |
| 28339 | buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, slice_length); /* all bytes initialized below */ |
| 28340 | DUK_ASSERT(buf_slice != NULL); |
| 28341 | |
| 28342 | /* Neutered or uncovered, TypeError. */ |
| 28343 | if (h_this->buf == NULL || |
| 28344 | !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)) { |
| 28345 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 28346 | } |
| 28347 | |
| 28348 | /* XXX: ideally we wouldn't make a copy but a view into the buffer for the |
| 28349 | * decoding process. Or the decoding helper could be changed to accept |
| 28350 | * the slice info (a buffer pointer is NOT a good approach because guaranteeing |
| 28351 | * its stability is difficult). |
| 28352 | */ |
| 28353 | |
| 28354 | DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)); |
| 28355 | duk_memcpy_unsafe((void *) buf_slice, |
| 28356 | (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), |
| 28357 | (size_t) slice_length); |
| 28358 | |
| 28359 | /* Use the equivalent of: new TextEncoder().encode(this) to convert the |
| 28360 | * string. Result will be valid UTF-8; non-CESU-8 inputs are currently |
| 28361 | * interpreted loosely. Value stack convention is a bit odd for now. |
| 28362 | */ |
| 28363 | duk_replace(thr, 0); |
| 28364 | duk_set_top(thr, 1); |
| 28365 | return duk_textdecoder_decode_utf8_nodejs(thr); |
| 28366 | } |
| 28367 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28368 | |
| 28369 | /* |
| 28370 | * Node.js Buffer.prototype: toJSON() |
| 28371 | */ |
| 28372 | |
| 28373 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28374 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_hthread *thr) { |
| 28375 | duk_hbufobj *h_this; |
| 28376 | duk_uint8_t *buf; |
| 28377 | duk_uint_t i, n; |
| 28378 | duk_tval *tv; |
| 28379 | |
| 28380 | h_this = duk__require_bufobj_this(thr); |
| 28381 | DUK_ASSERT(h_this != NULL); |
| 28382 | |
| 28383 | if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) { |
| 28384 | /* Serialize uncovered backing buffer as a null; doesn't |
| 28385 | * really matter as long we're memory safe. |
| 28386 | */ |
| 28387 | duk_push_null(thr); |
| 28388 | return 1; |
| 28389 | } |
| 28390 | |
| 28391 | duk_push_object(thr); |
| 28392 | duk_push_hstring_stridx(thr, DUK_STRIDX_UC_BUFFER); |
| 28393 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_TYPE); |
| 28394 | |
| 28395 | /* XXX: uninitialized would be OK */ |
| 28396 | DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX); |
| 28397 | tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */ |
| 28398 | DUK_ASSERT(!duk_is_bare_object(thr, -1)); |
| 28399 | |
| 28400 | DUK_ASSERT(h_this->buf != NULL); |
| 28401 | buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); |
| 28402 | for (i = 0, n = h_this->length; i < n; i++) { |
| 28403 | DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */ |
| 28404 | } |
| 28405 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_DATA); |
| 28406 | |
| 28407 | return 1; |
| 28408 | } |
| 28409 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28410 | |
| 28411 | /* |
| 28412 | * Node.js Buffer.prototype.equals() |
| 28413 | * Node.js Buffer.prototype.compare() |
| 28414 | * Node.js Buffer.compare() |
| 28415 | */ |
| 28416 | |
| 28417 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28418 | DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_hthread *thr) { |
| 28419 | duk_small_uint_t magic; |
| 28420 | duk_hbufobj *h_bufarg1; |
| 28421 | duk_hbufobj *h_bufarg2; |
| 28422 | duk_small_int_t comp_res; |
| 28423 | |
| 28424 | /* XXX: keep support for plain buffers and non-Node.js buffers? */ |
| 28425 | |
| 28426 | magic = (duk_small_uint_t) duk_get_current_magic(thr); |
| 28427 | if (magic & 0x02U) { |
| 28428 | /* Static call style. */ |
| 28429 | h_bufarg1 = duk__require_bufobj_value(thr, 0); |
| 28430 | h_bufarg2 = duk__require_bufobj_value(thr, 1); |
| 28431 | } else { |
| 28432 | h_bufarg1 = duk__require_bufobj_this(thr); |
| 28433 | h_bufarg2 = duk__require_bufobj_value(thr, 0); |
| 28434 | } |
| 28435 | DUK_ASSERT(h_bufarg1 != NULL); |
| 28436 | DUK_ASSERT(h_bufarg2 != NULL); |
| 28437 | |
| 28438 | /* We want to compare the slice/view areas of the arguments. |
| 28439 | * If either slice/view is invalid (underlying buffer is shorter) |
| 28440 | * ensure equals() is false, but otherwise the only thing that |
| 28441 | * matters is to be memory safe. |
| 28442 | */ |
| 28443 | |
| 28444 | if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) && |
| 28445 | DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) { |
| 28446 | comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset, |
| 28447 | (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset, |
| 28448 | (duk_size_t) h_bufarg1->length, |
| 28449 | (duk_size_t) h_bufarg2->length); |
| 28450 | } else { |
| 28451 | comp_res = -1; /* either nonzero value is ok */ |
| 28452 | } |
| 28453 | |
| 28454 | if (magic & 0x01U) { |
| 28455 | /* compare: similar to string comparison but for buffer data. */ |
| 28456 | duk_push_int(thr, comp_res); |
| 28457 | } else { |
| 28458 | /* equals */ |
| 28459 | duk_push_boolean(thr, (comp_res == 0)); |
| 28460 | } |
| 28461 | |
| 28462 | return 1; |
| 28463 | } |
| 28464 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28465 | |
| 28466 | /* |
| 28467 | * Node.js Buffer.prototype.fill() |
| 28468 | */ |
| 28469 | |
| 28470 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28471 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) { |
| 28472 | duk_hbufobj *h_this; |
| 28473 | const duk_uint8_t *fill_str_ptr; |
| 28474 | duk_size_t fill_str_len; |
| 28475 | duk_uint8_t fill_value; |
| 28476 | duk_int_t fill_offset; |
| 28477 | duk_int_t fill_end; |
| 28478 | duk_size_t fill_length; |
| 28479 | duk_uint8_t *p; |
| 28480 | |
| 28481 | h_this = duk__require_bufobj_this(thr); |
| 28482 | DUK_ASSERT(h_this != NULL); |
| 28483 | if (h_this->buf == NULL) { |
| 28484 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 28485 | } |
| 28486 | |
| 28487 | /* [ value offset end ] */ |
| 28488 | |
| 28489 | if (duk_is_string_notsymbol(thr, 0)) { |
| 28490 | fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(thr, 0, &fill_str_len); |
| 28491 | DUK_ASSERT(fill_str_ptr != NULL); |
| 28492 | } else { |
| 28493 | /* Symbols get ToNumber() coerced and cause TypeError. */ |
| 28494 | fill_value = (duk_uint8_t) duk_to_uint32(thr, 0); |
| 28495 | fill_str_ptr = (const duk_uint8_t *) &fill_value; |
| 28496 | fill_str_len = 1; |
| 28497 | } |
| 28498 | |
| 28499 | /* Fill offset handling is more lenient than in Node.js. */ |
| 28500 | |
| 28501 | duk__clamp_startend_nonegidx_noshift(thr, |
| 28502 | (duk_int_t) h_this->length, |
| 28503 | 1 /*idx_start*/, |
| 28504 | 2 /*idx_end*/, |
| 28505 | &fill_offset, |
| 28506 | &fill_end); |
| 28507 | |
| 28508 | DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld" , |
| 28509 | (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length)); |
| 28510 | |
| 28511 | DUK_ASSERT(fill_end - fill_offset >= 0); |
| 28512 | DUK_ASSERT(h_this->buf != NULL); |
| 28513 | |
| 28514 | p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset); |
| 28515 | fill_length = (duk_size_t) (fill_end - fill_offset); |
| 28516 | if (fill_str_len == 1) { |
| 28517 | /* Handle single character fills as memset() even when |
| 28518 | * the fill data comes from a one-char argument. |
| 28519 | */ |
| 28520 | duk_memset_unsafe((void *) p, (int) fill_str_ptr[0], (size_t) fill_length); |
| 28521 | } else if (fill_str_len > 1) { |
| 28522 | duk_size_t i, n, t; |
| 28523 | |
| 28524 | for (i = 0, n = (duk_size_t) (fill_end - fill_offset), t = 0; i < n; i++) { |
| 28525 | p[i] = fill_str_ptr[t++]; |
| 28526 | if (t >= fill_str_len) { |
| 28527 | t = 0; |
| 28528 | } |
| 28529 | } |
| 28530 | } else { |
| 28531 | DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently" )); |
| 28532 | } |
| 28533 | |
| 28534 | /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */ |
| 28535 | duk_push_this(thr); |
| 28536 | return 1; |
| 28537 | } |
| 28538 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28539 | |
| 28540 | /* |
| 28541 | * Node.js Buffer.prototype.write(string, [offset], [length], [encoding]) |
| 28542 | */ |
| 28543 | |
| 28544 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28545 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) { |
| 28546 | duk_hbufobj *h_this; |
| 28547 | duk_uint_t offset; |
| 28548 | duk_uint_t length; |
| 28549 | const duk_uint8_t *str_data; |
| 28550 | duk_size_t str_len; |
| 28551 | |
| 28552 | /* XXX: very inefficient support for plain buffers */ |
| 28553 | h_this = duk__require_bufobj_this(thr); |
| 28554 | DUK_ASSERT(h_this != NULL); |
| 28555 | |
| 28556 | /* Argument must be a string, e.g. a buffer is not allowed. */ |
| 28557 | str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(thr, 0, &str_len); |
| 28558 | |
| 28559 | duk__resolve_offset_opt_length(thr, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/); |
| 28560 | DUK_ASSERT(offset <= h_this->length); |
| 28561 | DUK_ASSERT(offset + length <= h_this->length); |
| 28562 | |
| 28563 | /* XXX: encoding is ignored now. */ |
| 28564 | |
| 28565 | if (length > str_len) { |
| 28566 | length = (duk_uint_t) str_len; |
| 28567 | } |
| 28568 | |
| 28569 | if (DUK_HBUFOBJ_VALID_SLICE(h_this)) { |
| 28570 | /* Cannot overlap. */ |
| 28571 | duk_memcpy_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset), |
| 28572 | (const void *) str_data, |
| 28573 | (size_t) length); |
| 28574 | } else { |
| 28575 | DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore" )); |
| 28576 | } |
| 28577 | |
| 28578 | duk_push_uint(thr, length); |
| 28579 | return 1; |
| 28580 | } |
| 28581 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28582 | |
| 28583 | /* |
| 28584 | * Node.js Buffer.prototype.copy() |
| 28585 | */ |
| 28586 | |
| 28587 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28588 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) { |
| 28589 | duk_hbufobj *h_this; |
| 28590 | duk_hbufobj *h_bufarg; |
| 28591 | duk_int_t source_length; |
| 28592 | duk_int_t target_length; |
| 28593 | duk_int_t target_start, source_start, source_end; |
| 28594 | duk_uint_t target_ustart, source_ustart, source_uend; |
| 28595 | duk_uint_t copy_size = 0; |
| 28596 | |
| 28597 | /* [ targetBuffer targetStart sourceStart sourceEnd ] */ |
| 28598 | |
| 28599 | h_this = duk__require_bufobj_this(thr); |
| 28600 | h_bufarg = duk__require_bufobj_value(thr, 0); |
| 28601 | DUK_ASSERT(h_this != NULL); |
| 28602 | DUK_ASSERT(h_bufarg != NULL); |
| 28603 | source_length = (duk_int_t) h_this->length; |
| 28604 | target_length = (duk_int_t) h_bufarg->length; |
| 28605 | |
| 28606 | target_start = duk_to_int(thr, 1); |
| 28607 | source_start = duk_to_int(thr, 2); |
| 28608 | if (duk_is_undefined(thr, 3)) { |
| 28609 | source_end = source_length; |
| 28610 | } else { |
| 28611 | source_end = duk_to_int(thr, 3); |
| 28612 | } |
| 28613 | |
| 28614 | DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, " |
| 28615 | "source_start=%ld, source_end=%ld, source_length=%ld" , |
| 28616 | (long) target_start, (long) h_bufarg->length, |
| 28617 | (long) source_start, (long) source_end, (long) source_length)); |
| 28618 | |
| 28619 | /* This behavior mostly mimics Node.js now. */ |
| 28620 | |
| 28621 | if (source_start < 0 || source_end < 0 || target_start < 0) { |
| 28622 | /* Negative offsets cause a RangeError. */ |
| 28623 | goto fail_bounds; |
| 28624 | } |
| 28625 | source_ustart = (duk_uint_t) source_start; |
| 28626 | source_uend = (duk_uint_t) source_end; |
| 28627 | target_ustart = (duk_uint_t) target_start; |
| 28628 | if (source_ustart >= source_uend || /* crossed offsets or zero size */ |
| 28629 | source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */ |
| 28630 | target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */ |
| 28631 | goto silent_ignore; |
| 28632 | } |
| 28633 | if (source_uend >= (duk_uint_t) source_length) { |
| 28634 | /* Source end clamped silently to available length. */ |
| 28635 | source_uend = (duk_uint_t) source_length; |
| 28636 | } |
| 28637 | copy_size = source_uend - source_ustart; |
| 28638 | if (target_ustart + copy_size > (duk_uint_t) target_length) { |
| 28639 | /* Clamp to target's end if too long. |
| 28640 | * |
| 28641 | * NOTE: there's no overflow possibility in the comparison; |
| 28642 | * both target_ustart and copy_size are >= 0 and based on |
| 28643 | * values in duk_int_t range. Adding them as duk_uint_t |
| 28644 | * values is then guaranteed not to overflow. |
| 28645 | */ |
| 28646 | DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */ |
| 28647 | DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */ |
| 28648 | copy_size = (duk_uint_t) target_length - target_ustart; |
| 28649 | } |
| 28650 | |
| 28651 | DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu" , |
| 28652 | (unsigned long) target_ustart, (unsigned long) source_ustart, |
| 28653 | (unsigned long) copy_size)); |
| 28654 | |
| 28655 | DUK_ASSERT(copy_size >= 1); |
| 28656 | DUK_ASSERT(source_ustart <= (duk_uint_t) source_length); |
| 28657 | DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length); |
| 28658 | DUK_ASSERT(target_ustart <= (duk_uint_t) target_length); |
| 28659 | DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length); |
| 28660 | |
| 28661 | /* Ensure copy is covered by underlying buffers. */ |
| 28662 | DUK_ASSERT(h_bufarg->buf != NULL); /* length check */ |
| 28663 | DUK_ASSERT(h_this->buf != NULL); /* length check */ |
| 28664 | if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) && |
| 28665 | DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) { |
| 28666 | /* Must use memmove() because copy area may overlap (source and target |
| 28667 | * buffer may be the same, or from different slices. |
| 28668 | */ |
| 28669 | duk_memmove_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart), |
| 28670 | (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart), |
| 28671 | (size_t) copy_size); |
| 28672 | } else { |
| 28673 | DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring" )); |
| 28674 | } |
| 28675 | |
| 28676 | silent_ignore: |
| 28677 | /* Return value is like write(), number of bytes written. |
| 28678 | * The return value matters because of code like: |
| 28679 | * "off += buf.copy(...)". |
| 28680 | */ |
| 28681 | duk_push_uint(thr, copy_size); |
| 28682 | return 1; |
| 28683 | |
| 28684 | fail_bounds: |
| 28685 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 28686 | } |
| 28687 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28688 | |
| 28689 | /* |
| 28690 | * TypedArray.prototype.set() |
| 28691 | * |
| 28692 | * TypedArray set() is pretty interesting to implement because: |
| 28693 | * |
| 28694 | * - The source argument may be a plain array or a typedarray. If the |
| 28695 | * source is a TypedArray, values are decoded and re-encoded into the |
| 28696 | * target (not as a plain byte copy). This may happen even when the |
| 28697 | * element byte size is the same, e.g. integer values may be re-encoded |
| 28698 | * into floats. |
| 28699 | * |
| 28700 | * - Source and target may refer to the same underlying buffer, so that |
| 28701 | * the set() operation may overlap. The specification requires that this |
| 28702 | * must work as if a copy was made before the operation. Note that this |
| 28703 | * is NOT a simple memmove() situation because the source and target |
| 28704 | * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may |
| 28705 | * expand to a 16-byte target (Uint32Array) so that the target overlaps |
| 28706 | * the source both from beginning and the end (unlike in typical memmove). |
| 28707 | * |
| 28708 | * - Even if 'buf' pointers of the source and target differ, there's no |
| 28709 | * guarantee that their memory areas don't overlap. This may be the |
| 28710 | * case with external buffers. |
| 28711 | * |
| 28712 | * Even so, it is nice to optimize for the common case: |
| 28713 | * |
| 28714 | * - Source and target separate buffers or non-overlapping. |
| 28715 | * |
| 28716 | * - Source and target have a compatible type so that a plain byte copy |
| 28717 | * is possible. Note that while e.g. uint8 and int8 are compatible |
| 28718 | * (coercion one way or another doesn't change the byte representation), |
| 28719 | * e.g. int8 and uint8clamped are NOT compatible when writing int8 |
| 28720 | * values into uint8clamped typedarray (-1 would clamp to 0 for instance). |
| 28721 | * |
| 28722 | * See test-bi-typedarray-proto-set.js. |
| 28723 | */ |
| 28724 | |
| 28725 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 28726 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) { |
| 28727 | duk_hbufobj *h_this; |
| 28728 | duk_hobject *h_obj; |
| 28729 | duk_uarridx_t i, n; |
| 28730 | duk_int_t offset_signed; |
| 28731 | duk_uint_t offset_elems; |
| 28732 | duk_uint_t offset_bytes; |
| 28733 | |
| 28734 | h_this = duk__require_bufobj_this(thr); |
| 28735 | DUK_ASSERT(h_this != NULL); |
| 28736 | DUK_HBUFOBJ_ASSERT_VALID(h_this); |
| 28737 | |
| 28738 | if (h_this->buf == NULL) { |
| 28739 | DUK_DDD(DUK_DDDPRINT("source neutered, skip copy" )); |
| 28740 | return 0; |
| 28741 | } |
| 28742 | |
| 28743 | duk_hbufobj_promote_plain(thr, 0); |
| 28744 | h_obj = duk_require_hobject(thr, 0); |
| 28745 | |
| 28746 | /* XXX: V8 throws a TypeError for negative values. Would it |
| 28747 | * be more useful to interpret negative offsets here from the |
| 28748 | * end of the buffer too? |
| 28749 | */ |
| 28750 | offset_signed = duk_to_int(thr, 1); |
| 28751 | if (offset_signed < 0) { |
| 28752 | /* For some reason this is a TypeError (at least in V8). */ |
| 28753 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 28754 | } |
| 28755 | offset_elems = (duk_uint_t) offset_signed; |
| 28756 | offset_bytes = offset_elems << h_this->shift; |
| 28757 | if ((offset_bytes >> h_this->shift) != offset_elems) { |
| 28758 | /* Byte length would overflow. */ |
| 28759 | /* XXX: easier check with less code? */ |
| 28760 | goto fail_args; |
| 28761 | } |
| 28762 | if (offset_bytes > h_this->length) { |
| 28763 | /* Equality may be OK but >length not. Checking |
| 28764 | * this explicitly avoids some overflow cases |
| 28765 | * below. |
| 28766 | */ |
| 28767 | goto fail_args; |
| 28768 | } |
| 28769 | DUK_ASSERT(offset_bytes <= h_this->length); |
| 28770 | |
| 28771 | /* Fast path: source is a TypedArray (or any bufobj). */ |
| 28772 | |
| 28773 | if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { |
| 28774 | duk_hbufobj *h_bufarg; |
| 28775 | #if !defined(DUK_USE_PREFER_SIZE) |
| 28776 | duk_uint16_t comp_mask; |
| 28777 | #endif |
| 28778 | duk_small_int_t no_overlap = 0; |
| 28779 | duk_uint_t src_length; |
| 28780 | duk_uint_t dst_length; |
| 28781 | duk_uint_t dst_length_elems; |
| 28782 | duk_uint8_t *p_src_base; |
| 28783 | duk_uint8_t *p_src_end; |
| 28784 | duk_uint8_t *p_src; |
| 28785 | duk_uint8_t *p_dst_base; |
| 28786 | duk_uint8_t *p_dst; |
| 28787 | duk_small_uint_t src_elem_size; |
| 28788 | duk_small_uint_t dst_elem_size; |
| 28789 | |
| 28790 | h_bufarg = (duk_hbufobj *) h_obj; |
| 28791 | DUK_HBUFOBJ_ASSERT_VALID(h_bufarg); |
| 28792 | |
| 28793 | if (h_bufarg->buf == NULL) { |
| 28794 | DUK_DDD(DUK_DDDPRINT("target neutered, skip copy" )); |
| 28795 | return 0; |
| 28796 | } |
| 28797 | |
| 28798 | /* Nominal size check. */ |
| 28799 | src_length = h_bufarg->length; /* bytes in source */ |
| 28800 | dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */ |
| 28801 | dst_length = dst_length_elems << h_this->shift; /* bytes in dest */ |
| 28802 | if ((dst_length >> h_this->shift) != dst_length_elems) { |
| 28803 | /* Byte length would overflow. */ |
| 28804 | /* XXX: easier check with less code? */ |
| 28805 | goto fail_args; |
| 28806 | } |
| 28807 | DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld" , |
| 28808 | (long) src_length, (long) dst_length)); |
| 28809 | DUK_ASSERT(offset_bytes <= h_this->length); |
| 28810 | if (dst_length > h_this->length - offset_bytes) { |
| 28811 | /* Overflow not an issue because subtraction is used on the right |
| 28812 | * side and guaranteed to be >= 0. |
| 28813 | */ |
| 28814 | DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length" )); |
| 28815 | goto fail_args; |
| 28816 | } |
| 28817 | if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) { |
| 28818 | DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore" )); |
| 28819 | return 0; |
| 28820 | } |
| 28821 | |
| 28822 | p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg); |
| 28823 | p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes; |
| 28824 | |
| 28825 | /* Check actual underlying buffers for validity and that they |
| 28826 | * cover the copy. No side effects are allowed after the check |
| 28827 | * so that the validity status doesn't change. |
| 28828 | */ |
| 28829 | if (!DUK_HBUFOBJ_VALID_SLICE(h_this) || |
| 28830 | !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) { |
| 28831 | /* The condition could be more narrow and check for the |
| 28832 | * copy area only, but there's no need for fine grained |
| 28833 | * behavior when the underlying buffer is misconfigured. |
| 28834 | */ |
| 28835 | DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy" )); |
| 28836 | return 0; |
| 28837 | } |
| 28838 | |
| 28839 | /* We want to do a straight memory copy if possible: this is |
| 28840 | * an important operation because .set() is the TypedArray |
| 28841 | * way to copy chunks of memory. However, because set() |
| 28842 | * conceptually works in terms of elements, not all views are |
| 28843 | * compatible with direct byte copying. |
| 28844 | * |
| 28845 | * If we do manage a direct copy, the "overlap issue" handled |
| 28846 | * below can just be solved using memmove() because the source |
| 28847 | * and destination element sizes are necessarily equal. |
| 28848 | */ |
| 28849 | |
| 28850 | #if !defined(DUK_USE_PREFER_SIZE) |
| 28851 | DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t)); |
| 28852 | comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type]; |
| 28853 | if (comp_mask & (1 << h_bufarg->elem_type)) { |
| 28854 | DUK_ASSERT(src_length == dst_length); |
| 28855 | |
| 28856 | DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible" )); |
| 28857 | duk_memmove_unsafe((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length); |
| 28858 | return 0; |
| 28859 | } |
| 28860 | DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item" )); |
| 28861 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 28862 | |
| 28863 | /* We want to avoid making a copy to process set() but that's |
| 28864 | * not always possible: the source and the target may overlap |
| 28865 | * and because element sizes are different, the overlap cannot |
| 28866 | * always be handled with a memmove() or choosing the copy |
| 28867 | * direction in a certain way. For example, if source type is |
| 28868 | * uint8 and target type is uint32, the target area may exceed |
| 28869 | * the source area from both ends! |
| 28870 | * |
| 28871 | * Note that because external buffers may point to the same |
| 28872 | * memory areas, we must ultimately make this check using |
| 28873 | * pointers. |
| 28874 | * |
| 28875 | * NOTE: careful with side effects: any side effect may cause |
| 28876 | * a buffer resize (or external buffer pointer/length update)! |
| 28877 | */ |
| 28878 | |
| 28879 | DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, " |
| 28880 | "p_dst_base=%p, dst_length=%ld" , |
| 28881 | (void *) p_src_base, (long) src_length, |
| 28882 | (void *) p_dst_base, (long) dst_length)); |
| 28883 | |
| 28884 | if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */ |
| 28885 | p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */ |
| 28886 | no_overlap = 1; |
| 28887 | } |
| 28888 | |
| 28889 | if (!no_overlap) { |
| 28890 | /* There's overlap: the desired end result is that |
| 28891 | * conceptually a copy is made to avoid "trampling" |
| 28892 | * of source data by destination writes. We make |
| 28893 | * an actual temporary copy to handle this case. |
| 28894 | */ |
| 28895 | duk_uint8_t *p_src_copy; |
| 28896 | |
| 28897 | DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source" )); |
| 28898 | p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length); |
| 28899 | DUK_ASSERT(p_src_copy != NULL); |
| 28900 | duk_memcpy_unsafe((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length); |
| 28901 | |
| 28902 | p_src_base = p_src_copy; /* use p_src_base from now on */ |
| 28903 | } |
| 28904 | /* Value stack intentionally mixed size here. */ |
| 28905 | |
| 28906 | DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, " |
| 28907 | "p_dst_base=%p, dst_length=%ld, valstack top=%ld" , |
| 28908 | (void *) p_src_base, (long) src_length, |
| 28909 | (void *) p_dst_base, (long) dst_length, |
| 28910 | (long) duk_get_top(thr))); |
| 28911 | |
| 28912 | /* Ready to make the copy. We must proceed element by element |
| 28913 | * and must avoid any side effects that might cause the buffer |
| 28914 | * validity check above to become invalid. |
| 28915 | * |
| 28916 | * Although we work through the value stack here, only plain |
| 28917 | * numbers are handled which should be side effect safe. |
| 28918 | */ |
| 28919 | |
| 28920 | src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift); |
| 28921 | dst_elem_size = (duk_small_uint_t) (1U << h_this->shift); |
| 28922 | p_src = p_src_base; |
| 28923 | p_dst = p_dst_base; |
| 28924 | p_src_end = p_src_base + src_length; |
| 28925 | |
| 28926 | while (p_src != p_src_end) { |
| 28927 | DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: " |
| 28928 | "p_src=%p, p_src_end=%p, p_dst=%p" , |
| 28929 | (void *) p_src, (void *) p_src_end, (void *) p_dst)); |
| 28930 | /* A validated read() is always a number, so it's write coercion |
| 28931 | * is always side effect free an won't invalidate pointers etc. |
| 28932 | */ |
| 28933 | duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size); |
| 28934 | duk_hbufobj_validated_write(thr, h_this, p_dst, dst_elem_size); |
| 28935 | duk_pop(thr); |
| 28936 | p_src += src_elem_size; |
| 28937 | p_dst += dst_elem_size; |
| 28938 | } |
| 28939 | |
| 28940 | return 0; |
| 28941 | } else { |
| 28942 | /* Slow path: quite slow, but we save space by using the property code |
| 28943 | * to write coerce target values. We don't need to worry about overlap |
| 28944 | * here because the source is not a TypedArray. |
| 28945 | * |
| 28946 | * We could use the bufobj write coercion helper but since the |
| 28947 | * property read may have arbitrary side effects, full validity checks |
| 28948 | * would be needed for every element anyway. |
| 28949 | */ |
| 28950 | |
| 28951 | n = (duk_uarridx_t) duk_get_length(thr, 0); |
| 28952 | DUK_ASSERT(offset_bytes <= h_this->length); |
| 28953 | if ((n << h_this->shift) > h_this->length - offset_bytes) { |
| 28954 | /* Overflow not an issue because subtraction is used on the right |
| 28955 | * side and guaranteed to be >= 0. |
| 28956 | */ |
| 28957 | DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length" )); |
| 28958 | goto fail_args; |
| 28959 | } |
| 28960 | |
| 28961 | /* There's no need to check for buffer validity status for the |
| 28962 | * target here: the property access code will do that for each |
| 28963 | * element. Moreover, if we did check the validity here, side |
| 28964 | * effects from reading the source argument might invalidate |
| 28965 | * the results anyway. |
| 28966 | */ |
| 28967 | |
| 28968 | DUK_ASSERT_TOP(thr, 2); |
| 28969 | duk_push_this(thr); |
| 28970 | |
| 28971 | for (i = 0; i < n; i++) { |
| 28972 | duk_get_prop_index(thr, 0, i); |
| 28973 | duk_put_prop_index(thr, 2, offset_elems + i); |
| 28974 | } |
| 28975 | } |
| 28976 | |
| 28977 | return 0; |
| 28978 | |
| 28979 | fail_args: |
| 28980 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 28981 | } |
| 28982 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 28983 | |
| 28984 | /* |
| 28985 | * Node.js Buffer.prototype.slice([start], [end]) |
| 28986 | * ArrayBuffer.prototype.slice(begin, [end]) |
| 28987 | * TypedArray.prototype.subarray(begin, [end]) |
| 28988 | * |
| 28989 | * The API calls are almost identical; negative indices are counted from end |
| 28990 | * of buffer, and final indices are clamped (allowing crossed indices). Main |
| 28991 | * differences: |
| 28992 | * |
| 28993 | * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create |
| 28994 | * views, ArrayBuffer .slice() creates a copy |
| 28995 | * |
| 28996 | * - Resulting object has a different class and prototype depending on the |
| 28997 | * call (or 'this' argument) |
| 28998 | * |
| 28999 | * - TypedArray .subarray() arguments are element indices, not byte offsets |
| 29000 | * |
| 29001 | * - Plain buffer argument creates a plain buffer slice |
| 29002 | */ |
| 29003 | |
| 29004 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29005 | DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val) { |
| 29006 | duk_int_t start_offset, end_offset; |
| 29007 | duk_uint_t slice_length; |
| 29008 | duk_uint8_t *p_copy; |
| 29009 | duk_size_t copy_length; |
| 29010 | |
| 29011 | duk__clamp_startend_negidx_shifted(thr, |
| 29012 | (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val), |
| 29013 | 0 /*buffer_shift*/, |
| 29014 | 0 /*idx_start*/, |
| 29015 | 1 /*idx_end*/, |
| 29016 | &start_offset, |
| 29017 | &end_offset); |
| 29018 | DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val)); |
| 29019 | DUK_ASSERT(start_offset >= 0); |
| 29020 | DUK_ASSERT(end_offset >= start_offset); |
| 29021 | slice_length = (duk_uint_t) (end_offset - start_offset); |
| 29022 | |
| 29023 | p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) slice_length); |
| 29024 | DUK_ASSERT(p_copy != NULL); |
| 29025 | copy_length = slice_length; |
| 29026 | |
| 29027 | duk_memcpy_unsafe((void *) p_copy, |
| 29028 | (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset), |
| 29029 | copy_length); |
| 29030 | } |
| 29031 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29032 | |
| 29033 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29034 | /* Shared helper for slice/subarray operation. |
| 29035 | * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling. |
| 29036 | */ |
| 29037 | DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) { |
| 29038 | duk_small_int_t magic; |
| 29039 | duk_small_uint_t res_class_num; |
| 29040 | duk_small_int_t res_proto_bidx; |
| 29041 | duk_hbufobj *h_this; |
| 29042 | duk_hbufobj *h_bufobj; |
| 29043 | duk_hbuffer *h_val; |
| 29044 | duk_int_t start_offset, end_offset; |
| 29045 | duk_uint_t slice_length; |
| 29046 | duk_tval *tv; |
| 29047 | |
| 29048 | /* [ start end ] */ |
| 29049 | |
| 29050 | magic = duk_get_current_magic(thr); |
| 29051 | |
| 29052 | tv = duk_get_borrowed_this_tval(thr); |
| 29053 | DUK_ASSERT(tv != NULL); |
| 29054 | |
| 29055 | if (DUK_TVAL_IS_BUFFER(tv)) { |
| 29056 | /* For plain buffers return a plain buffer slice. */ |
| 29057 | h_val = DUK_TVAL_GET_BUFFER(tv); |
| 29058 | DUK_ASSERT(h_val != NULL); |
| 29059 | |
| 29060 | if (magic & 0x02) { |
| 29061 | /* Make copy: ArrayBuffer.prototype.slice() uses this. */ |
| 29062 | duk__arraybuffer_plain_slice(thr, h_val); |
| 29063 | return 1; |
| 29064 | } else { |
| 29065 | /* View into existing buffer: cannot be done if the |
| 29066 | * result is a plain buffer because there's no slice |
| 29067 | * info. So return an ArrayBuffer instance; coerce |
| 29068 | * the 'this' binding into an object and behave as if |
| 29069 | * the original call was for an Object-coerced plain |
| 29070 | * buffer (handled automatically by duk__require_bufobj_this()). |
| 29071 | */ |
| 29072 | |
| 29073 | DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object" )); |
| 29074 | /* fall through */ |
| 29075 | } |
| 29076 | } |
| 29077 | tv = NULL; /* No longer valid nor needed. */ |
| 29078 | |
| 29079 | h_this = duk__require_bufobj_this(thr); |
| 29080 | |
| 29081 | /* Slice offsets are element (not byte) offsets, which only matters |
| 29082 | * for TypedArray views, Node.js Buffer and ArrayBuffer have shift |
| 29083 | * zero so byte and element offsets are the same. Negative indices |
| 29084 | * are counted from end of slice, crossed indices are allowed (and |
| 29085 | * result in zero length result), and final values are clamped |
| 29086 | * against the current slice. There's intentionally no check |
| 29087 | * against the underlying buffer here. |
| 29088 | */ |
| 29089 | |
| 29090 | duk__clamp_startend_negidx_shifted(thr, |
| 29091 | (duk_int_t) h_this->length, |
| 29092 | (duk_uint8_t) h_this->shift, |
| 29093 | 0 /*idx_start*/, |
| 29094 | 1 /*idx_end*/, |
| 29095 | &start_offset, |
| 29096 | &end_offset); |
| 29097 | DUK_ASSERT(end_offset >= start_offset); |
| 29098 | DUK_ASSERT(start_offset >= 0); |
| 29099 | DUK_ASSERT(end_offset >= 0); |
| 29100 | slice_length = (duk_uint_t) (end_offset - start_offset); |
| 29101 | |
| 29102 | /* The resulting buffer object gets the same class and prototype as |
| 29103 | * the buffer in 'this', e.g. if the input is a Uint8Array the |
| 29104 | * result is a Uint8Array; if the input is a Float32Array, the |
| 29105 | * result is a Float32Array. The result internal prototype should |
| 29106 | * be the default prototype for the class (e.g. initial value of |
| 29107 | * Uint8Array.prototype), not copied from the argument (Duktape 1.x |
| 29108 | * did that). |
| 29109 | * |
| 29110 | * Node.js Buffers have special handling: they're Uint8Arrays as far |
| 29111 | * as the internal class is concerned, so the new Buffer should also |
| 29112 | * be an Uint8Array but inherit from Buffer.prototype. |
| 29113 | */ |
| 29114 | res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this); |
| 29115 | DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN); /* type check guarantees */ |
| 29116 | DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX); |
| 29117 | res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN]; |
| 29118 | if (magic & 0x04) { |
| 29119 | res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE; |
| 29120 | } |
| 29121 | h_bufobj = duk_push_bufobj_raw(thr, |
| 29122 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 29123 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 29124 | DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num), |
| 29125 | res_proto_bidx); |
| 29126 | DUK_ASSERT(h_bufobj != NULL); |
| 29127 | |
| 29128 | DUK_ASSERT(h_bufobj->length == 0); |
| 29129 | h_bufobj->shift = h_this->shift; /* inherit */ |
| 29130 | h_bufobj->elem_type = h_this->elem_type; /* inherit */ |
| 29131 | h_bufobj->is_typedarray = magic & 0x01; |
| 29132 | DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1); |
| 29133 | |
| 29134 | h_val = h_this->buf; |
| 29135 | if (h_val == NULL) { |
| 29136 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 29137 | } |
| 29138 | |
| 29139 | if (magic & 0x02) { |
| 29140 | /* non-zero: make copy */ |
| 29141 | duk_uint8_t *p_copy; |
| 29142 | duk_size_t copy_length; |
| 29143 | |
| 29144 | p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */ |
| 29145 | DUK_ASSERT(p_copy != NULL); |
| 29146 | |
| 29147 | /* Copy slice, respecting underlying buffer limits; remainder |
| 29148 | * is left as zero. |
| 29149 | */ |
| 29150 | copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length); |
| 29151 | duk_memcpy_unsafe((void *) p_copy, |
| 29152 | (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset), |
| 29153 | copy_length); |
| 29154 | |
| 29155 | h_val = duk_known_hbuffer(thr, -1); |
| 29156 | |
| 29157 | h_bufobj->buf = h_val; |
| 29158 | DUK_HBUFFER_INCREF(thr, h_val); |
| 29159 | h_bufobj->length = slice_length; |
| 29160 | DUK_ASSERT(h_bufobj->offset == 0); |
| 29161 | |
| 29162 | duk_pop(thr); /* reachable so pop OK */ |
| 29163 | } else { |
| 29164 | h_bufobj->buf = h_val; |
| 29165 | DUK_HBUFFER_INCREF(thr, h_val); |
| 29166 | h_bufobj->length = slice_length; |
| 29167 | h_bufobj->offset = h_this->offset + (duk_uint_t) start_offset; |
| 29168 | |
| 29169 | /* Copy the .buffer property, needed for TypedArray.prototype.subarray(). |
| 29170 | * |
| 29171 | * XXX: limit copy only for TypedArray classes specifically? |
| 29172 | */ |
| 29173 | |
| 29174 | DUK_ASSERT(h_bufobj->buf_prop == NULL); |
| 29175 | h_bufobj->buf_prop = h_this->buf_prop; /* may be NULL */ |
| 29176 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop); |
| 29177 | } |
| 29178 | /* unbalanced stack on purpose */ |
| 29179 | |
| 29180 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 29181 | return 1; |
| 29182 | } |
| 29183 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29184 | |
| 29185 | /* |
| 29186 | * Node.js Buffer.isEncoding() |
| 29187 | */ |
| 29188 | |
| 29189 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29190 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_hthread *thr) { |
| 29191 | const char *encoding; |
| 29192 | |
| 29193 | /* only accept lowercase 'utf8' now. */ |
| 29194 | |
| 29195 | encoding = duk_to_string(thr, 0); |
| 29196 | DUK_ASSERT(duk_is_string(thr, 0)); /* guaranteed by duk_to_string() */ |
| 29197 | duk_push_boolean(thr, DUK_STRCMP(encoding, "utf8" ) == 0); |
| 29198 | return 1; |
| 29199 | } |
| 29200 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29201 | |
| 29202 | /* |
| 29203 | * Node.js Buffer.isBuffer() |
| 29204 | */ |
| 29205 | |
| 29206 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29207 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_hthread *thr) { |
| 29208 | duk_hobject *h; |
| 29209 | duk_hobject *h_proto; |
| 29210 | duk_bool_t ret = 0; |
| 29211 | |
| 29212 | DUK_ASSERT(duk_get_top(thr) >= 1); /* nargs */ |
| 29213 | h = duk_get_hobject(thr, 0); |
| 29214 | if (h != NULL) { |
| 29215 | h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE]; |
| 29216 | DUK_ASSERT(h_proto != NULL); |
| 29217 | |
| 29218 | h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); |
| 29219 | if (h != NULL) { |
| 29220 | ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/); |
| 29221 | } |
| 29222 | } |
| 29223 | |
| 29224 | duk_push_boolean(thr, ret); |
| 29225 | return 1; |
| 29226 | } |
| 29227 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29228 | |
| 29229 | /* |
| 29230 | * Node.js Buffer.byteLength() |
| 29231 | */ |
| 29232 | |
| 29233 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29234 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_hthread *thr) { |
| 29235 | const char *str; |
| 29236 | duk_size_t len; |
| 29237 | |
| 29238 | /* At the moment Buffer(<str>) will just use the string bytes as |
| 29239 | * is (ignoring encoding), so we return the string length here |
| 29240 | * unconditionally. |
| 29241 | */ |
| 29242 | |
| 29243 | /* XXX: to be revised; Old Node.js behavior just coerces any buffer |
| 29244 | * values to string: |
| 29245 | * $ node |
| 29246 | * > Buffer.byteLength(new Uint32Array(10)) |
| 29247 | * 20 |
| 29248 | * > Buffer.byteLength(new Uint32Array(100)) |
| 29249 | * 20 |
| 29250 | * (The 20 comes from '[object Uint32Array]'.length |
| 29251 | */ |
| 29252 | |
| 29253 | str = duk_to_lstring(thr, 0, &len); |
| 29254 | DUK_UNREF(str); |
| 29255 | duk_push_size_t(thr, len); |
| 29256 | return 1; |
| 29257 | } |
| 29258 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29259 | |
| 29260 | /* |
| 29261 | * Node.js Buffer.concat() |
| 29262 | */ |
| 29263 | |
| 29264 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29265 | DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) { |
| 29266 | duk_hobject *h_arg; |
| 29267 | duk_uint_t total_length; |
| 29268 | duk_hbufobj *h_bufobj; |
| 29269 | duk_hbufobj *h_bufres; |
| 29270 | duk_hbuffer *h_val; |
| 29271 | duk_uint_t i, n; |
| 29272 | duk_uint8_t *p; |
| 29273 | duk_size_t space_left; |
| 29274 | duk_size_t copy_size; |
| 29275 | |
| 29276 | /* Node.js accepts only actual Arrays. */ |
| 29277 | h_arg = duk_require_hobject(thr, 0); |
| 29278 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) { |
| 29279 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 29280 | } |
| 29281 | |
| 29282 | /* Compute result length and validate argument buffers. */ |
| 29283 | n = (duk_uint_t) duk_get_length(thr, 0); |
| 29284 | total_length = 0; |
| 29285 | for (i = 0; i < n; i++) { |
| 29286 | /* Neutered checks not necessary here: neutered buffers have |
| 29287 | * zero 'length' so we'll effectively skip them. |
| 29288 | */ |
| 29289 | DUK_ASSERT_TOP(thr, 2); /* [ array totalLength ] */ |
| 29290 | duk_get_prop_index(thr, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */ |
| 29291 | h_bufobj = duk__require_bufobj_value(thr, 2); |
| 29292 | DUK_ASSERT(h_bufobj != NULL); |
| 29293 | total_length += h_bufobj->length; |
| 29294 | if (DUK_UNLIKELY(total_length < h_bufobj->length)) { |
| 29295 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); /* Wrapped. */ |
| 29296 | } |
| 29297 | duk_pop(thr); |
| 29298 | } |
| 29299 | /* In Node.js v0.12.1 a 1-element array is special and won't create a |
| 29300 | * copy, this was fixed later so an explicit check no longer needed. |
| 29301 | */ |
| 29302 | |
| 29303 | /* User totalLength overrides a computed length, but we'll check |
| 29304 | * every copy in the copy loop. Note that duk_to_int() can |
| 29305 | * technically have arbitrary side effects so we need to recheck |
| 29306 | * the buffers in the copy loop. |
| 29307 | */ |
| 29308 | if (!duk_is_undefined(thr, 1) && n > 0) { |
| 29309 | /* For n == 0, Node.js ignores totalLength argument and |
| 29310 | * returns a zero length buffer. |
| 29311 | */ |
| 29312 | duk_int_t total_length_signed; |
| 29313 | total_length_signed = duk_to_int(thr, 1); |
| 29314 | if (total_length_signed < 0) { |
| 29315 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 29316 | } |
| 29317 | total_length = (duk_uint_t) total_length_signed; |
| 29318 | } |
| 29319 | |
| 29320 | h_bufres = duk_push_bufobj_raw(thr, |
| 29321 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 29322 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 29323 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY), |
| 29324 | DUK_BIDX_NODEJS_BUFFER_PROTOTYPE); |
| 29325 | DUK_ASSERT(h_bufres != NULL); |
| 29326 | |
| 29327 | p = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, total_length); /* must be zeroed, all bytes not necessarily written over */ |
| 29328 | DUK_ASSERT(p != NULL); |
| 29329 | space_left = (duk_size_t) total_length; |
| 29330 | |
| 29331 | for (i = 0; i < n; i++) { |
| 29332 | DUK_ASSERT_TOP(thr, 4); /* [ array totalLength bufres buf ] */ |
| 29333 | |
| 29334 | duk_get_prop_index(thr, 0, (duk_uarridx_t) i); |
| 29335 | h_bufobj = duk__require_bufobj_value(thr, 4); |
| 29336 | DUK_ASSERT(h_bufobj != NULL); |
| 29337 | |
| 29338 | copy_size = h_bufobj->length; |
| 29339 | if (copy_size > space_left) { |
| 29340 | copy_size = space_left; |
| 29341 | } |
| 29342 | |
| 29343 | if (h_bufobj->buf != NULL && |
| 29344 | DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { |
| 29345 | duk_memcpy_unsafe((void *) p, |
| 29346 | (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj), |
| 29347 | copy_size); |
| 29348 | } else { |
| 29349 | /* Just skip, leaving zeroes in the result. */ |
| 29350 | ; |
| 29351 | } |
| 29352 | p += copy_size; |
| 29353 | space_left -= copy_size; |
| 29354 | |
| 29355 | duk_pop(thr); |
| 29356 | } |
| 29357 | |
| 29358 | h_val = duk_known_hbuffer(thr, -1); |
| 29359 | |
| 29360 | duk__set_bufobj_buffer(thr, h_bufres, h_val); |
| 29361 | h_bufres->is_typedarray = 1; |
| 29362 | DUK_HBUFOBJ_ASSERT_VALID(h_bufres); |
| 29363 | |
| 29364 | duk_pop(thr); /* pop plain buffer, now reachable through h_bufres */ |
| 29365 | |
| 29366 | return 1; /* return h_bufres */ |
| 29367 | } |
| 29368 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29369 | |
| 29370 | /* |
| 29371 | * Shared readfield and writefield methods |
| 29372 | * |
| 29373 | * The readfield/writefield methods need support for endianness and field |
| 29374 | * types. All offsets are byte based so no offset shifting is needed. |
| 29375 | */ |
| 29376 | |
| 29377 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29378 | /* Format of magic, bits: |
| 29379 | * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused |
| 29380 | * 3: endianness: 0=little, 1=big |
| 29381 | * 4: signed: 1=yes, 0=no |
| 29382 | * 5: typedarray: 1=yes, 0=no |
| 29383 | */ |
| 29384 | #define DUK__FLD_8BIT 0 |
| 29385 | #define DUK__FLD_16BIT 1 |
| 29386 | #define DUK__FLD_32BIT 2 |
| 29387 | #define DUK__FLD_FLOAT 3 |
| 29388 | #define DUK__FLD_DOUBLE 4 |
| 29389 | #define DUK__FLD_VARINT 5 |
| 29390 | #define DUK__FLD_BIGENDIAN (1 << 3) |
| 29391 | #define DUK__FLD_SIGNED (1 << 4) |
| 29392 | #define DUK__FLD_TYPEDARRAY (1 << 5) |
| 29393 | |
| 29394 | /* XXX: split into separate functions for each field type? */ |
| 29395 | DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) { |
| 29396 | duk_small_uint_t magic = (duk_small_uint_t) duk_get_current_magic(thr); |
| 29397 | duk_small_uint_t magic_ftype; |
| 29398 | duk_small_uint_t magic_bigendian; |
| 29399 | duk_small_uint_t magic_signed; |
| 29400 | duk_small_uint_t magic_typedarray; |
| 29401 | duk_small_uint_t endswap; |
| 29402 | duk_hbufobj *h_this; |
| 29403 | duk_bool_t no_assert; |
| 29404 | duk_int_t offset_signed; |
| 29405 | duk_uint_t offset; |
| 29406 | duk_uint_t buffer_length; |
| 29407 | duk_uint_t check_length; |
| 29408 | duk_uint8_t *buf; |
| 29409 | duk_double_union du; |
| 29410 | |
| 29411 | magic_ftype = magic & 0x0007U; |
| 29412 | magic_bigendian = magic & 0x0008U; |
| 29413 | magic_signed = magic & 0x0010U; |
| 29414 | magic_typedarray = magic & 0x0020U; |
| 29415 | |
| 29416 | h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */ |
| 29417 | DUK_ASSERT(h_this != NULL); |
| 29418 | buffer_length = h_this->length; |
| 29419 | |
| 29420 | /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */ |
| 29421 | /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */ |
| 29422 | /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */ |
| 29423 | |
| 29424 | /* Handle TypedArray vs. Node.js Buffer arg differences */ |
| 29425 | if (magic_typedarray) { |
| 29426 | no_assert = 0; |
| 29427 | #if defined(DUK_USE_INTEGER_LE) |
| 29428 | endswap = !duk_to_boolean(thr, 1); /* 1=little endian */ |
| 29429 | #else |
| 29430 | endswap = duk_to_boolean(thr, 1); /* 1=little endian */ |
| 29431 | #endif |
| 29432 | } else { |
| 29433 | no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1); |
| 29434 | #if defined(DUK_USE_INTEGER_LE) |
| 29435 | endswap = magic_bigendian; |
| 29436 | #else |
| 29437 | endswap = !magic_bigendian; |
| 29438 | #endif |
| 29439 | } |
| 29440 | |
| 29441 | /* Offset is coerced first to signed integer range and then to unsigned. |
| 29442 | * This ensures we can add a small byte length (1-8) to the offset in |
| 29443 | * bound checks and not wrap. |
| 29444 | */ |
| 29445 | offset_signed = duk_to_int(thr, 0); |
| 29446 | offset = (duk_uint_t) offset_signed; |
| 29447 | if (offset_signed < 0) { |
| 29448 | goto fail_bounds; |
| 29449 | } |
| 29450 | |
| 29451 | DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, " |
| 29452 | "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, " |
| 29453 | "endswap=%u" , |
| 29454 | (long) buffer_length, (long) offset, (int) no_assert, |
| 29455 | (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3), |
| 29456 | (int) (magic_signed >> 4), (int) endswap)); |
| 29457 | |
| 29458 | /* Update 'buffer_length' to be the effective, safe limit which |
| 29459 | * takes into account the underlying buffer. This value will be |
| 29460 | * potentially invalidated by any side effect. |
| 29461 | */ |
| 29462 | check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length); |
| 29463 | DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld" , |
| 29464 | (long) buffer_length, (long) check_length)); |
| 29465 | |
| 29466 | if (h_this->buf) { |
| 29467 | buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); |
| 29468 | } else { |
| 29469 | /* Neutered. We could go into the switch-case safely with |
| 29470 | * buf == NULL because check_length == 0. To avoid scanbuild |
| 29471 | * warnings, fail directly instead. |
| 29472 | */ |
| 29473 | DUK_ASSERT(check_length == 0); |
| 29474 | goto fail_neutered; |
| 29475 | } |
| 29476 | DUK_ASSERT(buf != NULL); |
| 29477 | |
| 29478 | switch (magic_ftype) { |
| 29479 | case DUK__FLD_8BIT: { |
| 29480 | duk_uint8_t tmp; |
| 29481 | if (offset + 1U > check_length) { |
| 29482 | goto fail_bounds; |
| 29483 | } |
| 29484 | tmp = buf[offset]; |
| 29485 | if (magic_signed) { |
| 29486 | duk_push_int(thr, (duk_int_t) ((duk_int8_t) tmp)); |
| 29487 | } else { |
| 29488 | duk_push_uint(thr, (duk_uint_t) tmp); |
| 29489 | } |
| 29490 | break; |
| 29491 | } |
| 29492 | case DUK__FLD_16BIT: { |
| 29493 | duk_uint16_t tmp; |
| 29494 | if (offset + 2U > check_length) { |
| 29495 | goto fail_bounds; |
| 29496 | } |
| 29497 | duk_memcpy((void *) du.uc, (const void *) (buf + offset), 2); |
| 29498 | tmp = du.us[0]; |
| 29499 | if (endswap) { |
| 29500 | tmp = DUK_BSWAP16(tmp); |
| 29501 | } |
| 29502 | if (magic_signed) { |
| 29503 | duk_push_int(thr, (duk_int_t) ((duk_int16_t) tmp)); |
| 29504 | } else { |
| 29505 | duk_push_uint(thr, (duk_uint_t) tmp); |
| 29506 | } |
| 29507 | break; |
| 29508 | } |
| 29509 | case DUK__FLD_32BIT: { |
| 29510 | duk_uint32_t tmp; |
| 29511 | if (offset + 4U > check_length) { |
| 29512 | goto fail_bounds; |
| 29513 | } |
| 29514 | duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4); |
| 29515 | tmp = du.ui[0]; |
| 29516 | if (endswap) { |
| 29517 | tmp = DUK_BSWAP32(tmp); |
| 29518 | } |
| 29519 | if (magic_signed) { |
| 29520 | duk_push_int(thr, (duk_int_t) ((duk_int32_t) tmp)); |
| 29521 | } else { |
| 29522 | duk_push_uint(thr, (duk_uint_t) tmp); |
| 29523 | } |
| 29524 | break; |
| 29525 | } |
| 29526 | case DUK__FLD_FLOAT: { |
| 29527 | duk_uint32_t tmp; |
| 29528 | if (offset + 4U > check_length) { |
| 29529 | goto fail_bounds; |
| 29530 | } |
| 29531 | duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4); |
| 29532 | if (endswap) { |
| 29533 | tmp = du.ui[0]; |
| 29534 | tmp = DUK_BSWAP32(tmp); |
| 29535 | du.ui[0] = tmp; |
| 29536 | } |
| 29537 | duk_push_number(thr, (duk_double_t) du.f[0]); |
| 29538 | break; |
| 29539 | } |
| 29540 | case DUK__FLD_DOUBLE: { |
| 29541 | if (offset + 8U > check_length) { |
| 29542 | goto fail_bounds; |
| 29543 | } |
| 29544 | duk_memcpy((void *) du.uc, (const void *) (buf + offset), 8); |
| 29545 | if (endswap) { |
| 29546 | DUK_DBLUNION_BSWAP64(&du); |
| 29547 | } |
| 29548 | duk_push_number(thr, (duk_double_t) du.d); |
| 29549 | break; |
| 29550 | } |
| 29551 | case DUK__FLD_VARINT: { |
| 29552 | /* Node.js Buffer variable width integer field. We don't really |
| 29553 | * care about speed here, so aim for shortest algorithm. |
| 29554 | */ |
| 29555 | duk_int_t field_bytelen; |
| 29556 | duk_int_t i, i_step, i_end; |
| 29557 | #if defined(DUK_USE_64BIT_OPS) |
| 29558 | duk_int64_t tmp; |
| 29559 | duk_small_uint_t shift_tmp; |
| 29560 | #else |
| 29561 | duk_double_t tmp; |
| 29562 | duk_small_int_t highbyte; |
| 29563 | #endif |
| 29564 | const duk_uint8_t *p; |
| 29565 | |
| 29566 | field_bytelen = duk_get_int(thr, 1); /* avoid side effects! */ |
| 29567 | if (field_bytelen < 1 || field_bytelen > 6) { |
| 29568 | goto fail_field_length; |
| 29569 | } |
| 29570 | if (offset + (duk_uint_t) field_bytelen > check_length) { |
| 29571 | goto fail_bounds; |
| 29572 | } |
| 29573 | p = (const duk_uint8_t *) (buf + offset); |
| 29574 | |
| 29575 | /* Slow gathering of value using either 64-bit arithmetic |
| 29576 | * or IEEE doubles if 64-bit types not available. Handling |
| 29577 | * of negative numbers is a bit non-obvious in both cases. |
| 29578 | */ |
| 29579 | |
| 29580 | if (magic_bigendian) { |
| 29581 | /* Gather in big endian */ |
| 29582 | i = 0; |
| 29583 | i_step = 1; |
| 29584 | i_end = field_bytelen; /* one i_step over */ |
| 29585 | } else { |
| 29586 | /* Gather in little endian */ |
| 29587 | i = field_bytelen - 1; |
| 29588 | i_step = -1; |
| 29589 | i_end = -1; /* one i_step over */ |
| 29590 | } |
| 29591 | |
| 29592 | #if defined(DUK_USE_64BIT_OPS) |
| 29593 | tmp = 0; |
| 29594 | do { |
| 29595 | DUK_ASSERT(i >= 0 && i < field_bytelen); |
| 29596 | tmp = (tmp << 8) + (duk_int64_t) p[i]; |
| 29597 | i += i_step; |
| 29598 | } while (i != i_end); |
| 29599 | |
| 29600 | if (magic_signed) { |
| 29601 | /* Shift to sign extend. Left shift must be unsigned |
| 29602 | * to avoid undefined behavior; right shift must be |
| 29603 | * signed to sign extend properly. |
| 29604 | */ |
| 29605 | shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U); |
| 29606 | tmp = (duk_int64_t) ((duk_uint64_t) tmp << shift_tmp) >> shift_tmp; |
| 29607 | } |
| 29608 | |
| 29609 | duk_push_i64(thr, tmp); |
| 29610 | #else |
| 29611 | highbyte = p[i]; |
| 29612 | if (magic_signed && (highbyte & 0x80) != 0) { |
| 29613 | /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */ |
| 29614 | tmp = (duk_double_t) (highbyte - 256); |
| 29615 | } else { |
| 29616 | tmp = (duk_double_t) highbyte; |
| 29617 | } |
| 29618 | for (;;) { |
| 29619 | i += i_step; |
| 29620 | if (i == i_end) { |
| 29621 | break; |
| 29622 | } |
| 29623 | DUK_ASSERT(i >= 0 && i < field_bytelen); |
| 29624 | tmp = (tmp * 256.0) + (duk_double_t) p[i]; |
| 29625 | } |
| 29626 | |
| 29627 | duk_push_number(thr, tmp); |
| 29628 | #endif |
| 29629 | break; |
| 29630 | } |
| 29631 | default: { /* should never happen but default here */ |
| 29632 | goto fail_bounds; |
| 29633 | } |
| 29634 | } |
| 29635 | |
| 29636 | return 1; |
| 29637 | |
| 29638 | fail_neutered: |
| 29639 | fail_field_length: |
| 29640 | fail_bounds: |
| 29641 | if (no_assert) { |
| 29642 | /* Node.js return value for noAssert out-of-bounds reads is |
| 29643 | * usually (but not always) NaN. Return NaN consistently. |
| 29644 | */ |
| 29645 | duk_push_nan(thr); |
| 29646 | return 1; |
| 29647 | } |
| 29648 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 29649 | } |
| 29650 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29651 | |
| 29652 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29653 | /* XXX: split into separate functions for each field type? */ |
| 29654 | DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) { |
| 29655 | duk_small_uint_t magic = (duk_small_uint_t) duk_get_current_magic(thr); |
| 29656 | duk_small_uint_t magic_ftype; |
| 29657 | duk_small_uint_t magic_bigendian; |
| 29658 | duk_small_uint_t magic_signed; |
| 29659 | duk_small_uint_t magic_typedarray; |
| 29660 | duk_small_uint_t endswap; |
| 29661 | duk_hbufobj *h_this; |
| 29662 | duk_bool_t no_assert; |
| 29663 | duk_int_t offset_signed; |
| 29664 | duk_uint_t offset; |
| 29665 | duk_uint_t buffer_length; |
| 29666 | duk_uint_t check_length; |
| 29667 | duk_uint8_t *buf; |
| 29668 | duk_double_union du; |
| 29669 | duk_int_t nbytes = 0; |
| 29670 | |
| 29671 | magic_ftype = magic & 0x0007U; |
| 29672 | magic_bigendian = magic & 0x0008U; |
| 29673 | magic_signed = magic & 0x0010U; |
| 29674 | magic_typedarray = magic & 0x0020U; |
| 29675 | DUK_UNREF(magic_signed); |
| 29676 | |
| 29677 | h_this = duk__require_bufobj_this(thr); /* XXX: very inefficient for plain buffers */ |
| 29678 | DUK_ASSERT(h_this != NULL); |
| 29679 | buffer_length = h_this->length; |
| 29680 | |
| 29681 | /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */ |
| 29682 | /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */ |
| 29683 | /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */ |
| 29684 | |
| 29685 | /* Handle TypedArray vs. Node.js Buffer arg differences */ |
| 29686 | if (magic_typedarray) { |
| 29687 | no_assert = 0; |
| 29688 | #if defined(DUK_USE_INTEGER_LE) |
| 29689 | endswap = !duk_to_boolean(thr, 2); /* 1=little endian */ |
| 29690 | #else |
| 29691 | endswap = duk_to_boolean(thr, 2); /* 1=little endian */ |
| 29692 | #endif |
| 29693 | duk_swap(thr, 0, 1); /* offset/value order different from Node.js */ |
| 29694 | } else { |
| 29695 | no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2); |
| 29696 | #if defined(DUK_USE_INTEGER_LE) |
| 29697 | endswap = magic_bigendian; |
| 29698 | #else |
| 29699 | endswap = !magic_bigendian; |
| 29700 | #endif |
| 29701 | } |
| 29702 | |
| 29703 | /* Offset is coerced first to signed integer range and then to unsigned. |
| 29704 | * This ensures we can add a small byte length (1-8) to the offset in |
| 29705 | * bound checks and not wrap. |
| 29706 | */ |
| 29707 | offset_signed = duk_to_int(thr, 1); |
| 29708 | offset = (duk_uint_t) offset_signed; |
| 29709 | |
| 29710 | /* We need 'nbytes' even for a failed offset; return value must be |
| 29711 | * (offset + nbytes) even when write fails due to invalid offset. |
| 29712 | */ |
| 29713 | if (magic_ftype != DUK__FLD_VARINT) { |
| 29714 | DUK_ASSERT(magic_ftype < (duk_small_uint_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t))); |
| 29715 | nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype]; |
| 29716 | } else { |
| 29717 | nbytes = duk_get_int(thr, 2); |
| 29718 | if (nbytes < 1 || nbytes > 6) { |
| 29719 | goto fail_field_length; |
| 29720 | } |
| 29721 | } |
| 29722 | DUK_ASSERT(nbytes >= 1 && nbytes <= 8); |
| 29723 | |
| 29724 | /* Now we can check offset validity. */ |
| 29725 | if (offset_signed < 0) { |
| 29726 | goto fail_bounds; |
| 29727 | } |
| 29728 | |
| 29729 | DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, " |
| 29730 | "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, " |
| 29731 | "endswap=%u" , |
| 29732 | duk_get_tval(thr, 0), (long) buffer_length, (long) offset, (int) no_assert, |
| 29733 | (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3), |
| 29734 | (int) (magic_signed >> 4), (int) endswap)); |
| 29735 | |
| 29736 | /* Coerce value to a number before computing check_length, so that |
| 29737 | * the field type specific coercion below can't have side effects |
| 29738 | * that would invalidate check_length. |
| 29739 | */ |
| 29740 | duk_to_number(thr, 0); |
| 29741 | |
| 29742 | /* Update 'buffer_length' to be the effective, safe limit which |
| 29743 | * takes into account the underlying buffer. This value will be |
| 29744 | * potentially invalidated by any side effect. |
| 29745 | */ |
| 29746 | check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length); |
| 29747 | DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld" , |
| 29748 | (long) buffer_length, (long) check_length)); |
| 29749 | |
| 29750 | if (h_this->buf) { |
| 29751 | buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this); |
| 29752 | } else { |
| 29753 | /* Neutered. We could go into the switch-case safely with |
| 29754 | * buf == NULL because check_length == 0. To avoid scanbuild |
| 29755 | * warnings, fail directly instead. |
| 29756 | */ |
| 29757 | DUK_ASSERT(check_length == 0); |
| 29758 | goto fail_neutered; |
| 29759 | } |
| 29760 | DUK_ASSERT(buf != NULL); |
| 29761 | |
| 29762 | switch (magic_ftype) { |
| 29763 | case DUK__FLD_8BIT: { |
| 29764 | if (offset + 1U > check_length) { |
| 29765 | goto fail_bounds; |
| 29766 | } |
| 29767 | /* sign doesn't matter when writing */ |
| 29768 | buf[offset] = (duk_uint8_t) duk_to_uint32(thr, 0); |
| 29769 | break; |
| 29770 | } |
| 29771 | case DUK__FLD_16BIT: { |
| 29772 | duk_uint16_t tmp; |
| 29773 | if (offset + 2U > check_length) { |
| 29774 | goto fail_bounds; |
| 29775 | } |
| 29776 | tmp = (duk_uint16_t) duk_to_uint32(thr, 0); |
| 29777 | if (endswap) { |
| 29778 | tmp = DUK_BSWAP16(tmp); |
| 29779 | } |
| 29780 | du.us[0] = tmp; |
| 29781 | /* sign doesn't matter when writing */ |
| 29782 | duk_memcpy((void *) (buf + offset), (const void *) du.uc, 2); |
| 29783 | break; |
| 29784 | } |
| 29785 | case DUK__FLD_32BIT: { |
| 29786 | duk_uint32_t tmp; |
| 29787 | if (offset + 4U > check_length) { |
| 29788 | goto fail_bounds; |
| 29789 | } |
| 29790 | tmp = (duk_uint32_t) duk_to_uint32(thr, 0); |
| 29791 | if (endswap) { |
| 29792 | tmp = DUK_BSWAP32(tmp); |
| 29793 | } |
| 29794 | du.ui[0] = tmp; |
| 29795 | /* sign doesn't matter when writing */ |
| 29796 | duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4); |
| 29797 | break; |
| 29798 | } |
| 29799 | case DUK__FLD_FLOAT: { |
| 29800 | duk_uint32_t tmp; |
| 29801 | if (offset + 4U > check_length) { |
| 29802 | goto fail_bounds; |
| 29803 | } |
| 29804 | du.f[0] = (duk_float_t) duk_to_number(thr, 0); |
| 29805 | if (endswap) { |
| 29806 | tmp = du.ui[0]; |
| 29807 | tmp = DUK_BSWAP32(tmp); |
| 29808 | du.ui[0] = tmp; |
| 29809 | } |
| 29810 | /* sign doesn't matter when writing */ |
| 29811 | duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4); |
| 29812 | break; |
| 29813 | } |
| 29814 | case DUK__FLD_DOUBLE: { |
| 29815 | if (offset + 8U > check_length) { |
| 29816 | goto fail_bounds; |
| 29817 | } |
| 29818 | du.d = (duk_double_t) duk_to_number(thr, 0); |
| 29819 | if (endswap) { |
| 29820 | DUK_DBLUNION_BSWAP64(&du); |
| 29821 | } |
| 29822 | /* sign doesn't matter when writing */ |
| 29823 | duk_memcpy((void *) (buf + offset), (const void *) du.uc, 8); |
| 29824 | break; |
| 29825 | } |
| 29826 | case DUK__FLD_VARINT: { |
| 29827 | /* Node.js Buffer variable width integer field. We don't really |
| 29828 | * care about speed here, so aim for shortest algorithm. |
| 29829 | */ |
| 29830 | duk_int_t field_bytelen; |
| 29831 | duk_int_t i, i_step, i_end; |
| 29832 | #if defined(DUK_USE_64BIT_OPS) |
| 29833 | duk_int64_t tmp; |
| 29834 | #else |
| 29835 | duk_double_t tmp; |
| 29836 | #endif |
| 29837 | duk_uint8_t *p; |
| 29838 | |
| 29839 | field_bytelen = (duk_int_t) nbytes; |
| 29840 | if (offset + (duk_uint_t) field_bytelen > check_length) { |
| 29841 | goto fail_bounds; |
| 29842 | } |
| 29843 | |
| 29844 | /* Slow writing of value using either 64-bit arithmetic |
| 29845 | * or IEEE doubles if 64-bit types not available. There's |
| 29846 | * no special sign handling when writing varints. |
| 29847 | */ |
| 29848 | |
| 29849 | if (magic_bigendian) { |
| 29850 | /* Write in big endian */ |
| 29851 | i = field_bytelen; /* one i_step added at top of loop */ |
| 29852 | i_step = -1; |
| 29853 | i_end = 0; |
| 29854 | } else { |
| 29855 | /* Write in little endian */ |
| 29856 | i = -1; /* one i_step added at top of loop */ |
| 29857 | i_step = 1; |
| 29858 | i_end = field_bytelen - 1; |
| 29859 | } |
| 29860 | |
| 29861 | /* XXX: The duk_to_number() cast followed by integer coercion |
| 29862 | * is platform specific so NaN, +/- Infinity, and out-of-bounds |
| 29863 | * values result in platform specific output now. |
| 29864 | * See: test-bi-nodejs-buffer-proto-varint-special.js |
| 29865 | */ |
| 29866 | |
| 29867 | #if defined(DUK_USE_64BIT_OPS) |
| 29868 | tmp = (duk_int64_t) duk_to_number(thr, 0); |
| 29869 | p = (duk_uint8_t *) (buf + offset); |
| 29870 | do { |
| 29871 | i += i_step; |
| 29872 | DUK_ASSERT(i >= 0 && i < field_bytelen); |
| 29873 | p[i] = (duk_uint8_t) (tmp & 0xff); |
| 29874 | tmp = tmp >> 8; /* unnecessary shift for last byte */ |
| 29875 | } while (i != i_end); |
| 29876 | #else |
| 29877 | tmp = duk_to_number(thr, 0); |
| 29878 | p = (duk_uint8_t *) (buf + offset); |
| 29879 | do { |
| 29880 | i += i_step; |
| 29881 | tmp = DUK_FLOOR(tmp); |
| 29882 | DUK_ASSERT(i >= 0 && i < field_bytelen); |
| 29883 | p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0)); |
| 29884 | tmp = tmp / 256.0; /* unnecessary div for last byte */ |
| 29885 | } while (i != i_end); |
| 29886 | #endif |
| 29887 | break; |
| 29888 | } |
| 29889 | default: { /* should never happen but default here */ |
| 29890 | goto fail_bounds; |
| 29891 | } |
| 29892 | } |
| 29893 | |
| 29894 | /* Node.js Buffer: return offset + #bytes written (i.e. next |
| 29895 | * write offset). |
| 29896 | */ |
| 29897 | if (magic_typedarray) { |
| 29898 | /* For TypedArrays 'undefined' return value is specified |
| 29899 | * by ES2015 (matches V8). |
| 29900 | */ |
| 29901 | return 0; |
| 29902 | } |
| 29903 | duk_push_uint(thr, offset + (duk_uint_t) nbytes); |
| 29904 | return 1; |
| 29905 | |
| 29906 | fail_neutered: |
| 29907 | fail_field_length: |
| 29908 | fail_bounds: |
| 29909 | if (no_assert) { |
| 29910 | /* Node.js return value for failed writes is offset + #bytes |
| 29911 | * that would have been written. |
| 29912 | */ |
| 29913 | /* XXX: for negative input offsets, 'offset' will be a large |
| 29914 | * positive value so the result here is confusing. |
| 29915 | */ |
| 29916 | if (magic_typedarray) { |
| 29917 | return 0; |
| 29918 | } |
| 29919 | duk_push_uint(thr, offset + (duk_uint_t) nbytes); |
| 29920 | return 1; |
| 29921 | } |
| 29922 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 29923 | } |
| 29924 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 29925 | |
| 29926 | /* |
| 29927 | * Accessors for .buffer, .byteLength, .byteOffset |
| 29928 | */ |
| 29929 | |
| 29930 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 29931 | DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_hthread *thr, duk_hbuffer *h_buf) { |
| 29932 | duk_hbufobj *h_res; |
| 29933 | |
| 29934 | h_res = duk_push_bufobj_raw(thr, |
| 29935 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 29936 | DUK_HOBJECT_FLAG_BUFOBJ | |
| 29937 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER), |
| 29938 | DUK_BIDX_ARRAYBUFFER_PROTOTYPE); |
| 29939 | DUK_ASSERT(h_res != NULL); |
| 29940 | DUK_UNREF(h_res); |
| 29941 | |
| 29942 | duk__set_bufobj_buffer(thr, h_res, h_buf); |
| 29943 | DUK_HBUFOBJ_ASSERT_VALID(h_res); |
| 29944 | DUK_ASSERT(h_res->buf_prop == NULL); |
| 29945 | return h_res; |
| 29946 | } |
| 29947 | |
| 29948 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) { |
| 29949 | duk_hbufobj *h_bufobj; |
| 29950 | |
| 29951 | h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/); |
| 29952 | DUK_ASSERT(h_bufobj != NULL); |
| 29953 | if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { |
| 29954 | DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer" )); |
| 29955 | (void) duk__autospawn_arraybuffer(thr, (duk_hbuffer *) h_bufobj); |
| 29956 | return 1; |
| 29957 | } else { |
| 29958 | if (h_bufobj->buf_prop == NULL && |
| 29959 | DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER && |
| 29960 | h_bufobj->buf != NULL) { |
| 29961 | duk_hbufobj *h_arrbuf; |
| 29962 | |
| 29963 | DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView" )); |
| 29964 | h_arrbuf = duk__autospawn_arraybuffer(thr, h_bufobj->buf); |
| 29965 | |
| 29966 | if (h_bufobj->buf_prop == NULL) { |
| 29967 | /* Must recheck buf_prop, in case ArrayBuffer |
| 29968 | * alloc had a side effect which already filled |
| 29969 | * it! |
| 29970 | */ |
| 29971 | |
| 29972 | /* Set ArrayBuffer's .byteOffset and .byteLength based |
| 29973 | * on the view so that Arraybuffer[view.byteOffset] |
| 29974 | * matches view[0]. |
| 29975 | */ |
| 29976 | h_arrbuf->offset = 0; |
| 29977 | DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset); /* Wrap check on creation. */ |
| 29978 | h_arrbuf->length = h_bufobj->offset + h_bufobj->length; |
| 29979 | DUK_ASSERT(h_arrbuf->buf_prop == NULL); |
| 29980 | |
| 29981 | DUK_ASSERT(h_bufobj->buf_prop == NULL); |
| 29982 | h_bufobj->buf_prop = (duk_hobject *) h_arrbuf; |
| 29983 | DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */ |
| 29984 | } |
| 29985 | |
| 29986 | /* Left on stack; pushed for the second time below (OK). */ |
| 29987 | } |
| 29988 | if (h_bufobj->buf_prop) { |
| 29989 | duk_push_hobject(thr, h_bufobj->buf_prop); |
| 29990 | return 1; |
| 29991 | } |
| 29992 | } |
| 29993 | return 0; |
| 29994 | } |
| 29995 | |
| 29996 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) { |
| 29997 | duk_hbufobj *h_bufobj; |
| 29998 | |
| 29999 | h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/); |
| 30000 | DUK_ASSERT(h_bufobj != NULL); |
| 30001 | if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { |
| 30002 | duk_push_uint(thr, 0); |
| 30003 | } else { |
| 30004 | /* If neutered must return 0; offset is zeroed during |
| 30005 | * neutering. |
| 30006 | */ |
| 30007 | duk_push_uint(thr, h_bufobj->offset); |
| 30008 | } |
| 30009 | return 1; |
| 30010 | } |
| 30011 | |
| 30012 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) { |
| 30013 | duk_hbufobj *h_bufobj; |
| 30014 | |
| 30015 | h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/); |
| 30016 | DUK_ASSERT(h_bufobj != NULL); |
| 30017 | if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) { |
| 30018 | duk_hbuffer *h_buf; |
| 30019 | |
| 30020 | h_buf = (duk_hbuffer *) h_bufobj; |
| 30021 | DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */ |
| 30022 | duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf)); |
| 30023 | } else { |
| 30024 | /* If neutered must return 0; length is zeroed during |
| 30025 | * neutering. |
| 30026 | */ |
| 30027 | duk_push_uint(thr, h_bufobj->length); |
| 30028 | } |
| 30029 | return 1; |
| 30030 | } |
| 30031 | #else /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 30032 | /* No .buffer getter without ArrayBuffer support. */ |
| 30033 | #if 0 |
| 30034 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) { |
| 30035 | return 0; |
| 30036 | } |
| 30037 | #endif |
| 30038 | |
| 30039 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) { |
| 30040 | duk_push_uint(thr, 0); |
| 30041 | return 1; |
| 30042 | } |
| 30043 | |
| 30044 | DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) { |
| 30045 | duk_hbuffer *h_buf; |
| 30046 | |
| 30047 | /* XXX: helper? */ |
| 30048 | duk_push_this(thr); |
| 30049 | h_buf = duk_require_hbuffer(thr, -1); |
| 30050 | duk_push_uint(thr, DUK_HBUFFER_GET_SIZE(h_buf)); |
| 30051 | return 1; |
| 30052 | } |
| 30053 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 30054 | |
| 30055 | /* automatic undefs */ |
| 30056 | #undef DUK__BUFOBJ_FLAG_PROMOTE |
| 30057 | #undef DUK__BUFOBJ_FLAG_THROW |
| 30058 | #undef DUK__FLD_16BIT |
| 30059 | #undef DUK__FLD_32BIT |
| 30060 | #undef DUK__FLD_8BIT |
| 30061 | #undef DUK__FLD_BIGENDIAN |
| 30062 | #undef DUK__FLD_DOUBLE |
| 30063 | #undef DUK__FLD_FLOAT |
| 30064 | #undef DUK__FLD_SIGNED |
| 30065 | #undef DUK__FLD_TYPEDARRAY |
| 30066 | #undef DUK__FLD_VARINT |
| 30067 | #line 1 "duk_bi_cbor.c" |
| 30068 | /* |
| 30069 | * CBOR bindings. |
| 30070 | * |
| 30071 | * http://cbor.io/ |
| 30072 | * https://tools.ietf.org/html/rfc7049 |
| 30073 | */ |
| 30074 | |
| 30075 | /* #include duk_internal.h -> already included */ |
| 30076 | |
| 30077 | #if defined(DUK_USE_CBOR_SUPPORT) |
| 30078 | |
| 30079 | /* #define DUK_CBOR_STRESS */ |
| 30080 | |
| 30081 | /* Default behavior for encoding strings: use CBOR text string if string |
| 30082 | * is UTF-8 compatible, otherwise use CBOR byte string. These defines |
| 30083 | * can be used to force either type for all strings. Using text strings |
| 30084 | * for non-UTF-8 data is technically invalid CBOR. |
| 30085 | */ |
| 30086 | /* #define DUK_CBOR_TEXT_STRINGS */ |
| 30087 | /* #define DUK_CBOR_BYTE_STRINGS */ |
| 30088 | |
| 30089 | /* Misc. defines. */ |
| 30090 | /* #define DUK_CBOR_PREFER_SIZE */ |
| 30091 | /* #define DUK_CBOR_DOUBLE_AS_IS */ |
| 30092 | /* #define DUK_CBOR_DECODE_FASTPATH */ |
| 30093 | |
| 30094 | typedef struct { |
| 30095 | duk_hthread *thr; |
| 30096 | duk_uint8_t *ptr; |
| 30097 | duk_uint8_t *buf; |
| 30098 | duk_uint8_t *buf_end; |
| 30099 | duk_size_t len; |
| 30100 | duk_idx_t idx_buf; |
| 30101 | duk_uint_t recursion_depth; |
| 30102 | duk_uint_t recursion_limit; |
| 30103 | } duk_cbor_encode_context; |
| 30104 | |
| 30105 | typedef struct { |
| 30106 | duk_hthread *thr; |
| 30107 | const duk_uint8_t *buf; |
| 30108 | duk_size_t off; |
| 30109 | duk_size_t len; |
| 30110 | duk_uint_t recursion_depth; |
| 30111 | duk_uint_t recursion_limit; |
| 30112 | } duk_cbor_decode_context; |
| 30113 | |
| 30114 | DUK_LOCAL void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx); |
| 30115 | DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx); |
| 30116 | |
| 30117 | /* |
| 30118 | * Misc |
| 30119 | */ |
| 30120 | |
| 30121 | DUK_LOCAL duk_uint32_t duk__cbor_double_to_uint32(double d) { |
| 30122 | /* Out of range casts are undefined behavior, so caller must avoid. */ |
| 30123 | DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); |
| 30124 | return (duk_uint32_t) d; |
| 30125 | } |
| 30126 | |
| 30127 | /* |
| 30128 | * Encoding |
| 30129 | */ |
| 30130 | |
| 30131 | DUK_LOCAL void duk__cbor_encode_error(duk_cbor_encode_context *enc_ctx) { |
| 30132 | (void) duk_type_error(enc_ctx->thr, "cbor encode error" ); |
| 30133 | } |
| 30134 | |
| 30135 | DUK_LOCAL void duk__cbor_encode_req_stack(duk_cbor_encode_context *enc_ctx) { |
| 30136 | duk_require_stack(enc_ctx->thr, 4); |
| 30137 | } |
| 30138 | |
| 30139 | DUK_LOCAL void duk__cbor_encode_objarr_entry(duk_cbor_encode_context *enc_ctx) { |
| 30140 | duk_hthread *thr = enc_ctx->thr; |
| 30141 | |
| 30142 | /* Native stack check in object/array recursion. */ |
| 30143 | duk_native_stack_check(thr); |
| 30144 | |
| 30145 | /* When working with deeply recursive structures, this is important |
| 30146 | * to ensure there's no effective depth limit. |
| 30147 | */ |
| 30148 | duk__cbor_encode_req_stack(enc_ctx); |
| 30149 | |
| 30150 | DUK_ASSERT(enc_ctx->recursion_depth <= enc_ctx->recursion_limit); |
| 30151 | if (enc_ctx->recursion_depth >= enc_ctx->recursion_limit) { |
| 30152 | DUK_ERROR_RANGE(thr, DUK_STR_ENC_RECLIMIT); |
| 30153 | DUK_WO_NORETURN(return;); |
| 30154 | } |
| 30155 | enc_ctx->recursion_depth++; |
| 30156 | } |
| 30157 | |
| 30158 | DUK_LOCAL void duk__cbor_encode_objarr_exit(duk_cbor_encode_context *enc_ctx) { |
| 30159 | DUK_ASSERT(enc_ctx->recursion_depth > 0); |
| 30160 | enc_ctx->recursion_depth--; |
| 30161 | } |
| 30162 | |
| 30163 | /* Check that a size_t is in uint32 range to avoid out-of-range casts. */ |
| 30164 | DUK_LOCAL void duk__cbor_encode_sizet_uint32_check(duk_cbor_encode_context *enc_ctx, duk_size_t len) { |
| 30165 | if (DUK_UNLIKELY(sizeof(duk_size_t) > sizeof(duk_uint32_t) && len > (duk_size_t) DUK_UINT32_MAX)) { |
| 30166 | duk__cbor_encode_error(enc_ctx); |
| 30167 | } |
| 30168 | } |
| 30169 | |
| 30170 | DUK_LOCAL DUK_NOINLINE void duk__cbor_encode_ensure_slowpath(duk_cbor_encode_context *enc_ctx, duk_size_t len) { |
| 30171 | duk_size_t oldlen; |
| 30172 | duk_size_t minlen; |
| 30173 | duk_size_t newlen; |
| 30174 | duk_uint8_t *p_new; |
| 30175 | duk_size_t old_data_len; |
| 30176 | |
| 30177 | DUK_ASSERT(enc_ctx->ptr >= enc_ctx->buf); |
| 30178 | DUK_ASSERT(enc_ctx->buf_end >= enc_ctx->ptr); |
| 30179 | DUK_ASSERT(enc_ctx->buf_end >= enc_ctx->buf); |
| 30180 | |
| 30181 | /* Overflow check. |
| 30182 | * |
| 30183 | * Limit example: 0xffffffffUL / 2U = 0x7fffffffUL, we reject >= 0x80000000UL. |
| 30184 | */ |
| 30185 | oldlen = enc_ctx->len; |
| 30186 | minlen = oldlen + len; |
| 30187 | if (DUK_UNLIKELY(oldlen > DUK_SIZE_MAX / 2U || minlen < oldlen)) { |
| 30188 | duk__cbor_encode_error(enc_ctx); |
| 30189 | } |
| 30190 | |
| 30191 | #if defined(DUK_CBOR_STRESS) |
| 30192 | newlen = oldlen + 1U; |
| 30193 | #else |
| 30194 | newlen = oldlen * 2U; |
| 30195 | #endif |
| 30196 | DUK_ASSERT(newlen >= oldlen); |
| 30197 | |
| 30198 | if (minlen > newlen) { |
| 30199 | newlen = minlen; |
| 30200 | } |
| 30201 | DUK_ASSERT(newlen >= oldlen); |
| 30202 | DUK_ASSERT(newlen >= minlen); |
| 30203 | DUK_ASSERT(newlen > 0U); |
| 30204 | |
| 30205 | DUK_DD(DUK_DDPRINT("cbor encode buffer resized to %ld" , (long) newlen)); |
| 30206 | |
| 30207 | p_new = (duk_uint8_t *) duk_resize_buffer(enc_ctx->thr, enc_ctx->idx_buf, newlen); |
| 30208 | DUK_ASSERT(p_new != NULL); |
| 30209 | old_data_len = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf); |
| 30210 | enc_ctx->buf = p_new; |
| 30211 | enc_ctx->buf_end = p_new + newlen; |
| 30212 | enc_ctx->ptr = p_new + old_data_len; |
| 30213 | enc_ctx->len = newlen; |
| 30214 | } |
| 30215 | |
| 30216 | DUK_LOCAL DUK_INLINE void duk__cbor_encode_ensure(duk_cbor_encode_context *enc_ctx, duk_size_t len) { |
| 30217 | if (DUK_LIKELY((duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr) >= len)) { |
| 30218 | return; |
| 30219 | } |
| 30220 | duk__cbor_encode_ensure_slowpath(enc_ctx, len); |
| 30221 | } |
| 30222 | |
| 30223 | DUK_LOCAL duk_size_t duk__cbor_get_reserve(duk_cbor_encode_context *enc_ctx) { |
| 30224 | DUK_ASSERT(enc_ctx->ptr >= enc_ctx->buf); |
| 30225 | DUK_ASSERT(enc_ctx->ptr <= enc_ctx->buf_end); |
| 30226 | return (duk_size_t) (enc_ctx->buf_end - enc_ctx->ptr); |
| 30227 | } |
| 30228 | |
| 30229 | DUK_LOCAL void duk__cbor_encode_uint32(duk_cbor_encode_context *enc_ctx, duk_uint32_t u, duk_uint8_t base) { |
| 30230 | duk_uint8_t *p; |
| 30231 | |
| 30232 | /* Caller must ensure space. */ |
| 30233 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 4); |
| 30234 | |
| 30235 | p = enc_ctx->ptr; |
| 30236 | if (DUK_LIKELY(u <= 23U)) { |
| 30237 | *p++ = (duk_uint8_t) (base + (duk_uint8_t) u); |
| 30238 | } else if (u <= 0xffUL) { |
| 30239 | *p++ = base + 0x18U; |
| 30240 | *p++ = (duk_uint8_t) u; |
| 30241 | } else if (u <= 0xffffUL) { |
| 30242 | *p++ = base + 0x19U; |
| 30243 | DUK_RAW_WRITEINC_U16_BE(p, (duk_uint16_t) u); |
| 30244 | } else { |
| 30245 | *p++ = base + 0x1aU; |
| 30246 | DUK_RAW_WRITEINC_U32_BE(p, u); |
| 30247 | } |
| 30248 | enc_ctx->ptr = p; |
| 30249 | } |
| 30250 | |
| 30251 | #if defined(DUK_CBOR_DOUBLE_AS_IS) |
| 30252 | DUK_LOCAL void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) { |
| 30253 | duk_uint8_t *p; |
| 30254 | |
| 30255 | /* Caller must ensure space. */ |
| 30256 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); |
| 30257 | |
| 30258 | p = enc_ctx->ptr; |
| 30259 | *p++ = 0xfbU; |
| 30260 | DUK_RAW_WRITEINC_DOUBLE_BE(p, d); |
| 30261 | p += 8; |
| 30262 | enc_ctx->ptr = p; |
| 30263 | } |
| 30264 | #else /* DUK_CBOR_DOUBLE_AS_IS */ |
| 30265 | DUK_LOCAL void duk__cbor_encode_double_fp(duk_cbor_encode_context *enc_ctx, double d) { |
| 30266 | duk_double_union u; |
| 30267 | duk_uint16_t u16; |
| 30268 | duk_int16_t expt; |
| 30269 | duk_uint8_t *p; |
| 30270 | |
| 30271 | DUK_ASSERT(DUK_FPCLASSIFY(d) != DUK_FP_ZERO); |
| 30272 | |
| 30273 | /* Caller must ensure space. */ |
| 30274 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); |
| 30275 | |
| 30276 | /* Organize into little endian (no-op if platform is little endian). */ |
| 30277 | u.d = d; |
| 30278 | duk_dblunion_host_to_little(&u); |
| 30279 | |
| 30280 | /* Check if 'd' can represented as a normal half-float. |
| 30281 | * Denormal half-floats could also be used, but that check |
| 30282 | * isn't done now (denormal half-floats are decoded of course). |
| 30283 | * So just check exponent range and that at most 10 significant |
| 30284 | * bits (excluding implicit leading 1) are used in 'd'. |
| 30285 | */ |
| 30286 | u16 = (((duk_uint16_t) u.uc[7]) << 8) | ((duk_uint16_t) u.uc[6]); |
| 30287 | expt = (duk_int16_t) ((u16 & 0x7ff0U) >> 4) - 1023; |
| 30288 | |
| 30289 | if (expt >= -14 && expt <= 15) { |
| 30290 | /* Half-float normal exponents (excl. denormals). |
| 30291 | * |
| 30292 | * 7 6 5 4 3 2 1 0 (LE index) |
| 30293 | * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm |
| 30294 | * half: seeeee mmmm mmmmmm00 00000000 00000000 00000000 00000000 00000000 |
| 30295 | */ |
| 30296 | duk_bool_t use_half_float; |
| 30297 | |
| 30298 | use_half_float = |
| 30299 | (u.uc[0] == 0 && u.uc[1] == 0 && u.uc[2] == 0 && u.uc[3] == 0 && |
| 30300 | u.uc[4] == 0 && (u.uc[5] & 0x03U) == 0); |
| 30301 | |
| 30302 | if (use_half_float) { |
| 30303 | duk_uint32_t t; |
| 30304 | |
| 30305 | expt += 15; |
| 30306 | t = (duk_uint32_t) (u.uc[7] & 0x80U) << 8; |
| 30307 | t += (duk_uint32_t) expt << 10; |
| 30308 | t += ((duk_uint32_t) u.uc[6] & 0x0fU) << 6; |
| 30309 | t += ((duk_uint32_t) u.uc[5]) >> 2; |
| 30310 | |
| 30311 | /* seeeeemm mmmmmmmm */ |
| 30312 | p = enc_ctx->ptr; |
| 30313 | *p++ = 0xf9U; |
| 30314 | DUK_RAW_WRITEINC_U16_BE(p, (duk_uint16_t) t); |
| 30315 | enc_ctx->ptr = p; |
| 30316 | return; |
| 30317 | } |
| 30318 | } |
| 30319 | |
| 30320 | /* Same check for plain float. Also no denormal support here. */ |
| 30321 | if (expt >= -126 && expt <= 127) { |
| 30322 | /* Float normal exponents (excl. denormals). |
| 30323 | * |
| 30324 | * double: seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm |
| 30325 | * float: seeee eeeemmmm mmmmmmmm mmmmmmmm mmm00000 00000000 00000000 00000000 |
| 30326 | */ |
| 30327 | duk_bool_t use_float; |
| 30328 | duk_float_t d_float; |
| 30329 | |
| 30330 | /* We could do this explicit mantissa check, but doing |
| 30331 | * a double-float-double cast is fine because we've |
| 30332 | * already verified that the exponent is in range so |
| 30333 | * that the narrower cast is not undefined behavior. |
| 30334 | */ |
| 30335 | #if 0 |
| 30336 | use_float = |
| 30337 | (u.uc[0] == 0 && u.uc[1] == 0 && u.uc[2] == 0 && (u.uc[3] & 0xe0U) == 0); |
| 30338 | #endif |
| 30339 | d_float = (duk_float_t) d; |
| 30340 | use_float = duk_double_equals((duk_double_t) d_float, d); |
| 30341 | if (use_float) { |
| 30342 | p = enc_ctx->ptr; |
| 30343 | *p++ = 0xfaU; |
| 30344 | DUK_RAW_WRITEINC_FLOAT_BE(p, d_float); |
| 30345 | enc_ctx->ptr = p; |
| 30346 | return; |
| 30347 | } |
| 30348 | } |
| 30349 | |
| 30350 | /* Special handling for NaN and Inf which we want to encode as |
| 30351 | * half-floats. They share the same (maximum) exponent. |
| 30352 | */ |
| 30353 | if (expt == 1024) { |
| 30354 | DUK_ASSERT(DUK_ISNAN(d) || DUK_ISINF(d)); |
| 30355 | p = enc_ctx->ptr; |
| 30356 | *p++ = 0xf9U; |
| 30357 | if (DUK_ISNAN(d)) { |
| 30358 | /* Shortest NaN encoding is using a half-float. Lose the |
| 30359 | * exact NaN bits in the process. IEEE double would be |
| 30360 | * 7ff8 0000 0000 0000, i.e. a quiet NaN in most architectures |
| 30361 | * (https://en.wikipedia.org/wiki/NaN#Encoding). The |
| 30362 | * equivalent half float is 7e00. |
| 30363 | */ |
| 30364 | *p++ = 0x7eU; |
| 30365 | } else { |
| 30366 | /* Shortest +/- Infinity encoding is using a half-float. */ |
| 30367 | if (DUK_SIGNBIT(d)) { |
| 30368 | *p++ = 0xfcU; |
| 30369 | } else { |
| 30370 | *p++ = 0x7cU; |
| 30371 | } |
| 30372 | } |
| 30373 | *p++ = 0x00U; |
| 30374 | enc_ctx->ptr = p; |
| 30375 | return; |
| 30376 | } |
| 30377 | |
| 30378 | /* Cannot use half-float or float, encode as full IEEE double. */ |
| 30379 | p = enc_ctx->ptr; |
| 30380 | *p++ = 0xfbU; |
| 30381 | DUK_RAW_WRITEINC_DOUBLE_BE(p, d); |
| 30382 | enc_ctx->ptr = p; |
| 30383 | } |
| 30384 | |
| 30385 | DUK_LOCAL void duk__cbor_encode_double(duk_cbor_encode_context *enc_ctx, double d) { |
| 30386 | duk_uint8_t *p; |
| 30387 | double d_floor; |
| 30388 | |
| 30389 | /* Integers and floating point values of all types are conceptually |
| 30390 | * equivalent in CBOR. Try to always choose the shortest encoding |
| 30391 | * which is not always immediately obvious. For example, NaN and Inf |
| 30392 | * can be most compactly represented as a half-float (assuming NaN |
| 30393 | * bits are not preserved), and 0x1'0000'0000 as a single precision |
| 30394 | * float. Shortest forms in preference order (prefer integer over |
| 30395 | * float when equal length): |
| 30396 | * |
| 30397 | * uint 1 byte [0,23] (not -0) |
| 30398 | * sint 1 byte [-24,-1] |
| 30399 | * uint+1 2 bytes [24,255] |
| 30400 | * sint+1 2 bytes [-256,-25] |
| 30401 | * uint+2 3 bytes [256,65535] |
| 30402 | * sint+2 3 bytes [-65536,-257] |
| 30403 | * half-float 3 bytes -0, NaN, +/- Infinity, range [-65504,65504] |
| 30404 | * uint+4 5 bytes [65536,4294967295] |
| 30405 | * sint+4 5 bytes [-4294967296,-258] |
| 30406 | * float 5 bytes range [-(1 - 2^(-24)) * 2^128, (1 - 2^(-24)) * 2^128] |
| 30407 | * uint+8 9 bytes [4294967296,18446744073709551615] |
| 30408 | * sint+8 9 bytes [-18446744073709551616,-4294967297] |
| 30409 | * double 9 bytes |
| 30410 | * |
| 30411 | * For whole numbers (compatible with integers): |
| 30412 | * - 1-byte or 2-byte uint/sint representation is preferred for |
| 30413 | * [-256,255]. |
| 30414 | * - 3-byte uint/sint is preferred for [-65536,65535]. Half floats |
| 30415 | * are never preferred because they have the same length. |
| 30416 | * - 5-byte uint/sint is preferred for [-4294967296,4294967295]. |
| 30417 | * Single precision floats are never preferred, and half-floats |
| 30418 | * don't reach above the 3-byte uint/sint range so they're never |
| 30419 | * preferred. |
| 30420 | * - So, for all integers up to signed/unsigned 32-bit range the |
| 30421 | * preferred encoding is always an integer uint/sint. |
| 30422 | * - For integers above 32 bits the situation is more complicated. |
| 30423 | * Half-floats are never useful for them because of their limited |
| 30424 | * range, but IEEE single precision floats (5 bytes encoded) can |
| 30425 | * represent some integers between the 32-bit and 64-bit ranges |
| 30426 | * which require 9 bytes as a uint/sint. |
| 30427 | * |
| 30428 | * For floating point values not compatible with integers, the |
| 30429 | * preferred encoding is quite clear: |
| 30430 | * - For +Inf/-Inf use half-float. |
| 30431 | * - For NaN use a half-float, assuming NaN bits ("payload") is |
| 30432 | * not worth preserving. Duktape doesn't in general guarantee |
| 30433 | * preservation of the NaN payload so using a half-float seems |
| 30434 | * consistent with that. |
| 30435 | * - For remaining values, prefer the shortest form which doesn't |
| 30436 | * lose any precision. For normal half-floats and single precision |
| 30437 | * floats this is simple: just check exponent and mantissa bits |
| 30438 | * using a fixed mask. For denormal half-floats and single |
| 30439 | * precision floats the check is a bit more complicated: a normal |
| 30440 | * IEEE double can sometimes be represented as a denormal |
| 30441 | * half-float or single precision float. |
| 30442 | * |
| 30443 | * https://en.wikipedia.org/wiki/Half-precision_floating-point_format#IEEE_754_half-precision_binary_floating-point_format:_binary16 |
| 30444 | */ |
| 30445 | |
| 30446 | /* Caller must ensure space. */ |
| 30447 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); |
| 30448 | |
| 30449 | /* Most important path is integers. The floor() test will be true |
| 30450 | * for Inf too (but not NaN). |
| 30451 | */ |
| 30452 | d_floor = DUK_FLOOR(d); /* identity if d is +/- 0.0, NaN, or +/- Infinity */ |
| 30453 | if (DUK_LIKELY(duk_double_equals(d_floor, d) != 0)) { |
| 30454 | DUK_ASSERT(!DUK_ISNAN(d)); /* NaN == NaN compares false. */ |
| 30455 | if (DUK_SIGNBIT(d)) { |
| 30456 | if (d >= -4294967296.0) { |
| 30457 | d = -1.0 - d; |
| 30458 | if (d >= 0.0) { |
| 30459 | DUK_ASSERT(d >= 0.0); |
| 30460 | duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x20U); |
| 30461 | return; |
| 30462 | } |
| 30463 | |
| 30464 | /* Input was negative zero, d == -1.0 < 0.0. |
| 30465 | * Shortest -0 is using half-float. |
| 30466 | */ |
| 30467 | p = enc_ctx->ptr; |
| 30468 | *p++ = 0xf9U; |
| 30469 | *p++ = 0x80U; |
| 30470 | *p++ = 0x00U; |
| 30471 | enc_ctx->ptr = p; |
| 30472 | return; |
| 30473 | } |
| 30474 | } else { |
| 30475 | if (d <= 4294967295.0) { |
| 30476 | /* Positive zero needs no special handling. */ |
| 30477 | DUK_ASSERT(d >= 0.0); |
| 30478 | duk__cbor_encode_uint32(enc_ctx, duk__cbor_double_to_uint32(d), 0x00U); |
| 30479 | return; |
| 30480 | } |
| 30481 | } |
| 30482 | } |
| 30483 | |
| 30484 | /* 64-bit integers are not supported at present. So |
| 30485 | * we also don't need to deal with choosing between a |
| 30486 | * 64-bit uint/sint representation vs. IEEE double or |
| 30487 | * float. |
| 30488 | */ |
| 30489 | |
| 30490 | DUK_ASSERT(DUK_FPCLASSIFY(d) != DUK_FP_ZERO); |
| 30491 | duk__cbor_encode_double_fp(enc_ctx, d); |
| 30492 | } |
| 30493 | #endif /* DUK_CBOR_DOUBLE_AS_IS */ |
| 30494 | |
| 30495 | DUK_LOCAL void duk__cbor_encode_string_top(duk_cbor_encode_context *enc_ctx) { |
| 30496 | const duk_uint8_t *str; |
| 30497 | duk_size_t len; |
| 30498 | duk_uint8_t *p; |
| 30499 | |
| 30500 | /* CBOR differentiates between UTF-8 text strings and byte strings. |
| 30501 | * Text strings MUST be valid UTF-8, so not all Duktape strings can |
| 30502 | * be encoded as valid CBOR text strings. Possible behaviors: |
| 30503 | * |
| 30504 | * 1. Use text string when input is valid UTF-8, otherwise use |
| 30505 | * byte string (maybe tagged to indicate it was an extended |
| 30506 | * UTF-8 string). |
| 30507 | * 2. Always use text strings, but sanitize input string so that |
| 30508 | * invalid UTF-8 is replaced with U+FFFD for example. Combine |
| 30509 | * surrogates whenever possible. |
| 30510 | * 3. Always use byte strings. This is simple and produces valid |
| 30511 | * CBOR, but isn't ideal for interoperability. |
| 30512 | * 4. Always use text strings, even for invalid UTF-8 such as |
| 30513 | * codepoints in the surrogate pair range. This is simple but |
| 30514 | * produces technically invalid CBOR for non-UTF-8 strings which |
| 30515 | * may affect interoperability. |
| 30516 | * |
| 30517 | * Current default is 1; can be changed with defines. |
| 30518 | */ |
| 30519 | |
| 30520 | /* Caller must ensure space. */ |
| 30521 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); |
| 30522 | |
| 30523 | str = (const duk_uint8_t *) duk_require_lstring(enc_ctx->thr, -1, &len); |
| 30524 | if (duk_is_symbol(enc_ctx->thr, -1)) { |
| 30525 | /* Symbols, encode as an empty table for now. This matches |
| 30526 | * the behavior of cbor-js. |
| 30527 | * |
| 30528 | * XXX: Maybe encode String() coercion with a tag? |
| 30529 | * XXX: Option to keep enough information to recover |
| 30530 | * Symbols when decoding (this is not always desirable). |
| 30531 | */ |
| 30532 | p = enc_ctx->ptr; |
| 30533 | *p++ = 0xa0U; |
| 30534 | enc_ctx->ptr = p; |
| 30535 | return; |
| 30536 | } |
| 30537 | |
| 30538 | duk__cbor_encode_sizet_uint32_check(enc_ctx, len); |
| 30539 | #if defined(DUK_CBOR_TEXT_STRINGS) |
| 30540 | duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x60U); |
| 30541 | #elif defined(DUK_CBOR_BYTE_STRINGS) |
| 30542 | duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U); |
| 30543 | #else |
| 30544 | duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, |
| 30545 | (DUK_LIKELY(duk_unicode_is_utf8_compatible(str, len) != 0) ? 0x60U : 0x40U)); |
| 30546 | #endif |
| 30547 | duk__cbor_encode_ensure(enc_ctx, len); |
| 30548 | p = enc_ctx->ptr; |
| 30549 | duk_memcpy((void *) p, (const void *) str, len); |
| 30550 | p += len; |
| 30551 | enc_ctx->ptr = p; |
| 30552 | } |
| 30553 | |
| 30554 | DUK_LOCAL void duk__cbor_encode_object(duk_cbor_encode_context *enc_ctx) { |
| 30555 | duk_uint8_t *buf; |
| 30556 | duk_size_t len; |
| 30557 | duk_uint8_t *p; |
| 30558 | duk_size_t i; |
| 30559 | duk_size_t off_ib; |
| 30560 | duk_uint32_t count; |
| 30561 | |
| 30562 | /* Caller must ensure space. */ |
| 30563 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); |
| 30564 | |
| 30565 | duk__cbor_encode_objarr_entry(enc_ctx); |
| 30566 | |
| 30567 | /* XXX: Support for specific built-ins like Date and RegExp. */ |
| 30568 | if (duk_is_array(enc_ctx->thr, -1)) { |
| 30569 | /* Shortest encoding for arrays >= 256 in length is actually |
| 30570 | * the indefinite length one (3 or more bytes vs. 2 bytes). |
| 30571 | * We still use the definite length version because it is |
| 30572 | * more decoding friendly. |
| 30573 | */ |
| 30574 | len = duk_get_length(enc_ctx->thr, -1); |
| 30575 | duk__cbor_encode_sizet_uint32_check(enc_ctx, len); |
| 30576 | duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x80U); |
| 30577 | for (i = 0; i < len; i++) { |
| 30578 | duk_get_prop_index(enc_ctx->thr, -1, (duk_uarridx_t) i); |
| 30579 | duk__cbor_encode_value(enc_ctx); |
| 30580 | } |
| 30581 | } else if (duk_is_buffer_data(enc_ctx->thr, -1)) { |
| 30582 | /* XXX: Tag buffer data? |
| 30583 | * XXX: Encode typed arrays as integer arrays rather |
| 30584 | * than buffer data as is? |
| 30585 | */ |
| 30586 | buf = (duk_uint8_t *) duk_require_buffer_data(enc_ctx->thr, -1, &len); |
| 30587 | duk__cbor_encode_sizet_uint32_check(enc_ctx, len); |
| 30588 | duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U); |
| 30589 | duk__cbor_encode_ensure(enc_ctx, len); |
| 30590 | p = enc_ctx->ptr; |
| 30591 | duk_memcpy_unsafe((void *) p, (const void *) buf, len); |
| 30592 | p += len; |
| 30593 | enc_ctx->ptr = p; |
| 30594 | } else { |
| 30595 | /* We don't know the number of properties in advance |
| 30596 | * but would still like to encode at least small |
| 30597 | * objects without indefinite length. Emit an |
| 30598 | * indefinite length byte initially, and if the final |
| 30599 | * property count is small enough to also fit in one |
| 30600 | * byte, backpatch it later. Otherwise keep the |
| 30601 | * indefinite length. This works well up to 23 |
| 30602 | * properties which is practical and good enough. |
| 30603 | */ |
| 30604 | off_ib = (duk_size_t) (enc_ctx->ptr - enc_ctx->buf); /* XXX: get_offset? */ |
| 30605 | count = 0U; |
| 30606 | p = enc_ctx->ptr; |
| 30607 | *p++ = 0xa0U + 0x1fU; /* indefinite length */ |
| 30608 | enc_ctx->ptr = p; |
| 30609 | duk_enum(enc_ctx->thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); |
| 30610 | while (duk_next(enc_ctx->thr, -1, 1 /*get_value*/)) { |
| 30611 | duk_insert(enc_ctx->thr, -2); /* [ ... key value ] -> [ ... value key ] */ |
| 30612 | duk__cbor_encode_value(enc_ctx); |
| 30613 | duk__cbor_encode_value(enc_ctx); |
| 30614 | count++; |
| 30615 | if (count == 0U) { |
| 30616 | duk__cbor_encode_error(enc_ctx); |
| 30617 | } |
| 30618 | } |
| 30619 | duk_pop(enc_ctx->thr); |
| 30620 | if (count <= 0x17U) { |
| 30621 | DUK_ASSERT(off_ib < enc_ctx->len); |
| 30622 | enc_ctx->buf[off_ib] = 0xa0U + (duk_uint8_t) count; |
| 30623 | } else { |
| 30624 | duk__cbor_encode_ensure(enc_ctx, 1); |
| 30625 | p = enc_ctx->ptr; |
| 30626 | *p++ = 0xffU; /* break */ |
| 30627 | enc_ctx->ptr = p; |
| 30628 | } |
| 30629 | } |
| 30630 | |
| 30631 | duk__cbor_encode_objarr_exit(enc_ctx); |
| 30632 | } |
| 30633 | |
| 30634 | DUK_LOCAL void duk__cbor_encode_buffer(duk_cbor_encode_context *enc_ctx) { |
| 30635 | duk_uint8_t *buf; |
| 30636 | duk_size_t len; |
| 30637 | duk_uint8_t *p; |
| 30638 | |
| 30639 | /* Caller must ensure space. */ |
| 30640 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); |
| 30641 | |
| 30642 | /* Tag buffer data? */ |
| 30643 | buf = (duk_uint8_t *) duk_require_buffer(enc_ctx->thr, -1, &len); |
| 30644 | duk__cbor_encode_sizet_uint32_check(enc_ctx, len); |
| 30645 | duk__cbor_encode_uint32(enc_ctx, (duk_uint32_t) len, 0x40U); |
| 30646 | duk__cbor_encode_ensure(enc_ctx, len); |
| 30647 | p = enc_ctx->ptr; |
| 30648 | duk_memcpy_unsafe((void *) p, (const void *) buf, len); |
| 30649 | p += len; |
| 30650 | enc_ctx->ptr = p; |
| 30651 | } |
| 30652 | |
| 30653 | DUK_LOCAL void duk__cbor_encode_pointer(duk_cbor_encode_context *enc_ctx) { |
| 30654 | /* Pointers (void *) are challenging to encode. They can't |
| 30655 | * be relied to be even 64-bit integer compatible (there are |
| 30656 | * pointer models larger than that), nor can floats encode |
| 30657 | * them. They could be encoded as strings (%p format) but |
| 30658 | * that's not portable. They could be encoded as direct memory |
| 30659 | * representations. Recovering pointers is non-portable in any |
| 30660 | * case but it would be nice to be able to detect and recover |
| 30661 | * compatible pointers. |
| 30662 | * |
| 30663 | * For now, encode as "(%p)" string, matching JX. There doesn't |
| 30664 | * seem to be an appropriate tag, so pointers don't currently |
| 30665 | * survive a CBOR encode/decode roundtrip intact. |
| 30666 | */ |
| 30667 | const char *ptr; |
| 30668 | |
| 30669 | ptr = duk_to_string(enc_ctx->thr, -1); |
| 30670 | DUK_ASSERT(ptr != NULL); |
| 30671 | duk_push_sprintf(enc_ctx->thr, "(%s)" , ptr); |
| 30672 | duk_remove(enc_ctx->thr, -2); |
| 30673 | duk__cbor_encode_string_top(enc_ctx); |
| 30674 | } |
| 30675 | |
| 30676 | DUK_LOCAL void duk__cbor_encode_lightfunc(duk_cbor_encode_context *enc_ctx) { |
| 30677 | duk_uint8_t *p; |
| 30678 | |
| 30679 | /* Caller must ensure space. */ |
| 30680 | DUK_ASSERT(duk__cbor_get_reserve(enc_ctx) >= 1 + 8); |
| 30681 | |
| 30682 | /* For now encode as an empty object. */ |
| 30683 | p = enc_ctx->ptr; |
| 30684 | *p++ = 0xa0U; |
| 30685 | enc_ctx->ptr = p; |
| 30686 | } |
| 30687 | |
| 30688 | DUK_LOCAL void duk__cbor_encode_value(duk_cbor_encode_context *enc_ctx) { |
| 30689 | duk_uint8_t *p; |
| 30690 | |
| 30691 | /* Encode/decode cycle currently loses some type information. |
| 30692 | * This can be improved by registering custom tags with IANA. |
| 30693 | */ |
| 30694 | |
| 30695 | /* Reserve space for up to 64-bit types (1 initial byte + 8 |
| 30696 | * followup bytes). This allows encoding of integers, floats, |
| 30697 | * string/buffer length fields, etc without separate checks |
| 30698 | * in each code path. |
| 30699 | */ |
| 30700 | duk__cbor_encode_ensure(enc_ctx, 1 + 8); |
| 30701 | |
| 30702 | switch (duk_get_type(enc_ctx->thr, -1)) { |
| 30703 | case DUK_TYPE_UNDEFINED: { |
| 30704 | p = enc_ctx->ptr; |
| 30705 | *p++ = 0xf7; |
| 30706 | enc_ctx->ptr = p; |
| 30707 | break; |
| 30708 | } |
| 30709 | case DUK_TYPE_NULL: { |
| 30710 | p = enc_ctx->ptr; |
| 30711 | *p++ = 0xf6; |
| 30712 | enc_ctx->ptr = p; |
| 30713 | break; |
| 30714 | } |
| 30715 | case DUK_TYPE_BOOLEAN: { |
| 30716 | duk_uint8_t u8 = duk_get_boolean(enc_ctx->thr, -1) ? 0xf5U : 0xf4U; |
| 30717 | p = enc_ctx->ptr; |
| 30718 | *p++ = u8; |
| 30719 | enc_ctx->ptr = p; |
| 30720 | break; |
| 30721 | } |
| 30722 | case DUK_TYPE_NUMBER: { |
| 30723 | duk__cbor_encode_double(enc_ctx, duk_get_number(enc_ctx->thr, -1)); |
| 30724 | break; |
| 30725 | } |
| 30726 | case DUK_TYPE_STRING: { |
| 30727 | duk__cbor_encode_string_top(enc_ctx); |
| 30728 | break; |
| 30729 | } |
| 30730 | case DUK_TYPE_OBJECT: { |
| 30731 | duk__cbor_encode_object(enc_ctx); |
| 30732 | break; |
| 30733 | } |
| 30734 | case DUK_TYPE_BUFFER: { |
| 30735 | duk__cbor_encode_buffer(enc_ctx); |
| 30736 | break; |
| 30737 | } |
| 30738 | case DUK_TYPE_POINTER: { |
| 30739 | duk__cbor_encode_pointer(enc_ctx); |
| 30740 | break; |
| 30741 | } |
| 30742 | case DUK_TYPE_LIGHTFUNC: { |
| 30743 | duk__cbor_encode_lightfunc(enc_ctx); |
| 30744 | break; |
| 30745 | } |
| 30746 | case DUK_TYPE_NONE: |
| 30747 | default: |
| 30748 | goto fail; |
| 30749 | } |
| 30750 | |
| 30751 | duk_pop(enc_ctx->thr); |
| 30752 | return; |
| 30753 | |
| 30754 | fail: |
| 30755 | duk__cbor_encode_error(enc_ctx); |
| 30756 | } |
| 30757 | |
| 30758 | /* |
| 30759 | * Decoding |
| 30760 | */ |
| 30761 | |
| 30762 | DUK_LOCAL void duk__cbor_decode_error(duk_cbor_decode_context *dec_ctx) { |
| 30763 | (void) duk_type_error(dec_ctx->thr, "cbor decode error" ); |
| 30764 | } |
| 30765 | |
| 30766 | DUK_LOCAL void duk__cbor_decode_req_stack(duk_cbor_decode_context *dec_ctx) { |
| 30767 | duk_require_stack(dec_ctx->thr, 4); |
| 30768 | } |
| 30769 | |
| 30770 | DUK_LOCAL void duk__cbor_decode_objarr_entry(duk_cbor_decode_context *dec_ctx) { |
| 30771 | duk_hthread *thr = dec_ctx->thr; |
| 30772 | |
| 30773 | /* Native stack check in object/array recursion. */ |
| 30774 | duk_native_stack_check(thr); |
| 30775 | |
| 30776 | duk__cbor_decode_req_stack(dec_ctx); |
| 30777 | |
| 30778 | DUK_ASSERT(dec_ctx->recursion_depth <= dec_ctx->recursion_limit); |
| 30779 | if (dec_ctx->recursion_depth >= dec_ctx->recursion_limit) { |
| 30780 | DUK_ERROR_RANGE(thr, DUK_STR_DEC_RECLIMIT); |
| 30781 | DUK_WO_NORETURN(return;); |
| 30782 | } |
| 30783 | dec_ctx->recursion_depth++; |
| 30784 | } |
| 30785 | |
| 30786 | DUK_LOCAL void duk__cbor_decode_objarr_exit(duk_cbor_decode_context *dec_ctx) { |
| 30787 | DUK_ASSERT(dec_ctx->recursion_depth > 0); |
| 30788 | dec_ctx->recursion_depth--; |
| 30789 | } |
| 30790 | |
| 30791 | DUK_LOCAL duk_uint8_t duk__cbor_decode_readbyte(duk_cbor_decode_context *dec_ctx) { |
| 30792 | DUK_ASSERT(dec_ctx->off <= dec_ctx->len); |
| 30793 | if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 1U)) { |
| 30794 | duk__cbor_decode_error(dec_ctx); |
| 30795 | } |
| 30796 | return dec_ctx->buf[dec_ctx->off++]; |
| 30797 | } |
| 30798 | |
| 30799 | DUK_LOCAL duk_uint16_t duk__cbor_decode_read_u16(duk_cbor_decode_context *dec_ctx) { |
| 30800 | duk_uint16_t res; |
| 30801 | |
| 30802 | DUK_ASSERT(dec_ctx->off <= dec_ctx->len); |
| 30803 | if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 2U)) { |
| 30804 | duk__cbor_decode_error(dec_ctx); |
| 30805 | } |
| 30806 | res = DUK_RAW_READ_U16_BE(dec_ctx->buf + dec_ctx->off); |
| 30807 | dec_ctx->off += 2; |
| 30808 | return res; |
| 30809 | } |
| 30810 | |
| 30811 | DUK_LOCAL duk_uint32_t duk__cbor_decode_read_u32(duk_cbor_decode_context *dec_ctx) { |
| 30812 | duk_uint32_t res; |
| 30813 | |
| 30814 | DUK_ASSERT(dec_ctx->off <= dec_ctx->len); |
| 30815 | if (DUK_UNLIKELY(dec_ctx->len - dec_ctx->off < 4U)) { |
| 30816 | duk__cbor_decode_error(dec_ctx); |
| 30817 | } |
| 30818 | res = DUK_RAW_READ_U32_BE(dec_ctx->buf + dec_ctx->off); |
| 30819 | dec_ctx->off += 4; |
| 30820 | return res; |
| 30821 | } |
| 30822 | |
| 30823 | DUK_LOCAL duk_uint8_t duk__cbor_decode_peekbyte(duk_cbor_decode_context *dec_ctx) { |
| 30824 | if (DUK_UNLIKELY(dec_ctx->off >= dec_ctx->len)) { |
| 30825 | duk__cbor_decode_error(dec_ctx); |
| 30826 | } |
| 30827 | return dec_ctx->buf[dec_ctx->off]; |
| 30828 | } |
| 30829 | |
| 30830 | DUK_LOCAL void duk__cbor_decode_rewind(duk_cbor_decode_context *dec_ctx, duk_size_t len) { |
| 30831 | DUK_ASSERT(len <= dec_ctx->off); /* Caller must ensure. */ |
| 30832 | dec_ctx->off -= len; |
| 30833 | } |
| 30834 | |
| 30835 | #if 0 |
| 30836 | DUK_LOCAL void duk__cbor_decode_ensure(duk_cbor_decode_context *dec_ctx, duk_size_t len) { |
| 30837 | if (dec_ctx->off + len > dec_ctx->len) { |
| 30838 | duk__cbor_decode_error(dec_ctx); |
| 30839 | } |
| 30840 | } |
| 30841 | #endif |
| 30842 | |
| 30843 | DUK_LOCAL const duk_uint8_t *duk__cbor_decode_consume(duk_cbor_decode_context *dec_ctx, duk_size_t len) { |
| 30844 | DUK_ASSERT(dec_ctx->off <= dec_ctx->len); |
| 30845 | if (DUK_LIKELY(dec_ctx->len - dec_ctx->off >= len)) { |
| 30846 | const duk_uint8_t *res = dec_ctx->buf + dec_ctx->off; |
| 30847 | dec_ctx->off += len; |
| 30848 | return res; |
| 30849 | } |
| 30850 | |
| 30851 | duk__cbor_decode_error(dec_ctx); /* Not enough input. */ |
| 30852 | return NULL; |
| 30853 | } |
| 30854 | |
| 30855 | DUK_LOCAL int duk__cbor_decode_checkbreak(duk_cbor_decode_context *dec_ctx) { |
| 30856 | if (duk__cbor_decode_peekbyte(dec_ctx) == 0xffU) { |
| 30857 | DUK_ASSERT(dec_ctx->off < dec_ctx->len); |
| 30858 | dec_ctx->off++; |
| 30859 | #if 0 |
| 30860 | (void) duk__cbor_decode_readbyte(dec_ctx); |
| 30861 | #endif |
| 30862 | return 1; |
| 30863 | } |
| 30864 | return 0; |
| 30865 | } |
| 30866 | |
| 30867 | DUK_LOCAL void duk__cbor_decode_push_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_bool_t negative) { |
| 30868 | duk_uint8_t ai; |
| 30869 | duk_uint32_t t, t1, t2; |
| 30870 | #if 0 |
| 30871 | duk_uint64_t t3; |
| 30872 | #endif |
| 30873 | duk_double_t d1, d2; |
| 30874 | duk_double_t d; |
| 30875 | |
| 30876 | ai = ib & 0x1fU; |
| 30877 | if (ai <= 0x17U) { |
| 30878 | t = ai; |
| 30879 | goto shared_exit; |
| 30880 | } |
| 30881 | |
| 30882 | switch (ai) { |
| 30883 | case 0x18U: /* 1 byte */ |
| 30884 | t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx); |
| 30885 | goto shared_exit; |
| 30886 | case 0x19U: /* 2 byte */ |
| 30887 | t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx); |
| 30888 | goto shared_exit; |
| 30889 | case 0x1aU: /* 4 byte */ |
| 30890 | t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); |
| 30891 | goto shared_exit; |
| 30892 | case 0x1bU: /* 8 byte */ |
| 30893 | /* For uint64 it's important to handle the -1.0 part before |
| 30894 | * casting to double: otherwise the adjustment might be lost |
| 30895 | * in the cast. Uses: -1.0 - d <=> -(d + 1.0). |
| 30896 | */ |
| 30897 | t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); |
| 30898 | t2 = t; |
| 30899 | t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); |
| 30900 | t1 = t; |
| 30901 | #if 0 |
| 30902 | t3 = (duk_uint64_t) t2 * DUK_U64_CONSTANT(0x100000000) + (duk_uint64_t) t1; |
| 30903 | if (negative) { |
| 30904 | if (t3 == DUK_UINT64_MAX) { |
| 30905 | /* -(0xffff'ffff'ffff'ffffULL + 1) = |
| 30906 | * -0x1'0000'0000'0000'0000 |
| 30907 | * |
| 30908 | * >>> -0x10000000000000000 |
| 30909 | * -18446744073709551616L |
| 30910 | */ |
| 30911 | return -18446744073709551616.0; |
| 30912 | } else { |
| 30913 | return -((duk_double_t) (t3 + DUK_U64_CONSTANT(1))); |
| 30914 | } |
| 30915 | } else { |
| 30916 | return (duk_double_t) t3; /* XXX: cast helper */ |
| 30917 | } |
| 30918 | #endif |
| 30919 | #if 0 |
| 30920 | t3 = (duk_uint64_t) t2 * DUK_U64_CONSTANT(0x100000000) + (duk_uint64_t) t1; |
| 30921 | if (negative) { |
| 30922 | /* Simpler version: take advantage of the fact that |
| 30923 | * 0xffff'ffff'ffff'ffff and 0x1'0000'0000'0000'0000 |
| 30924 | * both round to 0x1'0000'0000'0000'0000: |
| 30925 | * > (0xffffffffffffffff).toString(16) |
| 30926 | * '10000000000000000' |
| 30927 | * > (0x10000000000000000).toString(16) |
| 30928 | * '10000000000000000' |
| 30929 | * |
| 30930 | * For the DUK_UINT64_MAX case we just skip the +1 |
| 30931 | * increment to avoid wrapping; the result still |
| 30932 | * comes out right for an IEEE double cast. |
| 30933 | */ |
| 30934 | if (t3 != DUK_UINT64_MAX) { |
| 30935 | t3++; |
| 30936 | } |
| 30937 | return -((duk_double_t) t3); |
| 30938 | } else { |
| 30939 | return (duk_double_t) t3; /* XXX: cast helper */ |
| 30940 | } |
| 30941 | #endif |
| 30942 | #if 1 |
| 30943 | /* Use two double parts, avoids dependency on 64-bit type. |
| 30944 | * Avoid precision loss carefully, especially when dealing |
| 30945 | * with the required +1 for negative values. |
| 30946 | * |
| 30947 | * No fastint check for this path at present. |
| 30948 | */ |
| 30949 | d1 = (duk_double_t) t1; /* XXX: cast helpers */ |
| 30950 | d2 = (duk_double_t) t2 * 4294967296.0; |
| 30951 | if (negative) { |
| 30952 | d1 += 1.0; |
| 30953 | } |
| 30954 | d = d2 + d1; |
| 30955 | if (negative) { |
| 30956 | d = -d; |
| 30957 | } |
| 30958 | #endif |
| 30959 | /* XXX: a push and check for fastint API would be nice */ |
| 30960 | duk_push_number(dec_ctx->thr, d); |
| 30961 | return; |
| 30962 | } |
| 30963 | |
| 30964 | duk__cbor_decode_error(dec_ctx); |
| 30965 | return; |
| 30966 | |
| 30967 | shared_exit: |
| 30968 | if (negative) { |
| 30969 | /* XXX: a push and check for fastint API would be nice */ |
| 30970 | if ((duk_uint_t) t <= (duk_uint_t) -(DUK_INT_MIN + 1)) { |
| 30971 | duk_push_int(dec_ctx->thr, -1 - ((duk_int_t) t)); |
| 30972 | } else { |
| 30973 | duk_push_number(dec_ctx->thr, -1.0 - (duk_double_t) t); |
| 30974 | } |
| 30975 | } else { |
| 30976 | duk_push_uint(dec_ctx->thr, (duk_uint_t) t); |
| 30977 | } |
| 30978 | } |
| 30979 | |
| 30980 | DUK_LOCAL void duk__cbor_decode_skip_aival_int(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) { |
| 30981 | const duk_int8_t skips[32] = { |
| 30982 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 30983 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 8, -1, -1, -1, -1 |
| 30984 | }; |
| 30985 | duk_uint8_t ai; |
| 30986 | duk_int8_t skip; |
| 30987 | |
| 30988 | ai = ib & 0x1fU; |
| 30989 | skip = skips[ai]; |
| 30990 | if (DUK_UNLIKELY(skip < 0)) { |
| 30991 | duk__cbor_decode_error(dec_ctx); |
| 30992 | } |
| 30993 | duk__cbor_decode_consume(dec_ctx, (duk_size_t) skip); |
| 30994 | return; |
| 30995 | } |
| 30996 | |
| 30997 | DUK_LOCAL duk_uint32_t duk__cbor_decode_aival_uint32(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib) { |
| 30998 | duk_uint8_t ai; |
| 30999 | duk_uint32_t t; |
| 31000 | |
| 31001 | ai = ib & 0x1fU; |
| 31002 | if (ai <= 0x17U) { |
| 31003 | return (duk_uint32_t) ai; |
| 31004 | } |
| 31005 | |
| 31006 | switch (ai) { |
| 31007 | case 0x18U: /* 1 byte */ |
| 31008 | t = (duk_uint32_t) duk__cbor_decode_readbyte(dec_ctx); |
| 31009 | return t; |
| 31010 | case 0x19U: /* 2 byte */ |
| 31011 | t = (duk_uint32_t) duk__cbor_decode_read_u16(dec_ctx); |
| 31012 | return t; |
| 31013 | case 0x1aU: /* 4 byte */ |
| 31014 | t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); |
| 31015 | return t; |
| 31016 | case 0x1bU: /* 8 byte */ |
| 31017 | t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); |
| 31018 | if (t != 0U) { |
| 31019 | break; |
| 31020 | } |
| 31021 | t = (duk_uint32_t) duk__cbor_decode_read_u32(dec_ctx); |
| 31022 | return t; |
| 31023 | } |
| 31024 | |
| 31025 | duk__cbor_decode_error(dec_ctx); |
| 31026 | return 0U; |
| 31027 | } |
| 31028 | |
| 31029 | DUK_LOCAL void duk__cbor_decode_buffer(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) { |
| 31030 | duk_uint32_t len; |
| 31031 | duk_uint8_t *buf; |
| 31032 | const duk_uint8_t *inp; |
| 31033 | duk_uint8_t ib; |
| 31034 | |
| 31035 | ib = duk__cbor_decode_readbyte(dec_ctx); |
| 31036 | if ((ib & 0xe0U) != expected_base) { |
| 31037 | duk__cbor_decode_error(dec_ctx); |
| 31038 | } |
| 31039 | /* Indefinite format is rejected by the following on purpose. */ |
| 31040 | len = duk__cbor_decode_aival_uint32(dec_ctx, ib); |
| 31041 | inp = duk__cbor_decode_consume(dec_ctx, len); |
| 31042 | /* XXX: duk_push_fixed_buffer_with_data() would be a nice API addition. */ |
| 31043 | buf = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->thr, (duk_size_t) len); |
| 31044 | duk_memcpy((void *) buf, (const void *) inp, (size_t) len); |
| 31045 | } |
| 31046 | |
| 31047 | DUK_LOCAL void duk__cbor_decode_join_buffers(duk_cbor_decode_context *dec_ctx, duk_idx_t count) { |
| 31048 | duk_size_t total_size = 0; |
| 31049 | duk_idx_t top = duk_get_top(dec_ctx->thr); |
| 31050 | duk_idx_t base = top - count; /* count is >= 1 */ |
| 31051 | duk_idx_t idx; |
| 31052 | duk_uint8_t *p = NULL; |
| 31053 | |
| 31054 | DUK_ASSERT(count >= 1); |
| 31055 | DUK_ASSERT(top >= count); |
| 31056 | |
| 31057 | for (;;) { |
| 31058 | /* First round: compute total size. |
| 31059 | * Second round: copy into place. |
| 31060 | */ |
| 31061 | for (idx = base; idx < top; idx++) { |
| 31062 | duk_uint8_t *buf_data; |
| 31063 | duk_size_t buf_size; |
| 31064 | |
| 31065 | buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->thr, idx, &buf_size); |
| 31066 | if (p != NULL) { |
| 31067 | duk_memcpy_unsafe((void *) p, (const void *) buf_data, buf_size); |
| 31068 | p += buf_size; |
| 31069 | } else { |
| 31070 | total_size += buf_size; |
| 31071 | if (DUK_UNLIKELY(total_size < buf_size)) { /* Wrap check. */ |
| 31072 | duk__cbor_decode_error(dec_ctx); |
| 31073 | } |
| 31074 | } |
| 31075 | } |
| 31076 | |
| 31077 | if (p != NULL) { |
| 31078 | break; |
| 31079 | } else { |
| 31080 | p = (duk_uint8_t *) duk_push_fixed_buffer(dec_ctx->thr, total_size); |
| 31081 | DUK_ASSERT(p != NULL); |
| 31082 | } |
| 31083 | } |
| 31084 | |
| 31085 | duk_replace(dec_ctx->thr, base); |
| 31086 | duk_pop_n(dec_ctx->thr, count - 1); |
| 31087 | } |
| 31088 | |
| 31089 | DUK_LOCAL void duk__cbor_decode_and_join_strbuf(duk_cbor_decode_context *dec_ctx, duk_uint8_t expected_base) { |
| 31090 | duk_idx_t count = 0; |
| 31091 | for (;;) { |
| 31092 | if (duk__cbor_decode_checkbreak(dec_ctx)) { |
| 31093 | break; |
| 31094 | } |
| 31095 | duk_require_stack(dec_ctx->thr, 1); |
| 31096 | duk__cbor_decode_buffer(dec_ctx, expected_base); |
| 31097 | count++; |
| 31098 | if (DUK_UNLIKELY(count <= 0)) { /* Wrap check. */ |
| 31099 | duk__cbor_decode_error(dec_ctx); |
| 31100 | } |
| 31101 | } |
| 31102 | if (count == 0) { |
| 31103 | (void) duk_push_fixed_buffer(dec_ctx->thr, 0); |
| 31104 | } else if (count > 1) { |
| 31105 | duk__cbor_decode_join_buffers(dec_ctx, count); |
| 31106 | } |
| 31107 | } |
| 31108 | |
| 31109 | DUK_LOCAL duk_double_t duk__cbor_decode_half_float(duk_cbor_decode_context *dec_ctx) { |
| 31110 | duk_double_union u; |
| 31111 | const duk_uint8_t *inp; |
| 31112 | duk_int_t expt; |
| 31113 | duk_uint_t u16; |
| 31114 | duk_uint_t tmp; |
| 31115 | duk_double_t res; |
| 31116 | |
| 31117 | inp = duk__cbor_decode_consume(dec_ctx, 2); |
| 31118 | u16 = ((duk_uint_t) inp[0] << 8) + (duk_uint_t) inp[1]; |
| 31119 | expt = (duk_int_t) ((u16 >> 10) & 0x1fU) - 15; |
| 31120 | |
| 31121 | /* Reconstruct IEEE double into little endian order first, then convert |
| 31122 | * to host order. |
| 31123 | */ |
| 31124 | |
| 31125 | duk_memzero((void *) &u, sizeof(u)); |
| 31126 | |
| 31127 | if (expt == -15) { |
| 31128 | /* Zero or denormal; but note that half float |
| 31129 | * denormals become double normals. |
| 31130 | */ |
| 31131 | if ((u16 & 0x03ffU) == 0) { |
| 31132 | u.uc[7] = inp[0] & 0x80U; |
| 31133 | } else { |
| 31134 | /* Create denormal by first creating a double that |
| 31135 | * contains the denormal bits and a leading implicit |
| 31136 | * 1-bit. Then subtract away the implicit 1-bit. |
| 31137 | * |
| 31138 | * 0.mmmmmmmmmm * 2^-14 |
| 31139 | * 1.mmmmmmmmmm 0.... * 2^-14 |
| 31140 | * -1.0000000000 0.... * 2^-14 |
| 31141 | * |
| 31142 | * Double exponent: -14 + 1023 = 0x3f1 |
| 31143 | */ |
| 31144 | u.uc[7] = 0x3fU; |
| 31145 | u.uc[6] = 0x10U + (duk_uint8_t) ((u16 >> 6) & 0x0fU); |
| 31146 | u.uc[5] = (duk_uint8_t) ((u16 << 2) & 0xffU); /* Mask is really 0xfcU */ |
| 31147 | |
| 31148 | duk_dblunion_little_to_host(&u); |
| 31149 | res = u.d - 0.00006103515625; /* 2^(-14) */ |
| 31150 | if (u16 & 0x8000U) { |
| 31151 | res = -res; |
| 31152 | } |
| 31153 | return res; |
| 31154 | } |
| 31155 | } else if (expt == 16) { |
| 31156 | /* +/- Inf or NaN. */ |
| 31157 | if ((u16 & 0x03ffU) == 0) { |
| 31158 | u.uc[7] = (inp[0] & 0x80U) + 0x7fU; |
| 31159 | u.uc[6] = 0xf0U; |
| 31160 | } else { |
| 31161 | /* Create a 'quiet NaN' with highest |
| 31162 | * bit set (there are some platforms |
| 31163 | * where the NaN payload convention is |
| 31164 | * the opposite). Keep sign. |
| 31165 | */ |
| 31166 | u.uc[7] = (inp[0] & 0x80U) + 0x7fU; |
| 31167 | u.uc[6] = 0xf8U; |
| 31168 | } |
| 31169 | } else { |
| 31170 | /* Normal. */ |
| 31171 | tmp = (inp[0] & 0x80U) ? 0x80000000UL : 0UL; |
| 31172 | tmp += (duk_uint_t) (expt + 1023) << 20; |
| 31173 | tmp += (duk_uint_t) (inp[0] & 0x03U) << 18; |
| 31174 | tmp += (duk_uint_t) (inp[1] & 0xffU) << 10; |
| 31175 | u.uc[7] = (tmp >> 24) & 0xffU; |
| 31176 | u.uc[6] = (tmp >> 16) & 0xffU; |
| 31177 | u.uc[5] = (tmp >> 8) & 0xffU; |
| 31178 | u.uc[4] = (tmp >> 0) & 0xffU; |
| 31179 | } |
| 31180 | |
| 31181 | duk_dblunion_little_to_host(&u); |
| 31182 | return u.d; |
| 31183 | } |
| 31184 | |
| 31185 | DUK_LOCAL void duk__cbor_decode_string(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) { |
| 31186 | /* If the CBOR string data is not valid UTF-8 it is technically |
| 31187 | * invalid CBOR. Possible behaviors at least: |
| 31188 | * |
| 31189 | * 1. Reject the input, i.e. throw TypeError. |
| 31190 | * |
| 31191 | * 2. Accept the input, but sanitize non-UTF-8 data into UTF-8 |
| 31192 | * using U+FFFD replacements. Also it might make sense to |
| 31193 | * decode non-BMP codepoints into surrogates for better |
| 31194 | * ECMAScript compatibility. |
| 31195 | * |
| 31196 | * 3. Accept the input as a Duktape string (which are not always |
| 31197 | * valid UTF-8), but reject any input that would create a |
| 31198 | * Symbol representation. |
| 31199 | * |
| 31200 | * Current behavior is 3. |
| 31201 | */ |
| 31202 | |
| 31203 | if (ai == 0x1fU) { |
| 31204 | duk_uint8_t *buf_data; |
| 31205 | duk_size_t buf_size; |
| 31206 | |
| 31207 | duk__cbor_decode_and_join_strbuf(dec_ctx, 0x60U); |
| 31208 | buf_data = (duk_uint8_t *) duk_require_buffer(dec_ctx->thr, -1, &buf_size); |
| 31209 | (void) duk_push_lstring(dec_ctx->thr, (const char *) buf_data, buf_size); |
| 31210 | duk_remove(dec_ctx->thr, -2); |
| 31211 | } else { |
| 31212 | duk_uint32_t len; |
| 31213 | const duk_uint8_t *inp; |
| 31214 | |
| 31215 | len = duk__cbor_decode_aival_uint32(dec_ctx, ib); |
| 31216 | inp = duk__cbor_decode_consume(dec_ctx, len); |
| 31217 | (void) duk_push_lstring(dec_ctx->thr, (const char *) inp, (duk_size_t) len); |
| 31218 | } |
| 31219 | if (duk_is_symbol(dec_ctx->thr, -1)) { |
| 31220 | /* Refuse to create Symbols when decoding. */ |
| 31221 | duk__cbor_decode_error(dec_ctx); |
| 31222 | } |
| 31223 | |
| 31224 | /* XXX: Here a Duktape API call to convert input -> utf-8 with |
| 31225 | * replacements would be nice. |
| 31226 | */ |
| 31227 | } |
| 31228 | |
| 31229 | DUK_LOCAL duk_bool_t duk__cbor_decode_array(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) { |
| 31230 | duk_uint32_t idx, len; |
| 31231 | |
| 31232 | duk__cbor_decode_objarr_entry(dec_ctx); |
| 31233 | |
| 31234 | /* Support arrays up to 0xfffffffeU in length. 0xffffffff is |
| 31235 | * used as an indefinite length marker. |
| 31236 | */ |
| 31237 | if (ai == 0x1fU) { |
| 31238 | len = 0xffffffffUL; |
| 31239 | } else { |
| 31240 | len = duk__cbor_decode_aival_uint32(dec_ctx, ib); |
| 31241 | if (len == 0xffffffffUL) { |
| 31242 | goto failure; |
| 31243 | } |
| 31244 | } |
| 31245 | |
| 31246 | /* XXX: use bare array? */ |
| 31247 | duk_push_array(dec_ctx->thr); |
| 31248 | for (idx = 0U; ;) { |
| 31249 | if (len == 0xffffffffUL && duk__cbor_decode_checkbreak(dec_ctx)) { |
| 31250 | break; |
| 31251 | } |
| 31252 | if (idx == len) { |
| 31253 | if (ai == 0x1fU) { |
| 31254 | goto failure; |
| 31255 | } |
| 31256 | break; |
| 31257 | } |
| 31258 | duk__cbor_decode_value(dec_ctx); |
| 31259 | duk_put_prop_index(dec_ctx->thr, -2, (duk_uarridx_t) idx); |
| 31260 | idx++; |
| 31261 | if (idx == 0U) { |
| 31262 | goto failure; /* wrapped */ |
| 31263 | } |
| 31264 | } |
| 31265 | |
| 31266 | #if 0 |
| 31267 | success: |
| 31268 | #endif |
| 31269 | duk__cbor_decode_objarr_exit(dec_ctx); |
| 31270 | return 1; |
| 31271 | |
| 31272 | failure: |
| 31273 | /* No need to unwind recursion checks, caller will throw. */ |
| 31274 | return 0; |
| 31275 | } |
| 31276 | |
| 31277 | DUK_LOCAL duk_bool_t duk__cbor_decode_map(duk_cbor_decode_context *dec_ctx, duk_uint8_t ib, duk_uint8_t ai) { |
| 31278 | duk_uint32_t count; |
| 31279 | |
| 31280 | duk__cbor_decode_objarr_entry(dec_ctx); |
| 31281 | |
| 31282 | if (ai == 0x1fU) { |
| 31283 | count = 0xffffffffUL; |
| 31284 | } else { |
| 31285 | count = duk__cbor_decode_aival_uint32(dec_ctx, ib); |
| 31286 | if (count == 0xffffffffUL) { |
| 31287 | goto failure; |
| 31288 | } |
| 31289 | } |
| 31290 | |
| 31291 | /* XXX: use bare object? */ |
| 31292 | duk_push_object(dec_ctx->thr); |
| 31293 | for (;;) { |
| 31294 | if (count == 0xffffffffUL) { |
| 31295 | if (duk__cbor_decode_checkbreak(dec_ctx)) { |
| 31296 | break; |
| 31297 | } |
| 31298 | } else { |
| 31299 | if (count == 0UL) { |
| 31300 | break; |
| 31301 | } |
| 31302 | count--; |
| 31303 | } |
| 31304 | |
| 31305 | /* Non-string keys are coerced to strings, |
| 31306 | * possibly leading to overwriting previous |
| 31307 | * keys. Last key of a certain coerced name |
| 31308 | * wins. If key is an object, it will coerce |
| 31309 | * to '[object Object]' which is consistent |
| 31310 | * but potentially misleading. One alternative |
| 31311 | * would be to skip non-string keys. |
| 31312 | */ |
| 31313 | duk__cbor_decode_value(dec_ctx); |
| 31314 | duk__cbor_decode_value(dec_ctx); |
| 31315 | duk_put_prop(dec_ctx->thr, -3); |
| 31316 | } |
| 31317 | |
| 31318 | #if 0 |
| 31319 | success: |
| 31320 | #endif |
| 31321 | duk__cbor_decode_objarr_exit(dec_ctx); |
| 31322 | return 1; |
| 31323 | |
| 31324 | failure: |
| 31325 | /* No need to unwind recursion checks, caller will throw. */ |
| 31326 | return 0; |
| 31327 | } |
| 31328 | |
| 31329 | DUK_LOCAL duk_double_t duk__cbor_decode_float(duk_cbor_decode_context *dec_ctx) { |
| 31330 | duk_float_union u; |
| 31331 | const duk_uint8_t *inp; |
| 31332 | inp = duk__cbor_decode_consume(dec_ctx, 4); |
| 31333 | duk_memcpy((void *) u.uc, (const void *) inp, 4); |
| 31334 | duk_fltunion_big_to_host(&u); |
| 31335 | return (duk_double_t) u.f; |
| 31336 | } |
| 31337 | |
| 31338 | DUK_LOCAL duk_double_t duk__cbor_decode_double(duk_cbor_decode_context *dec_ctx) { |
| 31339 | duk_double_union u; |
| 31340 | const duk_uint8_t *inp; |
| 31341 | inp = duk__cbor_decode_consume(dec_ctx, 8); |
| 31342 | duk_memcpy((void *) u.uc, (const void *) inp, 8); |
| 31343 | duk_dblunion_big_to_host(&u); |
| 31344 | return u.d; |
| 31345 | } |
| 31346 | |
| 31347 | #if defined(DUK_CBOR_DECODE_FASTPATH) |
| 31348 | #define DUK__CBOR_AI (ib & 0x1fU) |
| 31349 | |
| 31350 | DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) { |
| 31351 | duk_uint8_t ib; |
| 31352 | |
| 31353 | /* Any paths potentially recursing back to duk__cbor_decode_value() |
| 31354 | * must perform a Duktape value stack growth check. Avoid the check |
| 31355 | * here for simple paths like primitive values. |
| 31356 | */ |
| 31357 | |
| 31358 | reread_initial_byte: |
| 31359 | DUK_DDD(DUK_DDDPRINT("cbor decode off=%ld len=%ld" , (long) dec_ctx->off, (long) dec_ctx->len)); |
| 31360 | |
| 31361 | ib = duk__cbor_decode_readbyte(dec_ctx); |
| 31362 | |
| 31363 | /* Full initial byte switch, footprint cost over baseline is ~+1kB. */ |
| 31364 | /* XXX: Force full switch with no range check. */ |
| 31365 | |
| 31366 | switch (ib) { |
| 31367 | case 0x00U: case 0x01U: case 0x02U: case 0x03U: case 0x04U: case 0x05U: case 0x06U: case 0x07U: |
| 31368 | case 0x08U: case 0x09U: case 0x0aU: case 0x0bU: case 0x0cU: case 0x0dU: case 0x0eU: case 0x0fU: |
| 31369 | case 0x10U: case 0x11U: case 0x12U: case 0x13U: case 0x14U: case 0x15U: case 0x16U: case 0x17U: |
| 31370 | duk_push_uint(dec_ctx->thr, ib); |
| 31371 | break; |
| 31372 | case 0x18U: case 0x19U: case 0x1aU: case 0x1bU: |
| 31373 | duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/); |
| 31374 | break; |
| 31375 | case 0x1cU: case 0x1dU: case 0x1eU: case 0x1fU: |
| 31376 | goto format_error; |
| 31377 | case 0x20U: case 0x21U: case 0x22U: case 0x23U: case 0x24U: case 0x25U: case 0x26U: case 0x27U: |
| 31378 | case 0x28U: case 0x29U: case 0x2aU: case 0x2bU: case 0x2cU: case 0x2dU: case 0x2eU: case 0x2fU: |
| 31379 | case 0x30U: case 0x31U: case 0x32U: case 0x33U: case 0x34U: case 0x35U: case 0x36U: case 0x37U: |
| 31380 | duk_push_int(dec_ctx->thr, -((duk_int_t) ((ib - 0x20U) + 1U))); |
| 31381 | break; |
| 31382 | case 0x38U: case 0x39U: case 0x3aU: case 0x3bU: |
| 31383 | duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/); |
| 31384 | break; |
| 31385 | case 0x3cU: case 0x3dU: case 0x3eU: case 0x3fU: |
| 31386 | goto format_error; |
| 31387 | case 0x40U: case 0x41U: case 0x42U: case 0x43U: case 0x44U: case 0x45U: case 0x46U: case 0x47U: |
| 31388 | case 0x48U: case 0x49U: case 0x4aU: case 0x4bU: case 0x4cU: case 0x4dU: case 0x4eU: case 0x4fU: |
| 31389 | case 0x50U: case 0x51U: case 0x52U: case 0x53U: case 0x54U: case 0x55U: case 0x56U: case 0x57U: |
| 31390 | /* XXX: Avoid rewind, we know the length already. */ |
| 31391 | DUK_ASSERT(dec_ctx->off > 0U); |
| 31392 | dec_ctx->off--; |
| 31393 | duk__cbor_decode_buffer(dec_ctx, 0x40U); |
| 31394 | break; |
| 31395 | case 0x58U: case 0x59U: case 0x5aU: case 0x5bU: |
| 31396 | /* XXX: Avoid rewind, decode length inline. */ |
| 31397 | DUK_ASSERT(dec_ctx->off > 0U); |
| 31398 | dec_ctx->off--; |
| 31399 | duk__cbor_decode_buffer(dec_ctx, 0x40U); |
| 31400 | break; |
| 31401 | case 0x5cU: case 0x5dU: case 0x5eU: |
| 31402 | goto format_error; |
| 31403 | case 0x5fU: |
| 31404 | duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U); |
| 31405 | break; |
| 31406 | case 0x60U: case 0x61U: case 0x62U: case 0x63U: case 0x64U: case 0x65U: case 0x66U: case 0x67U: |
| 31407 | case 0x68U: case 0x69U: case 0x6aU: case 0x6bU: case 0x6cU: case 0x6dU: case 0x6eU: case 0x6fU: |
| 31408 | case 0x70U: case 0x71U: case 0x72U: case 0x73U: case 0x74U: case 0x75U: case 0x76U: case 0x77U: |
| 31409 | /* XXX: Avoid double decode of length. */ |
| 31410 | duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI); |
| 31411 | break; |
| 31412 | case 0x78U: case 0x79U: case 0x7aU: case 0x7bU: |
| 31413 | /* XXX: Avoid double decode of length. */ |
| 31414 | duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI); |
| 31415 | break; |
| 31416 | case 0x7cU: case 0x7dU: case 0x7eU: |
| 31417 | goto format_error; |
| 31418 | case 0x7fU: |
| 31419 | duk__cbor_decode_string(dec_ctx, ib, DUK__CBOR_AI); |
| 31420 | break; |
| 31421 | case 0x80U: case 0x81U: case 0x82U: case 0x83U: case 0x84U: case 0x85U: case 0x86U: case 0x87U: |
| 31422 | case 0x88U: case 0x89U: case 0x8aU: case 0x8bU: case 0x8cU: case 0x8dU: case 0x8eU: case 0x8fU: |
| 31423 | case 0x90U: case 0x91U: case 0x92U: case 0x93U: case 0x94U: case 0x95U: case 0x96U: case 0x97U: |
| 31424 | if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) { |
| 31425 | goto format_error; |
| 31426 | } |
| 31427 | break; |
| 31428 | case 0x98U: case 0x99U: case 0x9aU: case 0x9bU: |
| 31429 | if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) { |
| 31430 | goto format_error; |
| 31431 | } |
| 31432 | break; |
| 31433 | case 0x9cU: case 0x9dU: case 0x9eU: |
| 31434 | goto format_error; |
| 31435 | case 0x9fU: |
| 31436 | if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, DUK__CBOR_AI) == 0)) { |
| 31437 | goto format_error; |
| 31438 | } |
| 31439 | break; |
| 31440 | case 0xa0U: case 0xa1U: case 0xa2U: case 0xa3U: case 0xa4U: case 0xa5U: case 0xa6U: case 0xa7U: |
| 31441 | case 0xa8U: case 0xa9U: case 0xaaU: case 0xabU: case 0xacU: case 0xadU: case 0xaeU: case 0xafU: |
| 31442 | case 0xb0U: case 0xb1U: case 0xb2U: case 0xb3U: case 0xb4U: case 0xb5U: case 0xb6U: case 0xb7U: |
| 31443 | if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) { |
| 31444 | goto format_error; |
| 31445 | } |
| 31446 | break; |
| 31447 | case 0xb8U: case 0xb9U: case 0xbaU: case 0xbbU: |
| 31448 | if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) { |
| 31449 | goto format_error; |
| 31450 | } |
| 31451 | break; |
| 31452 | case 0xbcU: case 0xbdU: case 0xbeU: |
| 31453 | goto format_error; |
| 31454 | case 0xbfU: |
| 31455 | if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, DUK__CBOR_AI) == 0)) { |
| 31456 | goto format_error; |
| 31457 | } |
| 31458 | break; |
| 31459 | case 0xc0U: case 0xc1U: case 0xc2U: case 0xc3U: case 0xc4U: case 0xc5U: case 0xc6U: case 0xc7U: |
| 31460 | case 0xc8U: case 0xc9U: case 0xcaU: case 0xcbU: case 0xccU: case 0xcdU: case 0xceU: case 0xcfU: |
| 31461 | case 0xd0U: case 0xd1U: case 0xd2U: case 0xd3U: case 0xd4U: case 0xd5U: case 0xd6U: case 0xd7U: |
| 31462 | /* Tag 0-23: drop. */ |
| 31463 | goto reread_initial_byte; |
| 31464 | case 0xd8U: case 0xd9U: case 0xdaU: case 0xdbU: |
| 31465 | duk__cbor_decode_skip_aival_int(dec_ctx, ib); |
| 31466 | goto reread_initial_byte; |
| 31467 | case 0xdcU: case 0xddU: case 0xdeU: case 0xdfU: |
| 31468 | goto format_error; |
| 31469 | case 0xe0U: |
| 31470 | goto format_error; |
| 31471 | case 0xe1U: |
| 31472 | goto format_error; |
| 31473 | case 0xe2U: |
| 31474 | goto format_error; |
| 31475 | case 0xe3U: |
| 31476 | goto format_error; |
| 31477 | case 0xe4U: |
| 31478 | goto format_error; |
| 31479 | case 0xe5U: |
| 31480 | goto format_error; |
| 31481 | case 0xe6U: |
| 31482 | goto format_error; |
| 31483 | case 0xe7U: |
| 31484 | goto format_error; |
| 31485 | case 0xe8U: |
| 31486 | goto format_error; |
| 31487 | case 0xe9U: |
| 31488 | goto format_error; |
| 31489 | case 0xeaU: |
| 31490 | goto format_error; |
| 31491 | case 0xebU: |
| 31492 | goto format_error; |
| 31493 | case 0xecU: |
| 31494 | goto format_error; |
| 31495 | case 0xedU: |
| 31496 | goto format_error; |
| 31497 | case 0xeeU: |
| 31498 | goto format_error; |
| 31499 | case 0xefU: |
| 31500 | goto format_error; |
| 31501 | case 0xf0U: |
| 31502 | goto format_error; |
| 31503 | case 0xf1U: |
| 31504 | goto format_error; |
| 31505 | case 0xf2U: |
| 31506 | goto format_error; |
| 31507 | case 0xf3U: |
| 31508 | goto format_error; |
| 31509 | case 0xf4U: |
| 31510 | duk_push_false(dec_ctx->thr); |
| 31511 | break; |
| 31512 | case 0xf5U: |
| 31513 | duk_push_true(dec_ctx->thr); |
| 31514 | break; |
| 31515 | case 0xf6U: |
| 31516 | duk_push_null(dec_ctx->thr); |
| 31517 | break; |
| 31518 | case 0xf7U: |
| 31519 | duk_push_undefined(dec_ctx->thr); |
| 31520 | break; |
| 31521 | case 0xf8U: |
| 31522 | /* Simple value 32-255, nothing defined yet, so reject. */ |
| 31523 | goto format_error; |
| 31524 | case 0xf9U: { |
| 31525 | duk_double_t d; |
| 31526 | d = duk__cbor_decode_half_float(dec_ctx); |
| 31527 | duk_push_number(dec_ctx->thr, d); |
| 31528 | break; |
| 31529 | } |
| 31530 | case 0xfaU: { |
| 31531 | duk_double_t d; |
| 31532 | d = duk__cbor_decode_float(dec_ctx); |
| 31533 | duk_push_number(dec_ctx->thr, d); |
| 31534 | break; |
| 31535 | } |
| 31536 | case 0xfbU: { |
| 31537 | duk_double_t d; |
| 31538 | d = duk__cbor_decode_double(dec_ctx); |
| 31539 | duk_push_number(dec_ctx->thr, d); |
| 31540 | break; |
| 31541 | } |
| 31542 | case 0xfcU: |
| 31543 | case 0xfdU: |
| 31544 | case 0xfeU: |
| 31545 | case 0xffU: |
| 31546 | goto format_error; |
| 31547 | } /* end switch */ |
| 31548 | |
| 31549 | return; |
| 31550 | |
| 31551 | format_error: |
| 31552 | duk__cbor_decode_error(dec_ctx); |
| 31553 | } |
| 31554 | #else /* DUK_CBOR_DECODE_FASTPATH */ |
| 31555 | DUK_LOCAL void duk__cbor_decode_value(duk_cbor_decode_context *dec_ctx) { |
| 31556 | duk_uint8_t ib, mt, ai; |
| 31557 | |
| 31558 | /* Any paths potentially recursing back to duk__cbor_decode_value() |
| 31559 | * must perform a Duktape value stack growth check. Avoid the check |
| 31560 | * here for simple paths like primitive values. |
| 31561 | */ |
| 31562 | |
| 31563 | reread_initial_byte: |
| 31564 | DUK_DDD(DUK_DDDPRINT("cbor decode off=%ld len=%ld" , (long) dec_ctx->off, (long) dec_ctx->len)); |
| 31565 | |
| 31566 | ib = duk__cbor_decode_readbyte(dec_ctx); |
| 31567 | mt = ib >> 5U; |
| 31568 | ai = ib & 0x1fU; |
| 31569 | |
| 31570 | /* Additional information in [24,27] = [0x18,0x1b] has relatively |
| 31571 | * uniform handling for all major types: read 1/2/4/8 additional |
| 31572 | * bytes. For major type 7 the 1-byte value is a 'simple type', and |
| 31573 | * 2/4/8-byte values are floats. For other major types the 1/2/4/8 |
| 31574 | * byte values are integers. The lengths are uniform, but the typing |
| 31575 | * is not. |
| 31576 | */ |
| 31577 | |
| 31578 | switch (mt) { |
| 31579 | case 0U: { /* unsigned integer */ |
| 31580 | duk__cbor_decode_push_aival_int(dec_ctx, ib, 0 /*negative*/); |
| 31581 | break; |
| 31582 | } |
| 31583 | case 1U: { /* negative integer */ |
| 31584 | duk__cbor_decode_push_aival_int(dec_ctx, ib, 1 /*negative*/); |
| 31585 | break; |
| 31586 | } |
| 31587 | case 2U: { /* byte string */ |
| 31588 | if (ai == 0x1fU) { |
| 31589 | duk__cbor_decode_and_join_strbuf(dec_ctx, 0x40U); |
| 31590 | } else { |
| 31591 | duk__cbor_decode_rewind(dec_ctx, 1U); |
| 31592 | duk__cbor_decode_buffer(dec_ctx, 0x40U); |
| 31593 | } |
| 31594 | break; |
| 31595 | } |
| 31596 | case 3U: { /* text string */ |
| 31597 | duk__cbor_decode_string(dec_ctx, ib, ai); |
| 31598 | break; |
| 31599 | } |
| 31600 | case 4U: { /* array of data items */ |
| 31601 | if (DUK_UNLIKELY(duk__cbor_decode_array(dec_ctx, ib, ai) == 0)) { |
| 31602 | goto format_error; |
| 31603 | } |
| 31604 | break; |
| 31605 | } |
| 31606 | case 5U: { /* map of pairs of data items */ |
| 31607 | if (DUK_UNLIKELY(duk__cbor_decode_map(dec_ctx, ib, ai) == 0)) { |
| 31608 | goto format_error; |
| 31609 | } |
| 31610 | break; |
| 31611 | } |
| 31612 | case 6U: { /* semantic tagging */ |
| 31613 | /* Tags are ignored now, re-read initial byte. A tagged |
| 31614 | * value may itself be tagged (an unlimited number of times) |
| 31615 | * so keep on peeling away tags. |
| 31616 | */ |
| 31617 | duk__cbor_decode_skip_aival_int(dec_ctx, ib); |
| 31618 | goto reread_initial_byte; |
| 31619 | } |
| 31620 | case 7U: { /* floating point numbers, simple data types, break; other */ |
| 31621 | switch (ai) { |
| 31622 | case 0x14U: { |
| 31623 | duk_push_false(dec_ctx->thr); |
| 31624 | break; |
| 31625 | } |
| 31626 | case 0x15U: { |
| 31627 | duk_push_true(dec_ctx->thr); |
| 31628 | break; |
| 31629 | } |
| 31630 | case 0x16U: { |
| 31631 | duk_push_null(dec_ctx->thr); |
| 31632 | break; |
| 31633 | } |
| 31634 | case 0x17U: { |
| 31635 | duk_push_undefined(dec_ctx->thr); |
| 31636 | break; |
| 31637 | } |
| 31638 | case 0x18U: { /* more simple values (1 byte) */ |
| 31639 | /* Simple value encoded in additional byte (none |
| 31640 | * are defined so far). RFC 7049 states that the |
| 31641 | * follow-up byte must be 32-255 to minimize |
| 31642 | * confusion. So, a non-shortest encoding like |
| 31643 | * f815 (= true, shortest encoding f5) must be |
| 31644 | * rejected. cbor.me tester rejects f815, but |
| 31645 | * e.g. Python CBOR binding decodes it as true. |
| 31646 | */ |
| 31647 | goto format_error; |
| 31648 | } |
| 31649 | case 0x19U: { /* half-float (2 bytes) */ |
| 31650 | duk_double_t d; |
| 31651 | d = duk__cbor_decode_half_float(dec_ctx); |
| 31652 | duk_push_number(dec_ctx->thr, d); |
| 31653 | break; |
| 31654 | } |
| 31655 | case 0x1aU: { /* float (4 bytes) */ |
| 31656 | duk_double_t d; |
| 31657 | d = duk__cbor_decode_float(dec_ctx); |
| 31658 | duk_push_number(dec_ctx->thr, d); |
| 31659 | break; |
| 31660 | } |
| 31661 | case 0x1bU: { /* double (8 bytes) */ |
| 31662 | duk_double_t d; |
| 31663 | d = duk__cbor_decode_double(dec_ctx); |
| 31664 | duk_push_number(dec_ctx->thr, d); |
| 31665 | break; |
| 31666 | } |
| 31667 | case 0xffU: /* unexpected break */ |
| 31668 | default: { |
| 31669 | goto format_error; |
| 31670 | } |
| 31671 | } /* end switch */ |
| 31672 | break; |
| 31673 | } |
| 31674 | default: { |
| 31675 | goto format_error; /* will never actually occur */ |
| 31676 | } |
| 31677 | } /* end switch */ |
| 31678 | |
| 31679 | return; |
| 31680 | |
| 31681 | format_error: |
| 31682 | duk__cbor_decode_error(dec_ctx); |
| 31683 | } |
| 31684 | #endif /* DUK_CBOR_DECODE_FASTPATH */ |
| 31685 | |
| 31686 | DUK_LOCAL void duk__cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) { |
| 31687 | duk_cbor_encode_context enc_ctx; |
| 31688 | duk_uint8_t *buf; |
| 31689 | |
| 31690 | DUK_UNREF(encode_flags); |
| 31691 | |
| 31692 | idx = duk_require_normalize_index(thr, idx); |
| 31693 | |
| 31694 | enc_ctx.thr = thr; |
| 31695 | enc_ctx.idx_buf = duk_get_top(thr); |
| 31696 | |
| 31697 | enc_ctx.len = 64; |
| 31698 | buf = (duk_uint8_t *) duk_push_dynamic_buffer(thr, enc_ctx.len); |
| 31699 | enc_ctx.ptr = buf; |
| 31700 | enc_ctx.buf = buf; |
| 31701 | enc_ctx.buf_end = buf + enc_ctx.len; |
| 31702 | |
| 31703 | enc_ctx.recursion_depth = 0; |
| 31704 | enc_ctx.recursion_limit = DUK_USE_CBOR_ENC_RECLIMIT; |
| 31705 | |
| 31706 | duk_dup(thr, idx); |
| 31707 | duk__cbor_encode_req_stack(&enc_ctx); |
| 31708 | duk__cbor_encode_value(&enc_ctx); |
| 31709 | DUK_ASSERT(enc_ctx.recursion_depth == 0); |
| 31710 | duk_resize_buffer(enc_ctx.thr, enc_ctx.idx_buf, (duk_size_t) (enc_ctx.ptr - enc_ctx.buf)); |
| 31711 | duk_replace(thr, idx); |
| 31712 | } |
| 31713 | |
| 31714 | DUK_LOCAL void duk__cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) { |
| 31715 | duk_cbor_decode_context dec_ctx; |
| 31716 | |
| 31717 | DUK_UNREF(decode_flags); |
| 31718 | |
| 31719 | /* Suppress compile warnings for functions only needed with e.g. |
| 31720 | * asserts enabled. |
| 31721 | */ |
| 31722 | DUK_UNREF(duk__cbor_get_reserve); |
| 31723 | |
| 31724 | idx = duk_require_normalize_index(thr, idx); |
| 31725 | |
| 31726 | dec_ctx.thr = thr; |
| 31727 | dec_ctx.buf = (const duk_uint8_t *) duk_require_buffer_data(thr, idx, &dec_ctx.len); |
| 31728 | dec_ctx.off = 0; |
| 31729 | /* dec_ctx.len: set above */ |
| 31730 | |
| 31731 | dec_ctx.recursion_depth = 0; |
| 31732 | dec_ctx.recursion_limit = DUK_USE_CBOR_DEC_RECLIMIT; |
| 31733 | |
| 31734 | duk__cbor_decode_req_stack(&dec_ctx); |
| 31735 | duk__cbor_decode_value(&dec_ctx); |
| 31736 | DUK_ASSERT(dec_ctx.recursion_depth == 0); |
| 31737 | if (dec_ctx.off != dec_ctx.len) { |
| 31738 | (void) duk_type_error(thr, "trailing garbage" ); |
| 31739 | } |
| 31740 | |
| 31741 | duk_replace(thr, idx); |
| 31742 | } |
| 31743 | |
| 31744 | #else /* DUK_USE_CBOR_SUPPORT */ |
| 31745 | |
| 31746 | DUK_LOCAL void duk__cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) { |
| 31747 | DUK_UNREF(idx); |
| 31748 | DUK_UNREF(encode_flags); |
| 31749 | DUK_ERROR_UNSUPPORTED(thr); |
| 31750 | } |
| 31751 | |
| 31752 | DUK_LOCAL void duk__cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) { |
| 31753 | DUK_UNREF(idx); |
| 31754 | DUK_UNREF(decode_flags); |
| 31755 | DUK_ERROR_UNSUPPORTED(thr); |
| 31756 | } |
| 31757 | |
| 31758 | #endif /* DUK_USE_CBOR_SUPPORT */ |
| 31759 | |
| 31760 | /* |
| 31761 | * Public APIs |
| 31762 | */ |
| 31763 | |
| 31764 | DUK_EXTERNAL void duk_cbor_encode(duk_hthread *thr, duk_idx_t idx, duk_uint_t encode_flags) { |
| 31765 | DUK_ASSERT_API_ENTRY(thr); |
| 31766 | duk__cbor_encode(thr, idx, encode_flags); |
| 31767 | } |
| 31768 | DUK_EXTERNAL void duk_cbor_decode(duk_hthread *thr, duk_idx_t idx, duk_uint_t decode_flags) { |
| 31769 | DUK_ASSERT_API_ENTRY(thr); |
| 31770 | duk__cbor_decode(thr, idx, decode_flags); |
| 31771 | } |
| 31772 | |
| 31773 | #if defined(DUK_USE_CBOR_BUILTIN) |
| 31774 | #if defined(DUK_USE_CBOR_SUPPORT) |
| 31775 | DUK_INTERNAL duk_ret_t duk_bi_cbor_encode(duk_hthread *thr) { |
| 31776 | DUK_ASSERT_TOP(thr, 1); |
| 31777 | |
| 31778 | duk__cbor_encode(thr, -1, 0 /*flags*/); |
| 31779 | |
| 31780 | /* Produce an ArrayBuffer by first decoding into a plain buffer which |
| 31781 | * mimics a Uint8Array and gettings its .buffer property. |
| 31782 | */ |
| 31783 | /* XXX: shortcut */ |
| 31784 | (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_LC_BUFFER); |
| 31785 | return 1; |
| 31786 | } |
| 31787 | |
| 31788 | DUK_INTERNAL duk_ret_t duk_bi_cbor_decode(duk_hthread *thr) { |
| 31789 | DUK_ASSERT_TOP(thr, 1); |
| 31790 | |
| 31791 | duk__cbor_decode(thr, -1, 0 /*flags*/); |
| 31792 | return 1; |
| 31793 | } |
| 31794 | #else /* DUK_USE_CBOR_SUPPORT */ |
| 31795 | DUK_INTERNAL duk_ret_t duk_bi_cbor_encode(duk_hthread *thr) { |
| 31796 | DUK_ERROR_UNSUPPORTED(thr); |
| 31797 | DUK_WO_NORETURN(return 0;); |
| 31798 | } |
| 31799 | DUK_INTERNAL duk_ret_t duk_bi_cbor_decode(duk_hthread *thr) { |
| 31800 | DUK_ERROR_UNSUPPORTED(thr); |
| 31801 | DUK_WO_NORETURN(return 0;); |
| 31802 | } |
| 31803 | #endif /* DUK_USE_CBOR_SUPPORT */ |
| 31804 | #endif /* DUK_USE_CBOR_BUILTIN */ |
| 31805 | |
| 31806 | /* automatic undefs */ |
| 31807 | #undef DUK__CBOR_AI |
| 31808 | #line 1 "duk_bi_date.c" |
| 31809 | /* |
| 31810 | * Date built-ins |
| 31811 | * |
| 31812 | * Unlike most built-ins, Date has some platform dependencies for getting |
| 31813 | * UTC time, converting between UTC and local time, and parsing and |
| 31814 | * formatting time values. These are all abstracted behind DUK_USE_xxx |
| 31815 | * config options. There are built-in platform specific providers for |
| 31816 | * POSIX and Windows, but external providers can also be used. |
| 31817 | * |
| 31818 | * See doc/datetime.rst. |
| 31819 | * |
| 31820 | */ |
| 31821 | |
| 31822 | /* #include duk_internal.h -> already included */ |
| 31823 | |
| 31824 | /* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */ |
| 31825 | |
| 31826 | /* |
| 31827 | * Forward declarations |
| 31828 | */ |
| 31829 | |
| 31830 | DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset); |
| 31831 | DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags); |
| 31832 | DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val); |
| 31833 | DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags); |
| 31834 | |
| 31835 | /* |
| 31836 | * Other file level defines |
| 31837 | */ |
| 31838 | |
| 31839 | /* Debug macro to print all parts and dparts (used manually because of debug level). */ |
| 31840 | #define DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts) do { \ |
| 31841 | DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \ |
| 31842 | (long) (parts)[0], (long) (parts)[1], \ |
| 31843 | (long) (parts)[2], (long) (parts)[3], \ |
| 31844 | (long) (parts)[4], (long) (parts)[5], \ |
| 31845 | (long) (parts)[6], (long) (parts)[7], \ |
| 31846 | (double) (dparts)[0], (double) (dparts)[1], \ |
| 31847 | (double) (dparts)[2], (double) (dparts)[3], \ |
| 31848 | (double) (dparts)[4], (double) (dparts)[5], \ |
| 31849 | (double) (dparts)[6], (double) (dparts)[7])); \ |
| 31850 | } while (0) |
| 31851 | #define DUK__DPRINT_PARTS(parts) do { \ |
| 31852 | DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \ |
| 31853 | (long) (parts)[0], (long) (parts)[1], \ |
| 31854 | (long) (parts)[2], (long) (parts)[3], \ |
| 31855 | (long) (parts)[4], (long) (parts)[5], \ |
| 31856 | (long) (parts)[6], (long) (parts)[7])); \ |
| 31857 | } while (0) |
| 31858 | #define DUK__DPRINT_DPARTS(dparts) do { \ |
| 31859 | DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \ |
| 31860 | (double) (dparts)[0], (double) (dparts)[1], \ |
| 31861 | (double) (dparts)[2], (double) (dparts)[3], \ |
| 31862 | (double) (dparts)[4], (double) (dparts)[5], \ |
| 31863 | (double) (dparts)[6], (double) (dparts)[7])); \ |
| 31864 | } while (0) |
| 31865 | |
| 31866 | /* Equivalent year for DST calculations outside [1970,2038[ range, see |
| 31867 | * E5 Section 15.9.1.8. Equivalent year has the same leap-year-ness and |
| 31868 | * starts with the same weekday on Jan 1. |
| 31869 | * https://bugzilla.mozilla.org/show_bug.cgi?id=351066 |
| 31870 | */ |
| 31871 | #define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970)) |
| 31872 | DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = { |
| 31873 | #if 1 |
| 31874 | /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py): |
| 31875 | * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146 |
| 31876 | */ |
| 31877 | |
| 31878 | /* non-leap year: sunday, monday, ... */ |
| 31879 | DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031), |
| 31880 | DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011), |
| 31881 | |
| 31882 | /* leap year: sunday, monday, ... */ |
| 31883 | DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020), |
| 31884 | DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028) |
| 31885 | #endif |
| 31886 | |
| 31887 | #if 0 |
| 31888 | /* This is based on Rhino EquivalentYear() algorithm: |
| 31889 | * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java |
| 31890 | */ |
| 31891 | |
| 31892 | /* non-leap year: sunday, monday, ... */ |
| 31893 | DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986), |
| 31894 | DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977), |
| 31895 | |
| 31896 | /* leap year: sunday, monday, ... */ |
| 31897 | DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992), |
| 31898 | DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972) |
| 31899 | #endif |
| 31900 | }; |
| 31901 | |
| 31902 | /* |
| 31903 | * ISO 8601 subset parser. |
| 31904 | */ |
| 31905 | |
| 31906 | /* Parser part count. */ |
| 31907 | #define DUK__NUM_ISO8601_PARSER_PARTS 9 |
| 31908 | |
| 31909 | /* Parser part indices. */ |
| 31910 | #define DUK__PI_YEAR 0 |
| 31911 | #define DUK__PI_MONTH 1 |
| 31912 | #define DUK__PI_DAY 2 |
| 31913 | #define DUK__PI_HOUR 3 |
| 31914 | #define DUK__PI_MINUTE 4 |
| 31915 | #define DUK__PI_SECOND 5 |
| 31916 | #define DUK__PI_MILLISECOND 6 |
| 31917 | #define DUK__PI_TZHOUR 7 |
| 31918 | #define DUK__PI_TZMINUTE 8 |
| 31919 | |
| 31920 | /* Parser part masks. */ |
| 31921 | #define DUK__PM_YEAR (1 << DUK__PI_YEAR) |
| 31922 | #define DUK__PM_MONTH (1 << DUK__PI_MONTH) |
| 31923 | #define DUK__PM_DAY (1 << DUK__PI_DAY) |
| 31924 | #define DUK__PM_HOUR (1 << DUK__PI_HOUR) |
| 31925 | #define DUK__PM_MINUTE (1 << DUK__PI_MINUTE) |
| 31926 | #define DUK__PM_SECOND (1 << DUK__PI_SECOND) |
| 31927 | #define DUK__PM_MILLISECOND (1 << DUK__PI_MILLISECOND) |
| 31928 | #define DUK__PM_TZHOUR (1 << DUK__PI_TZHOUR) |
| 31929 | #define DUK__PM_TZMINUTE (1 << DUK__PI_TZMINUTE) |
| 31930 | |
| 31931 | /* Parser separator indices. */ |
| 31932 | #define DUK__SI_PLUS 0 |
| 31933 | #define DUK__SI_MINUS 1 |
| 31934 | #define DUK__SI_T 2 |
| 31935 | #define DUK__SI_SPACE 3 |
| 31936 | #define DUK__SI_COLON 4 |
| 31937 | #define DUK__SI_PERIOD 5 |
| 31938 | #define DUK__SI_Z 6 |
| 31939 | #define DUK__SI_NUL 7 |
| 31940 | |
| 31941 | /* Parser separator masks. */ |
| 31942 | #define DUK__SM_PLUS (1 << DUK__SI_PLUS) |
| 31943 | #define DUK__SM_MINUS (1 << DUK__SI_MINUS) |
| 31944 | #define DUK__SM_T (1 << DUK__SI_T) |
| 31945 | #define DUK__SM_SPACE (1 << DUK__SI_SPACE) |
| 31946 | #define DUK__SM_COLON (1 << DUK__SI_COLON) |
| 31947 | #define DUK__SM_PERIOD (1 << DUK__SI_PERIOD) |
| 31948 | #define DUK__SM_Z (1 << DUK__SI_Z) |
| 31949 | #define DUK__SM_NUL (1 << DUK__SI_NUL) |
| 31950 | |
| 31951 | /* Rule control flags. */ |
| 31952 | #define DUK__CF_NEG (1 << 0) /* continue matching, set neg_tzoffset flag */ |
| 31953 | #define DUK__CF_ACCEPT (1 << 1) /* accept string */ |
| 31954 | #define DUK__CF_ACCEPT_NUL (1 << 2) /* accept string if next char is NUL (otherwise reject) */ |
| 31955 | |
| 31956 | #define DUK__PACK_RULE(partmask,sepmask,nextpart,flags) \ |
| 31957 | ((duk_uint32_t) (partmask) + \ |
| 31958 | (((duk_uint32_t) (sepmask)) << 9) + \ |
| 31959 | (((duk_uint32_t) (nextpart)) << 17) + \ |
| 31960 | (((duk_uint32_t) (flags)) << 21)) |
| 31961 | |
| 31962 | #define DUK__UNPACK_RULE(rule,var_nextidx,var_flags) do { \ |
| 31963 | (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \ |
| 31964 | (var_flags) = (duk_small_uint_t) ((rule) >> 21); \ |
| 31965 | } while (0) |
| 31966 | |
| 31967 | #define DUK__RULE_MASK_PART_SEP 0x1ffffUL |
| 31968 | |
| 31969 | /* Matching separator index is used in the control table */ |
| 31970 | DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = { |
| 31971 | DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/, |
| 31972 | DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/ |
| 31973 | }; |
| 31974 | |
| 31975 | /* Rule table: first matching rule is used to determine what to do next. */ |
| 31976 | DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = { |
| 31977 | DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0), |
| 31978 | DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0), |
| 31979 | DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0), |
| 31980 | DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0), |
| 31981 | DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0), |
| 31982 | DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0), |
| 31983 | DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0), |
| 31984 | 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), |
| 31985 | 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), |
| 31986 | 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), |
| 31987 | 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) |
| 31988 | |
| 31989 | /* Note1: the specification doesn't require matching a time form with |
| 31990 | * just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z". |
| 31991 | * |
| 31992 | * Note2: the specification doesn't require matching a timezone offset |
| 31993 | * with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02" |
| 31994 | */ |
| 31995 | }; |
| 31996 | |
| 31997 | DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const char *str) { |
| 31998 | duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS]; |
| 31999 | duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; |
| 32000 | duk_double_t d; |
| 32001 | const duk_uint8_t *p; |
| 32002 | duk_small_uint_t part_idx = 0; |
| 32003 | duk_int_t accum = 0; |
| 32004 | duk_small_uint_t ndigits = 0; |
| 32005 | duk_bool_t neg_year = 0; |
| 32006 | duk_bool_t neg_tzoffset = 0; |
| 32007 | duk_uint_fast8_t ch; |
| 32008 | duk_small_uint_t i; |
| 32009 | |
| 32010 | /* During parsing, month and day are one-based; set defaults here. */ |
| 32011 | duk_memzero(parts, sizeof(parts)); |
| 32012 | DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */ |
| 32013 | parts[DUK_DATE_IDX_MONTH] = 1; |
| 32014 | parts[DUK_DATE_IDX_DAY] = 1; |
| 32015 | |
| 32016 | /* Special handling for year sign. */ |
| 32017 | p = (const duk_uint8_t *) str; |
| 32018 | ch = p[0]; |
| 32019 | if (ch == DUK_ASC_PLUS) { |
| 32020 | p++; |
| 32021 | } else if (ch == DUK_ASC_MINUS) { |
| 32022 | neg_year = 1; |
| 32023 | p++; |
| 32024 | } |
| 32025 | |
| 32026 | for (;;) { |
| 32027 | ch = *p++; |
| 32028 | DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')" , |
| 32029 | (long) part_idx, (long) ch, |
| 32030 | (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION))); |
| 32031 | |
| 32032 | if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) { |
| 32033 | if (ndigits >= 9) { |
| 32034 | DUK_DDD(DUK_DDDPRINT("too many digits -> reject" )); |
| 32035 | goto reject; |
| 32036 | } |
| 32037 | if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) { |
| 32038 | /* ignore millisecond fractions after 3 */ |
| 32039 | } else { |
| 32040 | accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00; |
| 32041 | ndigits++; |
| 32042 | } |
| 32043 | } else { |
| 32044 | duk_uint_fast32_t match_val; |
| 32045 | duk_small_uint_t sep_idx; |
| 32046 | |
| 32047 | if (ndigits <= 0) { |
| 32048 | goto reject; |
| 32049 | } |
| 32050 | if (part_idx == DUK__PI_MILLISECOND) { |
| 32051 | /* complete the millisecond field */ |
| 32052 | while (ndigits < 3) { |
| 32053 | accum *= 10; |
| 32054 | ndigits++; |
| 32055 | } |
| 32056 | } |
| 32057 | parts[part_idx] = accum; |
| 32058 | DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld" , (long) part_idx, (long) accum)); |
| 32059 | |
| 32060 | accum = 0; |
| 32061 | ndigits = 0; |
| 32062 | |
| 32063 | for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) { |
| 32064 | if (duk__parse_iso8601_seps[i] == ch) { |
| 32065 | break; |
| 32066 | } |
| 32067 | } |
| 32068 | if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) { |
| 32069 | DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject" )); |
| 32070 | goto reject; |
| 32071 | } |
| 32072 | |
| 32073 | sep_idx = i; |
| 32074 | match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); /* match against rule part/sep bits */ |
| 32075 | |
| 32076 | for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) { |
| 32077 | duk_uint_fast32_t rule = duk__parse_iso8601_control[i]; |
| 32078 | duk_small_uint_t nextpart; |
| 32079 | duk_small_uint_t cflags; |
| 32080 | |
| 32081 | DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx" , |
| 32082 | (long) part_idx, (long) sep_idx, |
| 32083 | (unsigned long) match_val, (unsigned long) rule)); |
| 32084 | |
| 32085 | if ((rule & match_val) != match_val) { |
| 32086 | continue; |
| 32087 | } |
| 32088 | |
| 32089 | DUK__UNPACK_RULE(rule, nextpart, cflags); |
| 32090 | |
| 32091 | DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, " |
| 32092 | "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx" , |
| 32093 | (long) part_idx, (long) sep_idx, |
| 32094 | (unsigned long) match_val, (unsigned long) rule, |
| 32095 | (long) nextpart, (unsigned long) cflags)); |
| 32096 | |
| 32097 | if (cflags & DUK__CF_NEG) { |
| 32098 | neg_tzoffset = 1; |
| 32099 | } |
| 32100 | |
| 32101 | if (cflags & DUK__CF_ACCEPT) { |
| 32102 | goto accept; |
| 32103 | } |
| 32104 | |
| 32105 | if (cflags & DUK__CF_ACCEPT_NUL) { |
| 32106 | DUK_ASSERT(*(p - 1) != (char) 0); |
| 32107 | if (*p == DUK_ASC_NUL) { |
| 32108 | goto accept; |
| 32109 | } |
| 32110 | goto reject; |
| 32111 | } |
| 32112 | |
| 32113 | part_idx = nextpart; |
| 32114 | break; |
| 32115 | } /* rule match */ |
| 32116 | |
| 32117 | if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) { |
| 32118 | DUK_DDD(DUK_DDDPRINT("no rule matches -> reject" )); |
| 32119 | goto reject; |
| 32120 | } |
| 32121 | |
| 32122 | if (ch == 0) { |
| 32123 | /* This shouldn't be necessary, but check just in case |
| 32124 | * to avoid any chance of overruns. |
| 32125 | */ |
| 32126 | DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject" )); |
| 32127 | goto reject; |
| 32128 | } |
| 32129 | } /* if-digit-else-ctrl */ |
| 32130 | } /* char loop */ |
| 32131 | |
| 32132 | /* We should never exit the loop above. */ |
| 32133 | DUK_UNREACHABLE(); |
| 32134 | |
| 32135 | reject: |
| 32136 | DUK_DDD(DUK_DDDPRINT("reject" )); |
| 32137 | return 0; |
| 32138 | |
| 32139 | accept: |
| 32140 | DUK_DDD(DUK_DDDPRINT("accept" )); |
| 32141 | |
| 32142 | /* Apply timezone offset to get the main parts in UTC */ |
| 32143 | if (neg_year) { |
| 32144 | parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR]; |
| 32145 | } |
| 32146 | if (neg_tzoffset) { |
| 32147 | parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR]; |
| 32148 | parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE]; |
| 32149 | } else { |
| 32150 | parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR]; |
| 32151 | parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE]; |
| 32152 | } |
| 32153 | parts[DUK__PI_MONTH] -= 1; /* zero-based month */ |
| 32154 | parts[DUK__PI_DAY] -= 1; /* zero-based day */ |
| 32155 | |
| 32156 | /* Use double parts, they tolerate unnormalized time. |
| 32157 | * |
| 32158 | * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR) |
| 32159 | * on purpose. It won't be actually used by duk_bi_date_get_timeval_from_dparts(), |
| 32160 | * but will make the value initialized just in case, and avoid any |
| 32161 | * potential for Valgrind issues. |
| 32162 | */ |
| 32163 | for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) { |
| 32164 | DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld" , (long) i, (long) parts[i])); |
| 32165 | dparts[i] = parts[i]; |
| 32166 | } |
| 32167 | |
| 32168 | d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/); |
| 32169 | duk_push_number(thr, d); |
| 32170 | return 1; |
| 32171 | } |
| 32172 | |
| 32173 | /* |
| 32174 | * Date/time parsing helper. |
| 32175 | * |
| 32176 | * Parse a datetime string into a time value. We must first try to parse |
| 32177 | * the input according to the standard format in E5.1 Section 15.9.1.15. |
| 32178 | * If that fails, we can try to parse using custom parsing, which can |
| 32179 | * either be platform neutral (custom code) or platform specific (using |
| 32180 | * existing platform API calls). |
| 32181 | * |
| 32182 | * Note in particular that we must parse whatever toString(), toUTCString(), |
| 32183 | * and toISOString() can produce; see E5.1 Section 15.9.4.2. |
| 32184 | * |
| 32185 | * Returns 1 to allow tail calling. |
| 32186 | * |
| 32187 | * There is much room for improvement here with respect to supporting |
| 32188 | * alternative datetime formats. For instance, V8 parses '2012-01-01' as |
| 32189 | * UTC and '2012/01/01' as local time. |
| 32190 | */ |
| 32191 | |
| 32192 | DUK_LOCAL duk_ret_t duk__parse_string(duk_hthread *thr, const char *str) { |
| 32193 | /* XXX: there is a small risk here: because the ISO 8601 parser is |
| 32194 | * very loose, it may end up parsing some datetime values which |
| 32195 | * would be better parsed with a platform specific parser. |
| 32196 | */ |
| 32197 | |
| 32198 | DUK_ASSERT(str != NULL); |
| 32199 | DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'" , (const char *) str)); |
| 32200 | |
| 32201 | if (duk__parse_string_iso8601_subset(thr, str) != 0) { |
| 32202 | return 1; |
| 32203 | } |
| 32204 | |
| 32205 | #if defined(DUK_USE_DATE_PARSE_STRING) |
| 32206 | /* Contract, either: |
| 32207 | * - Push value on stack and return 1 |
| 32208 | * - Don't push anything on stack and return 0 |
| 32209 | */ |
| 32210 | |
| 32211 | if (DUK_USE_DATE_PARSE_STRING(thr, str) != 0) { |
| 32212 | return 1; |
| 32213 | } |
| 32214 | #else |
| 32215 | /* No platform-specific parsing, this is not an error. */ |
| 32216 | #endif |
| 32217 | |
| 32218 | duk_push_nan(thr); |
| 32219 | return 1; |
| 32220 | } |
| 32221 | |
| 32222 | /* |
| 32223 | * Calendar helpers |
| 32224 | * |
| 32225 | * Some helpers are used for getters and can operate on normalized values |
| 32226 | * which can be represented with 32-bit signed integers. Other helpers are |
| 32227 | * needed by setters and operate on un-normalized double values, must watch |
| 32228 | * out for non-finite numbers etc. |
| 32229 | */ |
| 32230 | |
| 32231 | DUK_LOCAL duk_uint8_t duk__days_in_month[12] = { |
| 32232 | (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30, |
| 32233 | (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31, |
| 32234 | (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31 |
| 32235 | }; |
| 32236 | |
| 32237 | /* Maximum iteration count for computing UTC-to-local time offset when |
| 32238 | * creating an ECMAScript time value from local parts. |
| 32239 | */ |
| 32240 | #define DUK__LOCAL_TZOFFSET_MAXITER 4 |
| 32241 | |
| 32242 | /* Because 'day since epoch' can be negative and is used to compute weekday |
| 32243 | * using a modulo operation, add this multiple of 7 to avoid negative values |
| 32244 | * when year is below 1970 epoch. ECMAScript time values are restricted to |
| 32245 | * +/- 100 million days from epoch, so this adder fits nicely into 32 bits. |
| 32246 | * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin. |
| 32247 | */ |
| 32248 | #define DUK__WEEKDAY_MOD_ADDER (20000000 * 7) /* 0x08583b00 */ |
| 32249 | |
| 32250 | DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) { |
| 32251 | if ((year % 4) != 0) { |
| 32252 | return 0; |
| 32253 | } |
| 32254 | if ((year % 100) != 0) { |
| 32255 | return 1; |
| 32256 | } |
| 32257 | if ((year % 400) != 0) { |
| 32258 | return 0; |
| 32259 | } |
| 32260 | return 1; |
| 32261 | } |
| 32262 | |
| 32263 | DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) { |
| 32264 | return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS); |
| 32265 | } |
| 32266 | |
| 32267 | DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) { |
| 32268 | return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY); |
| 32269 | } |
| 32270 | |
| 32271 | DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) { |
| 32272 | return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR); |
| 32273 | } |
| 32274 | |
| 32275 | DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) { |
| 32276 | if (!DUK_ISFINITE(x)) { |
| 32277 | return DUK_DOUBLE_NAN; |
| 32278 | } |
| 32279 | |
| 32280 | if (!duk_bi_date_timeval_in_valid_range(x)) { |
| 32281 | return DUK_DOUBLE_NAN; |
| 32282 | } |
| 32283 | |
| 32284 | x = duk_js_tointeger_number(x); |
| 32285 | |
| 32286 | /* Here we'd have the option to normalize -0 to +0. */ |
| 32287 | return x; |
| 32288 | } |
| 32289 | |
| 32290 | /* Integer division which floors also negative values correctly. */ |
| 32291 | DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) { |
| 32292 | DUK_ASSERT(b > 0); |
| 32293 | if (a >= 0) { |
| 32294 | return a / b; |
| 32295 | } else { |
| 32296 | /* e.g. a = -4, b = 5 --> -4 - 5 + 1 / 5 --> -8 / 5 --> -1 |
| 32297 | * a = -5, b = 5 --> -5 - 5 + 1 / 5 --> -9 / 5 --> -1 |
| 32298 | * a = -6, b = 5 --> -6 - 5 + 1 / 5 --> -10 / 5 --> -2 |
| 32299 | */ |
| 32300 | return (a - b + 1) / b; |
| 32301 | } |
| 32302 | } |
| 32303 | |
| 32304 | /* Compute day number of the first day of a given year. */ |
| 32305 | DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) { |
| 32306 | /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative |
| 32307 | * values, but is incorrect for negative ones. |
| 32308 | */ |
| 32309 | return 365 * (year - 1970) |
| 32310 | + duk__div_floor(year - 1969, 4) |
| 32311 | - duk__div_floor(year - 1901, 100) |
| 32312 | + duk__div_floor(year - 1601, 400); |
| 32313 | } |
| 32314 | |
| 32315 | /* Given a day number, determine year and day-within-year. */ |
| 32316 | DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) { |
| 32317 | duk_int_t year; |
| 32318 | duk_int_t diff_days; |
| 32319 | |
| 32320 | /* estimate year upwards (towards positive infinity), then back down; |
| 32321 | * two iterations should be enough |
| 32322 | */ |
| 32323 | |
| 32324 | if (day >= 0) { |
| 32325 | year = 1970 + day / 365; |
| 32326 | } else { |
| 32327 | year = 1970 + day / 366; |
| 32328 | } |
| 32329 | |
| 32330 | for (;;) { |
| 32331 | diff_days = duk__day_from_year(year) - day; |
| 32332 | DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld" , (long) year, (long) day, (long) diff_days)); |
| 32333 | if (diff_days <= 0) { |
| 32334 | DUK_ASSERT(-diff_days < 366); /* fits into duk_small_int_t */ |
| 32335 | *out_day_within_year = -diff_days; |
| 32336 | DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld" , |
| 32337 | (long) year, (long) *out_day_within_year)); |
| 32338 | DUK_ASSERT(*out_day_within_year >= 0); |
| 32339 | DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365)); |
| 32340 | return year; |
| 32341 | } |
| 32342 | |
| 32343 | /* Note: this is very tricky; we must never 'overshoot' the |
| 32344 | * correction downwards. |
| 32345 | */ |
| 32346 | year -= 1 + (diff_days - 1) / 366; /* conservative */ |
| 32347 | } |
| 32348 | } |
| 32349 | |
| 32350 | /* Given a (year, month, day-within-month) triple, compute day number. |
| 32351 | * The input triple is un-normalized and may contain non-finite values. |
| 32352 | */ |
| 32353 | DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) { |
| 32354 | duk_int_t day_num; |
| 32355 | duk_bool_t is_leap; |
| 32356 | duk_small_int_t i, n; |
| 32357 | |
| 32358 | /* Assume that year, month, day are all coerced to whole numbers. |
| 32359 | * They may also be NaN or infinity, in which case this function |
| 32360 | * must return NaN or infinity to ensure time value becomes NaN. |
| 32361 | * If 'day' is NaN, the final return will end up returning a NaN, |
| 32362 | * so it doesn't need to be checked here. |
| 32363 | */ |
| 32364 | |
| 32365 | if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) { |
| 32366 | return DUK_DOUBLE_NAN; |
| 32367 | } |
| 32368 | |
| 32369 | year += DUK_FLOOR(month / 12.0); |
| 32370 | |
| 32371 | month = DUK_FMOD(month, 12.0); |
| 32372 | if (month < 0.0) { |
| 32373 | /* handle negative values */ |
| 32374 | month += 12.0; |
| 32375 | } |
| 32376 | |
| 32377 | /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but |
| 32378 | * does not normalize the day-of-month (nor check whether or not |
| 32379 | * it is finite) because it's not necessary for finding the day |
| 32380 | * number which matches the (year,month) pair. |
| 32381 | * |
| 32382 | * We assume that duk__day_from_year() is exact here. |
| 32383 | * |
| 32384 | * Without an explicit infinity / NaN check in the beginning, |
| 32385 | * day_num would be a bogus integer here. |
| 32386 | * |
| 32387 | * It's possible for 'year' to be out of integer range here. |
| 32388 | * If so, we need to return NaN without integer overflow. |
| 32389 | * This fixes test-bug-setyear-overflow.js. |
| 32390 | */ |
| 32391 | |
| 32392 | if (!duk_bi_date_year_in_valid_range(year)) { |
| 32393 | DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf" , (double) year)); |
| 32394 | return DUK_DOUBLE_NAN; |
| 32395 | } |
| 32396 | day_num = duk__day_from_year((duk_int_t) year); |
| 32397 | is_leap = duk_bi_date_is_leap_year((duk_int_t) year); |
| 32398 | |
| 32399 | n = (duk_small_int_t) month; |
| 32400 | for (i = 0; i < n; i++) { |
| 32401 | day_num += duk__days_in_month[i]; |
| 32402 | if (i == 1 && is_leap) { |
| 32403 | day_num++; |
| 32404 | } |
| 32405 | } |
| 32406 | |
| 32407 | /* If 'day' is NaN, returns NaN. */ |
| 32408 | return (duk_double_t) day_num + day; |
| 32409 | } |
| 32410 | |
| 32411 | /* Split time value into parts. The time value may contain fractions (it may |
| 32412 | * come from duk_time_to_components() API call) which are truncated. Possible |
| 32413 | * local time adjustment has already been applied when reading the time value. |
| 32414 | */ |
| 32415 | DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags) { |
| 32416 | duk_double_t d1, d2; |
| 32417 | duk_int_t t1, t2; |
| 32418 | duk_int_t day_since_epoch; |
| 32419 | duk_int_t year; /* does not fit into 16 bits */ |
| 32420 | duk_small_int_t day_in_year; |
| 32421 | duk_small_int_t month; |
| 32422 | duk_small_int_t day; |
| 32423 | duk_small_int_t dim; |
| 32424 | duk_int_t jan1_since_epoch; |
| 32425 | duk_small_int_t jan1_weekday; |
| 32426 | duk_int_t equiv_year; |
| 32427 | duk_small_uint_t i; |
| 32428 | duk_bool_t is_leap; |
| 32429 | duk_small_int_t arridx; |
| 32430 | |
| 32431 | DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */ |
| 32432 | d = DUK_FLOOR(d); /* remove fractions if present */ |
| 32433 | DUK_ASSERT(duk_double_equals(DUK_FLOOR(d), d)); |
| 32434 | |
| 32435 | /* The timevalue must be in valid ECMAScript range, but since a local |
| 32436 | * time offset can be applied, we need to allow a +/- 24h leeway to |
| 32437 | * the value. In other words, although the UTC time is within the |
| 32438 | * ECMAScript range, the local part values can be just outside of it. |
| 32439 | */ |
| 32440 | DUK_UNREF(duk_bi_date_timeval_in_leeway_range); |
| 32441 | DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d)); |
| 32442 | |
| 32443 | /* These computations are guaranteed to be exact for the valid |
| 32444 | * E5 time value range, assuming milliseconds without fractions. |
| 32445 | */ |
| 32446 | d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY); |
| 32447 | if (d1 < 0.0) { |
| 32448 | /* deal with negative values */ |
| 32449 | d1 += (duk_double_t) DUK_DATE_MSEC_DAY; |
| 32450 | } |
| 32451 | d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY)); |
| 32452 | DUK_ASSERT(duk_double_equals(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1, d)); |
| 32453 | /* now expected to fit into a 32-bit integer */ |
| 32454 | t1 = (duk_int_t) d1; |
| 32455 | t2 = (duk_int_t) d2; |
| 32456 | day_since_epoch = t2; |
| 32457 | DUK_ASSERT(duk_double_equals((duk_double_t) t1, d1)); |
| 32458 | DUK_ASSERT(duk_double_equals((duk_double_t) t2, d2)); |
| 32459 | |
| 32460 | /* t1 = milliseconds within day (fits 32 bit) |
| 32461 | * t2 = day number from epoch (fits 32 bit, may be negative) |
| 32462 | */ |
| 32463 | |
| 32464 | parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000; |
| 32465 | parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60; |
| 32466 | parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60; |
| 32467 | parts[DUK_DATE_IDX_HOUR] = t1; |
| 32468 | DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999); |
| 32469 | DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59); |
| 32470 | DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59); |
| 32471 | DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23); |
| 32472 | |
| 32473 | DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld" , |
| 32474 | (double) d, (double) d1, (double) d2, (long) t1, (long) t2, |
| 32475 | (long) parts[DUK_DATE_IDX_HOUR], |
| 32476 | (long) parts[DUK_DATE_IDX_MINUTE], |
| 32477 | (long) parts[DUK_DATE_IDX_SECOND], |
| 32478 | (long) parts[DUK_DATE_IDX_MILLISECOND])); |
| 32479 | |
| 32480 | /* This assert depends on the input parts representing time inside |
| 32481 | * the ECMAScript range. |
| 32482 | */ |
| 32483 | DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0); |
| 32484 | parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */ |
| 32485 | DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6); |
| 32486 | |
| 32487 | year = duk__year_from_day(t2, &day_in_year); |
| 32488 | day = day_in_year; |
| 32489 | is_leap = duk_bi_date_is_leap_year(year); |
| 32490 | for (month = 0; month < 12; month++) { |
| 32491 | dim = duk__days_in_month[month]; |
| 32492 | if (month == 1 && is_leap) { |
| 32493 | dim++; |
| 32494 | } |
| 32495 | DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld" , |
| 32496 | (long) month, (long) dim, (long) day)); |
| 32497 | if (day < dim) { |
| 32498 | break; |
| 32499 | } |
| 32500 | day -= dim; |
| 32501 | } |
| 32502 | DUK_DDD(DUK_DDDPRINT("final month=%ld" , (long) month)); |
| 32503 | DUK_ASSERT(month >= 0 && month <= 11); |
| 32504 | DUK_ASSERT(day >= 0 && day <= 31); |
| 32505 | |
| 32506 | /* Equivalent year mapping, used to avoid DST trouble when platform |
| 32507 | * may fail to provide reasonable DST answers for dates outside the |
| 32508 | * ordinary range (e.g. 1970-2038). An equivalent year has the same |
| 32509 | * leap-year-ness as the original year and begins on the same weekday |
| 32510 | * (Jan 1). |
| 32511 | * |
| 32512 | * The year 2038 is avoided because there seem to be problems with it |
| 32513 | * on some platforms. The year 1970 is also avoided as there were |
| 32514 | * practical problems with it; an equivalent year is used for it too, |
| 32515 | * which breaks some DST computations for 1970 right now, see e.g. |
| 32516 | * test-bi-date-tzoffset-brute-fi.js. |
| 32517 | */ |
| 32518 | if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) { |
| 32519 | DUK_ASSERT(is_leap == 0 || is_leap == 1); |
| 32520 | |
| 32521 | jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */ |
| 32522 | DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0); |
| 32523 | jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */ |
| 32524 | DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6); |
| 32525 | arridx = jan1_weekday; |
| 32526 | if (is_leap) { |
| 32527 | arridx += 7; |
| 32528 | } |
| 32529 | DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t))); |
| 32530 | |
| 32531 | equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970; |
| 32532 | year = equiv_year; |
| 32533 | DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, " |
| 32534 | "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld" , |
| 32535 | (long) year, (long) day_in_year, (long) day_since_epoch, |
| 32536 | (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year)); |
| 32537 | } |
| 32538 | |
| 32539 | parts[DUK_DATE_IDX_YEAR] = year; |
| 32540 | parts[DUK_DATE_IDX_MONTH] = month; |
| 32541 | parts[DUK_DATE_IDX_DAY] = day; |
| 32542 | |
| 32543 | if (flags & DUK_DATE_FLAG_ONEBASED) { |
| 32544 | parts[DUK_DATE_IDX_MONTH]++; /* zero-based -> one-based */ |
| 32545 | parts[DUK_DATE_IDX_DAY]++; /* -""- */ |
| 32546 | } |
| 32547 | |
| 32548 | if (dparts != NULL) { |
| 32549 | for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) { |
| 32550 | dparts[i] = (duk_double_t) parts[i]; |
| 32551 | } |
| 32552 | } |
| 32553 | } |
| 32554 | |
| 32555 | /* Compute time value from (double) parts. The parts can be either UTC |
| 32556 | * or local time; if local, they need to be (conceptually) converted into |
| 32557 | * UTC time. The parts may represent valid or invalid time, and may be |
| 32558 | * wildly out of range (but may cancel each other and still come out in |
| 32559 | * the valid Date range). |
| 32560 | */ |
| 32561 | DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) { |
| 32562 | #if defined(DUK_USE_PARANOID_DATE_COMPUTATION) |
| 32563 | /* See comments below on MakeTime why these are volatile. */ |
| 32564 | volatile duk_double_t tmp_time; |
| 32565 | volatile duk_double_t tmp_day; |
| 32566 | volatile duk_double_t d; |
| 32567 | #else |
| 32568 | duk_double_t tmp_time; |
| 32569 | duk_double_t tmp_day; |
| 32570 | duk_double_t d; |
| 32571 | #endif |
| 32572 | duk_small_uint_t i; |
| 32573 | duk_int_t tzoff, tzoffprev1, tzoffprev2; |
| 32574 | |
| 32575 | /* Expects 'this' at top of stack on entry. */ |
| 32576 | |
| 32577 | /* Coerce all finite parts with ToInteger(). ToInteger() must not |
| 32578 | * be called for NaN/Infinity because it will convert e.g. NaN to |
| 32579 | * zero. If ToInteger() has already been called, this has no side |
| 32580 | * effects and is idempotent. |
| 32581 | * |
| 32582 | * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind |
| 32583 | * issues if the value is uninitialized. |
| 32584 | */ |
| 32585 | for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) { |
| 32586 | /* SCANBUILD: scan-build complains here about assigned value |
| 32587 | * being garbage or undefined. This is correct but operating |
| 32588 | * on undefined values has no ill effect and is ignored by the |
| 32589 | * caller in the case where this happens. |
| 32590 | */ |
| 32591 | d = dparts[i]; |
| 32592 | if (DUK_ISFINITE(d)) { |
| 32593 | dparts[i] = duk_js_tointeger_number(d); |
| 32594 | } |
| 32595 | } |
| 32596 | |
| 32597 | /* Use explicit steps in computation to try to ensure that |
| 32598 | * computation happens with intermediate results coerced to |
| 32599 | * double values (instead of using something more accurate). |
| 32600 | * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754 |
| 32601 | * rules (= ECMAScript '+' and '*' operators). |
| 32602 | * |
| 32603 | * Without 'volatile' even this approach fails on some platform |
| 32604 | * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu |
| 32605 | * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js |
| 32606 | * would fail because of some optimizations when computing tmp_time |
| 32607 | * (MakeTime below). Adding 'volatile' to tmp_time solved this |
| 32608 | * particular problem (annoyingly, also adding debug prints or |
| 32609 | * running the executable under valgrind hides it). |
| 32610 | */ |
| 32611 | |
| 32612 | /* MakeTime */ |
| 32613 | tmp_time = 0.0; |
| 32614 | tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR); |
| 32615 | tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE); |
| 32616 | tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND); |
| 32617 | tmp_time += dparts[DUK_DATE_IDX_MILLISECOND]; |
| 32618 | |
| 32619 | /* MakeDay */ |
| 32620 | tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]); |
| 32621 | |
| 32622 | /* MakeDate */ |
| 32623 | d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time; |
| 32624 | |
| 32625 | DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf" , |
| 32626 | (double) tmp_time, (double) tmp_day, (double) d)); |
| 32627 | |
| 32628 | /* Optional UTC conversion. */ |
| 32629 | if (flags & DUK_DATE_FLAG_LOCALTIME) { |
| 32630 | /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a |
| 32631 | * time value computed from UTC parts. At this point we only |
| 32632 | * have 'd' which is a time value computed from local parts, so |
| 32633 | * it is off by the UTC-to-local time offset which we don't know |
| 32634 | * yet. The current solution for computing the UTC-to-local |
| 32635 | * time offset is to iterate a few times and detect a fixed |
| 32636 | * point or a two-cycle loop (or a sanity iteration limit), |
| 32637 | * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js. |
| 32638 | * |
| 32639 | * E5.1 Section 15.9.1.9: |
| 32640 | * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA) |
| 32641 | * |
| 32642 | * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0. |
| 32643 | */ |
| 32644 | |
| 32645 | #if 0 |
| 32646 | /* Old solution: don't iterate, incorrect */ |
| 32647 | tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); |
| 32648 | DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld" , (long) tzoff)); |
| 32649 | d -= tzoff * 1000L; |
| 32650 | DUK_UNREF(tzoffprev1); |
| 32651 | DUK_UNREF(tzoffprev2); |
| 32652 | #endif |
| 32653 | |
| 32654 | /* Iteration solution */ |
| 32655 | tzoff = 0; |
| 32656 | tzoffprev1 = 999999999L; /* invalid value which never matches */ |
| 32657 | for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) { |
| 32658 | tzoffprev2 = tzoffprev1; |
| 32659 | tzoffprev1 = tzoff; |
| 32660 | tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L); |
| 32661 | DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld" , |
| 32662 | (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2)); |
| 32663 | if (tzoff == tzoffprev1) { |
| 32664 | DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld" , |
| 32665 | (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2)); |
| 32666 | break; |
| 32667 | } else if (tzoff == tzoffprev2) { |
| 32668 | /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js. |
| 32669 | * In these cases, favor a higher tzoffset to get a consistent |
| 32670 | * result which is independent of iteration count. Not sure if |
| 32671 | * this is a generically correct solution. |
| 32672 | */ |
| 32673 | DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld" , |
| 32674 | (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2)); |
| 32675 | if (tzoffprev1 > tzoff) { |
| 32676 | tzoff = tzoffprev1; |
| 32677 | } |
| 32678 | break; |
| 32679 | } |
| 32680 | } |
| 32681 | DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld" , (long) tzoff)); |
| 32682 | d -= tzoff * 1000L; |
| 32683 | } |
| 32684 | |
| 32685 | /* TimeClip(), which also handles Infinity -> NaN conversion */ |
| 32686 | d = duk__timeclip(d); |
| 32687 | |
| 32688 | return d; |
| 32689 | } |
| 32690 | |
| 32691 | /* |
| 32692 | * API oriented helpers |
| 32693 | */ |
| 32694 | |
| 32695 | /* Push 'this' binding, check that it is a Date object; then push the |
| 32696 | * internal time value. At the end, stack is: [ ... this timeval ]. |
| 32697 | * Returns the time value. Local time adjustment is done if requested. |
| 32698 | */ |
| 32699 | DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset) { |
| 32700 | duk_hobject *h; |
| 32701 | duk_double_t d; |
| 32702 | duk_int_t tzoffset = 0; |
| 32703 | |
| 32704 | duk_push_this(thr); |
| 32705 | h = duk_get_hobject(thr, -1); /* XXX: getter with class check, useful in built-ins */ |
| 32706 | if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) { |
| 32707 | DUK_ERROR_TYPE(thr, "expected Date" ); |
| 32708 | DUK_WO_NORETURN(return 0.0;); |
| 32709 | } |
| 32710 | |
| 32711 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); |
| 32712 | d = duk_to_number_m1(thr); |
| 32713 | duk_pop(thr); |
| 32714 | |
| 32715 | if (DUK_ISNAN(d)) { |
| 32716 | if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) { |
| 32717 | d = 0.0; |
| 32718 | } |
| 32719 | if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) { |
| 32720 | DUK_ERROR_RANGE(thr, "Invalid Date" ); |
| 32721 | DUK_WO_NORETURN(return 0.0;); |
| 32722 | } |
| 32723 | } |
| 32724 | /* if no NaN handling flag, may still be NaN here, but not Inf */ |
| 32725 | DUK_ASSERT(!DUK_ISINF(d)); |
| 32726 | |
| 32727 | if (flags & DUK_DATE_FLAG_LOCALTIME) { |
| 32728 | /* Note: DST adjustment is determined using UTC time. |
| 32729 | * If 'd' is NaN, tzoffset will be 0. |
| 32730 | */ |
| 32731 | tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); /* seconds */ |
| 32732 | d += tzoffset * 1000L; |
| 32733 | } |
| 32734 | if (out_tzoffset) { |
| 32735 | *out_tzoffset = tzoffset; |
| 32736 | } |
| 32737 | |
| 32738 | /* [ ... this ] */ |
| 32739 | return d; |
| 32740 | } |
| 32741 | |
| 32742 | DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags) { |
| 32743 | return duk__push_this_get_timeval_tzoffset(thr, flags, NULL); |
| 32744 | } |
| 32745 | |
| 32746 | /* Set timeval to 'this' from dparts, push the new time value onto the |
| 32747 | * value stack and return 1 (caller can then tail call us). Expects |
| 32748 | * the value stack to contain 'this' on the stack top. |
| 32749 | */ |
| 32750 | DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags) { |
| 32751 | duk_double_t d; |
| 32752 | |
| 32753 | /* [ ... this ] */ |
| 32754 | |
| 32755 | d = duk_bi_date_get_timeval_from_dparts(dparts, flags); |
| 32756 | duk_push_number(thr, d); /* -> [ ... this timeval_new ] */ |
| 32757 | duk_dup_top(thr); /* -> [ ... this timeval_new timeval_new ] */ |
| 32758 | |
| 32759 | /* Must force write because e.g. .setYear() must work even when |
| 32760 | * the Date instance is frozen. |
| 32761 | */ |
| 32762 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); |
| 32763 | |
| 32764 | /* Stack top: new time value, return 1 to allow tail calls. */ |
| 32765 | return 1; |
| 32766 | } |
| 32767 | |
| 32768 | /* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */ |
| 32769 | DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) { |
| 32770 | char yearstr[8]; /* "-123456\0" */ |
| 32771 | char tzstr[8]; /* "+11:22\0" */ |
| 32772 | char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE; |
| 32773 | |
| 32774 | DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12); |
| 32775 | DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31); |
| 32776 | DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999); |
| 32777 | |
| 32778 | /* Note: %06d for positive value, %07d for negative value to include |
| 32779 | * sign and 6 digits. |
| 32780 | */ |
| 32781 | DUK_SNPRINTF(yearstr, |
| 32782 | sizeof(yearstr), |
| 32783 | (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" : |
| 32784 | ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld" ), |
| 32785 | (long) parts[DUK_DATE_IDX_YEAR]); |
| 32786 | yearstr[sizeof(yearstr) - 1] = (char) 0; |
| 32787 | |
| 32788 | if (flags & DUK_DATE_FLAG_LOCALTIME) { |
| 32789 | /* tzoffset seconds are dropped; 16 bits suffice for |
| 32790 | * time offset in minutes |
| 32791 | */ |
| 32792 | const char *fmt; |
| 32793 | duk_small_int_t tmp, arg_hours, arg_minutes; |
| 32794 | |
| 32795 | if (tzoffset >= 0) { |
| 32796 | tmp = tzoffset; |
| 32797 | fmt = "+%02d:%02d" ; |
| 32798 | } else { |
| 32799 | tmp = -tzoffset; |
| 32800 | fmt = "-%02d:%02d" ; |
| 32801 | } |
| 32802 | tmp = tmp / 60; |
| 32803 | arg_hours = tmp / 60; |
| 32804 | arg_minutes = tmp % 60; |
| 32805 | DUK_ASSERT(arg_hours <= 24); /* Even less is actually guaranteed for a valid tzoffset. */ |
| 32806 | arg_hours = arg_hours & 0x3f; /* For [0,24] this is a no-op, but fixes GCC 7 warning, see https://github.com/svaarala/duktape/issues/1602. */ |
| 32807 | |
| 32808 | DUK_SNPRINTF(tzstr, sizeof(tzstr), fmt, (int) arg_hours, (int) arg_minutes); |
| 32809 | tzstr[sizeof(tzstr) - 1] = (char) 0; |
| 32810 | } else { |
| 32811 | tzstr[0] = DUK_ASC_UC_Z; |
| 32812 | tzstr[1] = (char) 0; |
| 32813 | } |
| 32814 | |
| 32815 | /* Unlike year, the other parts fit into 16 bits so %d format |
| 32816 | * is portable. |
| 32817 | */ |
| 32818 | if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) { |
| 32819 | DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s" , |
| 32820 | (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep, |
| 32821 | (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE], |
| 32822 | (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr); |
| 32823 | } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) { |
| 32824 | DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d" , |
| 32825 | (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]); |
| 32826 | } else { |
| 32827 | DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME); |
| 32828 | DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s" , |
| 32829 | (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE], |
| 32830 | (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], |
| 32831 | (const char *) tzstr); |
| 32832 | } |
| 32833 | } |
| 32834 | |
| 32835 | /* Helper for string conversion calls: check 'this' binding, get the |
| 32836 | * internal time value, and format date and/or time in a few formats. |
| 32837 | * Return value allows tail calls. |
| 32838 | */ |
| 32839 | DUK_LOCAL duk_ret_t duk__to_string_helper(duk_hthread *thr, duk_small_uint_t flags) { |
| 32840 | duk_double_t d; |
| 32841 | duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; |
| 32842 | duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */ |
| 32843 | duk_bool_t rc; |
| 32844 | duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE]; |
| 32845 | |
| 32846 | DUK_UNREF(rc); /* unreferenced with some options */ |
| 32847 | |
| 32848 | d = duk__push_this_get_timeval_tzoffset(thr, flags, &tzoffset); |
| 32849 | if (DUK_ISNAN(d)) { |
| 32850 | duk_push_hstring_stridx(thr, DUK_STRIDX_INVALID_DATE); |
| 32851 | return 1; |
| 32852 | } |
| 32853 | DUK_ASSERT(DUK_ISFINITE(d)); |
| 32854 | |
| 32855 | /* formatters always get one-based month/day-of-month */ |
| 32856 | duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED); |
| 32857 | DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12); |
| 32858 | DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31); |
| 32859 | |
| 32860 | if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) { |
| 32861 | /* try locale specific formatter; if it refuses to format the |
| 32862 | * string, fall back to an ISO 8601 formatted value in local |
| 32863 | * time. |
| 32864 | */ |
| 32865 | #if defined(DUK_USE_DATE_FORMAT_STRING) |
| 32866 | /* Contract, either: |
| 32867 | * - Push string to value stack and return 1 |
| 32868 | * - Don't push anything and return 0 |
| 32869 | */ |
| 32870 | |
| 32871 | rc = DUK_USE_DATE_FORMAT_STRING(thr, parts, tzoffset, flags); |
| 32872 | if (rc != 0) { |
| 32873 | return 1; |
| 32874 | } |
| 32875 | #else |
| 32876 | /* No locale specific formatter; this is OK, we fall back |
| 32877 | * to ISO 8601. |
| 32878 | */ |
| 32879 | #endif |
| 32880 | } |
| 32881 | |
| 32882 | /* Different calling convention than above used because the helper |
| 32883 | * is shared. |
| 32884 | */ |
| 32885 | duk__format_parts_iso8601(parts, tzoffset, flags, buf); |
| 32886 | duk_push_string(thr, (const char *) buf); |
| 32887 | return 1; |
| 32888 | } |
| 32889 | |
| 32890 | /* Helper for component getter calls: check 'this' binding, get the |
| 32891 | * internal time value, split it into parts (either as UTC time or |
| 32892 | * local time), push a specified component as a return value to the |
| 32893 | * value stack and return 1 (caller can then tail call us). |
| 32894 | */ |
| 32895 | DUK_LOCAL duk_ret_t duk__get_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_idx) { |
| 32896 | duk_double_t d; |
| 32897 | duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; |
| 32898 | duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */ |
| 32899 | |
| 32900 | DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */ |
| 32901 | DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS); |
| 32902 | |
| 32903 | d = duk__push_this_get_timeval(thr, flags_and_idx); |
| 32904 | if (DUK_ISNAN(d)) { |
| 32905 | duk_push_nan(thr); |
| 32906 | return 1; |
| 32907 | } |
| 32908 | DUK_ASSERT(DUK_ISFINITE(d)); |
| 32909 | |
| 32910 | duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx); /* no need to mask idx portion */ |
| 32911 | |
| 32912 | /* Setter APIs detect special year numbers (0...99) and apply a +1900 |
| 32913 | * only in certain cases. The legacy getYear() getter applies -1900 |
| 32914 | * unconditionally. |
| 32915 | */ |
| 32916 | duk_push_int(thr, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]); |
| 32917 | return 1; |
| 32918 | } |
| 32919 | |
| 32920 | /* Helper for component setter calls: check 'this' binding, get the |
| 32921 | * internal time value, split it into parts (either as UTC time or |
| 32922 | * local time), modify one or more components as specified, recompute |
| 32923 | * the time value, set it as the internal value. Finally, push the |
| 32924 | * new time value as a return value to the value stack and return 1 |
| 32925 | * (caller can then tail call us). |
| 32926 | */ |
| 32927 | DUK_LOCAL duk_ret_t duk__set_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_maxnargs) { |
| 32928 | duk_double_t d; |
| 32929 | duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; |
| 32930 | duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; |
| 32931 | duk_idx_t nargs; |
| 32932 | duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */ |
| 32933 | duk_small_uint_t idx_first, idx; |
| 32934 | duk_small_uint_t i; |
| 32935 | |
| 32936 | nargs = duk_get_top(thr); |
| 32937 | d = duk__push_this_get_timeval(thr, flags_and_maxnargs); |
| 32938 | DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d)); |
| 32939 | |
| 32940 | if (DUK_ISFINITE(d)) { |
| 32941 | duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs); |
| 32942 | } else { |
| 32943 | /* NaN timevalue: we need to coerce the arguments, but |
| 32944 | * the resulting internal timestamp needs to remain NaN. |
| 32945 | * This works but is not pretty: parts and dparts will |
| 32946 | * be partially uninitialized, but we only write to them. |
| 32947 | */ |
| 32948 | } |
| 32949 | |
| 32950 | /* |
| 32951 | * Determining which datetime components to overwrite based on |
| 32952 | * stack arguments is a bit complicated, but important to factor |
| 32953 | * out from setters themselves for compactness. |
| 32954 | * |
| 32955 | * If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type: |
| 32956 | * |
| 32957 | * 1 -> millisecond |
| 32958 | * 2 -> second, [millisecond] |
| 32959 | * 3 -> minute, [second], [millisecond] |
| 32960 | * 4 -> hour, [minute], [second], [millisecond] |
| 32961 | * |
| 32962 | * Else: |
| 32963 | * |
| 32964 | * 1 -> date |
| 32965 | * 2 -> month, [date] |
| 32966 | * 3 -> year, [month], [date] |
| 32967 | * |
| 32968 | * By comparing nargs and maxnargs (and flags) we know which |
| 32969 | * components to override. We rely on part index ordering. |
| 32970 | */ |
| 32971 | |
| 32972 | if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) { |
| 32973 | DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4); |
| 32974 | idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1); |
| 32975 | } else { |
| 32976 | DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3); |
| 32977 | idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1); |
| 32978 | } |
| 32979 | DUK_ASSERT_DISABLE(idx_first >= 0); /* unsigned */ |
| 32980 | DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS); |
| 32981 | |
| 32982 | for (i = 0; i < maxnargs; i++) { |
| 32983 | if ((duk_idx_t) i >= nargs) { |
| 32984 | /* no argument given -> leave components untouched */ |
| 32985 | break; |
| 32986 | } |
| 32987 | idx = idx_first + i; |
| 32988 | DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */ |
| 32989 | DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS); |
| 32990 | |
| 32991 | if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) { |
| 32992 | duk__twodigit_year_fixup(thr, (duk_idx_t) i); |
| 32993 | } |
| 32994 | |
| 32995 | dparts[idx] = duk_to_number(thr, (duk_idx_t) i); |
| 32996 | |
| 32997 | if (idx == DUK_DATE_IDX_DAY) { |
| 32998 | /* Day-of-month is one-based in the API, but zero-based |
| 32999 | * internally, so fix here. Note that month is zero-based |
| 33000 | * both in the API and internally. |
| 33001 | */ |
| 33002 | /* SCANBUILD: complains about use of uninitialized values. |
| 33003 | * The complaint is correct, but operating in undefined |
| 33004 | * values here is intentional in some cases and the caller |
| 33005 | * ignores the results. |
| 33006 | */ |
| 33007 | dparts[idx] -= 1.0; |
| 33008 | } |
| 33009 | } |
| 33010 | |
| 33011 | /* Leaves new timevalue on stack top and returns 1, which is correct |
| 33012 | * for part setters. |
| 33013 | */ |
| 33014 | if (DUK_ISFINITE(d)) { |
| 33015 | return duk__set_this_timeval_from_dparts(thr, dparts, flags_and_maxnargs); |
| 33016 | } else { |
| 33017 | /* Internal timevalue is already NaN, so don't touch it. */ |
| 33018 | duk_push_nan(thr); |
| 33019 | return 1; |
| 33020 | } |
| 33021 | } |
| 33022 | |
| 33023 | /* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add |
| 33024 | * 1900 and replace value at idx_val. |
| 33025 | */ |
| 33026 | DUK_LOCAL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val) { |
| 33027 | duk_double_t d; |
| 33028 | |
| 33029 | /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t |
| 33030 | * might not generate better code due to casting. |
| 33031 | */ |
| 33032 | |
| 33033 | /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */ |
| 33034 | duk_to_number(thr, idx_val); |
| 33035 | if (duk_is_nan(thr, idx_val)) { |
| 33036 | return; |
| 33037 | } |
| 33038 | duk_dup(thr, idx_val); |
| 33039 | duk_to_int(thr, -1); |
| 33040 | d = duk_get_number(thr, -1); /* get as double to handle huge numbers correctly */ |
| 33041 | if (d >= 0.0 && d <= 99.0) { |
| 33042 | d += 1900.0; |
| 33043 | duk_push_number(thr, d); |
| 33044 | duk_replace(thr, idx_val); |
| 33045 | } |
| 33046 | duk_pop(thr); |
| 33047 | } |
| 33048 | |
| 33049 | /* Set datetime parts from stack arguments, defaulting any missing values. |
| 33050 | * Day-of-week is not set; it is not required when setting the time value. |
| 33051 | */ |
| 33052 | DUK_LOCAL void duk__set_parts_from_args(duk_hthread *thr, duk_double_t *dparts, duk_idx_t nargs) { |
| 33053 | duk_double_t d; |
| 33054 | duk_small_uint_t i; |
| 33055 | duk_small_uint_t idx; |
| 33056 | |
| 33057 | /* Causes a ToNumber() coercion, but doesn't break coercion order since |
| 33058 | * year is coerced first anyway. |
| 33059 | */ |
| 33060 | duk__twodigit_year_fixup(thr, 0); |
| 33061 | |
| 33062 | /* There are at most 7 args, but we use 8 here so that also |
| 33063 | * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential |
| 33064 | * for any Valgrind gripes later. |
| 33065 | */ |
| 33066 | for (i = 0; i < 8; i++) { |
| 33067 | /* Note: rely on index ordering */ |
| 33068 | idx = DUK_DATE_IDX_YEAR + i; |
| 33069 | if ((duk_idx_t) i < nargs) { |
| 33070 | d = duk_to_number(thr, (duk_idx_t) i); |
| 33071 | if (idx == DUK_DATE_IDX_DAY) { |
| 33072 | /* Convert day from one-based to zero-based (internal). This may |
| 33073 | * cause the day part to be negative, which is OK. |
| 33074 | */ |
| 33075 | d -= 1.0; |
| 33076 | } |
| 33077 | } else { |
| 33078 | /* All components default to 0 except day-of-month which defaults |
| 33079 | * to 1. However, because our internal day-of-month is zero-based, |
| 33080 | * it also defaults to zero here. |
| 33081 | */ |
| 33082 | d = 0.0; |
| 33083 | } |
| 33084 | dparts[idx] = d; |
| 33085 | } |
| 33086 | |
| 33087 | DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf" , |
| 33088 | (double) dparts[0], (double) dparts[1], |
| 33089 | (double) dparts[2], (double) dparts[3], |
| 33090 | (double) dparts[4], (double) dparts[5], |
| 33091 | (double) dparts[6], (double) dparts[7])); |
| 33092 | } |
| 33093 | |
| 33094 | /* |
| 33095 | * Indirect magic value lookup for Date methods. |
| 33096 | * |
| 33097 | * Date methods don't put their control flags into the function magic value |
| 33098 | * because they wouldn't fit into a LIGHTFUNC's magic field. Instead, the |
| 33099 | * magic value is set to an index pointing to the array of control flags |
| 33100 | * below. |
| 33101 | * |
| 33102 | * This must be kept in strict sync with genbuiltins.py! |
| 33103 | */ |
| 33104 | |
| 33105 | static duk_uint16_t duk__date_magics[] = { |
| 33106 | /* 0: toString */ |
| 33107 | DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME, |
| 33108 | |
| 33109 | /* 1: toDateString */ |
| 33110 | DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME, |
| 33111 | |
| 33112 | /* 2: toTimeString */ |
| 33113 | DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME, |
| 33114 | |
| 33115 | /* 3: toLocaleString */ |
| 33116 | DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME, |
| 33117 | |
| 33118 | /* 4: toLocaleDateString */ |
| 33119 | DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME, |
| 33120 | |
| 33121 | /* 5: toLocaleTimeString */ |
| 33122 | DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME, |
| 33123 | |
| 33124 | /* 6: toUTCString */ |
| 33125 | DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME, |
| 33126 | |
| 33127 | /* 7: toISOString */ |
| 33128 | DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T, |
| 33129 | |
| 33130 | /* 8: getFullYear */ |
| 33131 | DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33132 | |
| 33133 | /* 9: getUTCFullYear */ |
| 33134 | 0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33135 | |
| 33136 | /* 10: getMonth */ |
| 33137 | DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33138 | |
| 33139 | /* 11: getUTCMonth */ |
| 33140 | 0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33141 | |
| 33142 | /* 12: getDate */ |
| 33143 | DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33144 | |
| 33145 | /* 13: getUTCDate */ |
| 33146 | DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33147 | |
| 33148 | /* 14: getDay */ |
| 33149 | DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33150 | |
| 33151 | /* 15: getUTCDay */ |
| 33152 | 0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33153 | |
| 33154 | /* 16: getHours */ |
| 33155 | DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33156 | |
| 33157 | /* 17: getUTCHours */ |
| 33158 | 0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33159 | |
| 33160 | /* 18: getMinutes */ |
| 33161 | DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33162 | |
| 33163 | /* 19: getUTCMinutes */ |
| 33164 | 0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33165 | |
| 33166 | /* 20: getSeconds */ |
| 33167 | DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33168 | |
| 33169 | /* 21: getUTCSeconds */ |
| 33170 | 0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33171 | |
| 33172 | /* 22: getMilliseconds */ |
| 33173 | DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33174 | |
| 33175 | /* 23: getUTCMilliseconds */ |
| 33176 | 0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33177 | |
| 33178 | /* 24: setMilliseconds */ |
| 33179 | DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33180 | |
| 33181 | /* 25: setUTCMilliseconds */ |
| 33182 | DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33183 | |
| 33184 | /* 26: setSeconds */ |
| 33185 | DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33186 | |
| 33187 | /* 27: setUTCSeconds */ |
| 33188 | DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33189 | |
| 33190 | /* 28: setMinutes */ |
| 33191 | DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33192 | |
| 33193 | /* 29: setUTCMinutes */ |
| 33194 | DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33195 | |
| 33196 | /* 30: setHours */ |
| 33197 | DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33198 | |
| 33199 | /* 31: setUTCHours */ |
| 33200 | DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33201 | |
| 33202 | /* 32: setDate */ |
| 33203 | DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33204 | |
| 33205 | /* 33: setUTCDate */ |
| 33206 | 0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33207 | |
| 33208 | /* 34: setMonth */ |
| 33209 | DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33210 | |
| 33211 | /* 35: setUTCMonth */ |
| 33212 | 0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33213 | |
| 33214 | /* 36: setFullYear */ |
| 33215 | DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33216 | |
| 33217 | /* 37: setUTCFullYear */ |
| 33218 | DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33219 | |
| 33220 | /* 38: getYear */ |
| 33221 | DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33222 | |
| 33223 | /* 39: setYear */ |
| 33224 | DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT), |
| 33225 | }; |
| 33226 | |
| 33227 | DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_hthread *thr) { |
| 33228 | duk_small_uint_t magicidx = (duk_small_uint_t) duk_get_current_magic(thr); |
| 33229 | DUK_ASSERT(magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t))); |
| 33230 | return (duk_small_uint_t) duk__date_magics[magicidx]; |
| 33231 | } |
| 33232 | |
| 33233 | #if defined(DUK_USE_DATE_BUILTIN) |
| 33234 | /* |
| 33235 | * Constructor calls |
| 33236 | */ |
| 33237 | |
| 33238 | DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) { |
| 33239 | duk_idx_t nargs = duk_get_top(thr); |
| 33240 | duk_bool_t is_cons = duk_is_constructor_call(thr); |
| 33241 | duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; |
| 33242 | duk_double_t d; |
| 33243 | |
| 33244 | DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld" , (long) nargs, (long) is_cons)); |
| 33245 | |
| 33246 | (void) duk_push_object_helper(thr, |
| 33247 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 33248 | DUK_HOBJECT_FLAG_FASTREFS | |
| 33249 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE), |
| 33250 | DUK_BIDX_DATE_PROTOTYPE); |
| 33251 | |
| 33252 | /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date |
| 33253 | * is mutable. |
| 33254 | */ |
| 33255 | |
| 33256 | if (nargs == 0 || !is_cons) { |
| 33257 | d = duk__timeclip(duk_time_get_ecmascript_time_nofrac(thr)); |
| 33258 | duk_push_number(thr, d); |
| 33259 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); |
| 33260 | if (!is_cons) { |
| 33261 | /* called as a normal function: return new Date().toString() */ |
| 33262 | duk_to_string(thr, -1); |
| 33263 | } |
| 33264 | return 1; |
| 33265 | } else if (nargs == 1) { |
| 33266 | const char *str; |
| 33267 | duk_to_primitive(thr, 0, DUK_HINT_NONE); |
| 33268 | str = duk_get_string_notsymbol(thr, 0); |
| 33269 | if (str) { |
| 33270 | duk__parse_string(thr, str); |
| 33271 | duk_replace(thr, 0); /* may be NaN */ |
| 33272 | } |
| 33273 | d = duk__timeclip(duk_to_number(thr, 0)); /* symbols fail here */ |
| 33274 | duk_push_number(thr, d); |
| 33275 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); |
| 33276 | return 1; |
| 33277 | } |
| 33278 | |
| 33279 | duk__set_parts_from_args(thr, dparts, nargs); |
| 33280 | |
| 33281 | /* Parts are in local time, convert when setting. */ |
| 33282 | |
| 33283 | (void) duk__set_this_timeval_from_dparts(thr, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */ |
| 33284 | duk_pop(thr); /* -> [ ... this ] */ |
| 33285 | return 1; |
| 33286 | } |
| 33287 | |
| 33288 | DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_hthread *thr) { |
| 33289 | return duk__parse_string(thr, duk_to_string(thr, 0)); |
| 33290 | } |
| 33291 | |
| 33292 | DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) { |
| 33293 | duk_idx_t nargs = duk_get_top(thr); |
| 33294 | duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; |
| 33295 | duk_double_t d; |
| 33296 | |
| 33297 | /* Behavior for nargs < 2 is implementation dependent: currently we'll |
| 33298 | * set a NaN time value (matching V8 behavior) in this case. |
| 33299 | */ |
| 33300 | |
| 33301 | if (nargs < 2) { |
| 33302 | duk_push_nan(thr); |
| 33303 | } else { |
| 33304 | duk__set_parts_from_args(thr, dparts, nargs); |
| 33305 | d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/); |
| 33306 | duk_push_number(thr, d); |
| 33307 | } |
| 33308 | return 1; |
| 33309 | } |
| 33310 | |
| 33311 | DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) { |
| 33312 | duk_double_t d; |
| 33313 | |
| 33314 | d = duk_time_get_ecmascript_time_nofrac(thr); |
| 33315 | DUK_ASSERT(duk_double_equals(duk__timeclip(d), d)); /* TimeClip() should never be necessary */ |
| 33316 | duk_push_number(thr, d); |
| 33317 | return 1; |
| 33318 | } |
| 33319 | |
| 33320 | /* |
| 33321 | * String/JSON conversions |
| 33322 | * |
| 33323 | * Human readable conversions are now basically ISO 8601 with a space |
| 33324 | * (instead of 'T') as the date/time separator. This is a good baseline |
| 33325 | * and is platform independent. |
| 33326 | * |
| 33327 | * A shared native helper to provide many conversions. Magic value contains |
| 33328 | * a set of flags. The helper provides: |
| 33329 | * |
| 33330 | * toString() |
| 33331 | * toDateString() |
| 33332 | * toTimeString() |
| 33333 | * toLocaleString() |
| 33334 | * toLocaleDateString() |
| 33335 | * toLocaleTimeString() |
| 33336 | * toUTCString() |
| 33337 | * toISOString() |
| 33338 | * |
| 33339 | * Notes: |
| 33340 | * |
| 33341 | * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are |
| 33342 | * required to be the same ECMAScript function object (!), so it is |
| 33343 | * omitted from here. |
| 33344 | * |
| 33345 | * - Date.prototype.toUTCString(): E5.1 specification does not require a |
| 33346 | * specific format, but result should be human readable. The |
| 33347 | * specification suggests using ISO 8601 format with a space (instead |
| 33348 | * of 'T') separator if a more human readable format is not available. |
| 33349 | * |
| 33350 | * - Date.prototype.toISOString(): unlike other conversion functions, |
| 33351 | * toISOString() requires a RangeError for invalid date values. |
| 33352 | */ |
| 33353 | |
| 33354 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_hthread *thr) { |
| 33355 | duk_small_uint_t flags = duk__date_get_indirect_magic(thr); |
| 33356 | return duk__to_string_helper(thr, flags); |
| 33357 | } |
| 33358 | |
| 33359 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_hthread *thr) { |
| 33360 | /* This native function is also used for Date.prototype.getTime() |
| 33361 | * as their behavior is identical. |
| 33362 | */ |
| 33363 | |
| 33364 | duk_double_t d = duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ this ] */ |
| 33365 | DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d)); |
| 33366 | duk_push_number(thr, d); |
| 33367 | return 1; |
| 33368 | } |
| 33369 | |
| 33370 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_hthread *thr) { |
| 33371 | /* Note: toJSON() is a generic function which works even if 'this' |
| 33372 | * is not a Date. The sole argument is ignored. |
| 33373 | */ |
| 33374 | |
| 33375 | duk_push_this(thr); |
| 33376 | duk_to_object(thr, -1); |
| 33377 | |
| 33378 | duk_dup_top(thr); |
| 33379 | duk_to_primitive(thr, -1, DUK_HINT_NUMBER); |
| 33380 | if (duk_is_number(thr, -1)) { |
| 33381 | duk_double_t d = duk_get_number(thr, -1); |
| 33382 | if (!DUK_ISFINITE(d)) { |
| 33383 | duk_push_null(thr); |
| 33384 | return 1; |
| 33385 | } |
| 33386 | } |
| 33387 | duk_pop(thr); |
| 33388 | |
| 33389 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_ISO_STRING); |
| 33390 | duk_dup_m2(thr); /* -> [ O toIsoString O ] */ |
| 33391 | duk_call_method(thr, 0); |
| 33392 | return 1; |
| 33393 | } |
| 33394 | |
| 33395 | /* |
| 33396 | * Getters. |
| 33397 | * |
| 33398 | * Implementing getters is quite easy. The internal time value is either |
| 33399 | * NaN, or represents milliseconds (without fractions) from Jan 1, 1970. |
| 33400 | * The internal time value can be converted to integer parts, and each |
| 33401 | * part will be normalized and will fit into a 32-bit signed integer. |
| 33402 | * |
| 33403 | * A shared native helper to provide all getters. Magic value contains |
| 33404 | * a set of flags and also packs the date component index argument. The |
| 33405 | * helper provides: |
| 33406 | * |
| 33407 | * getFullYear() |
| 33408 | * getUTCFullYear() |
| 33409 | * getMonth() |
| 33410 | * getUTCMonth() |
| 33411 | * getDate() |
| 33412 | * getUTCDate() |
| 33413 | * getDay() |
| 33414 | * getUTCDay() |
| 33415 | * getHours() |
| 33416 | * getUTCHours() |
| 33417 | * getMinutes() |
| 33418 | * getUTCMinutes() |
| 33419 | * getSeconds() |
| 33420 | * getUTCSeconds() |
| 33421 | * getMilliseconds() |
| 33422 | * getUTCMilliseconds() |
| 33423 | * getYear() |
| 33424 | * |
| 33425 | * Notes: |
| 33426 | * |
| 33427 | * - Date.prototype.getDate(): 'date' means day-of-month, and is |
| 33428 | * zero-based in internal calculations but public API expects it to |
| 33429 | * be one-based. |
| 33430 | * |
| 33431 | * - Date.prototype.getTime() and Date.prototype.valueOf() have identical |
| 33432 | * behavior. They have separate function objects, but share the same C |
| 33433 | * function (duk_bi_date_prototype_value_of). |
| 33434 | */ |
| 33435 | |
| 33436 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_hthread *thr) { |
| 33437 | duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(thr); |
| 33438 | return duk__get_part_helper(thr, flags_and_idx); |
| 33439 | } |
| 33440 | |
| 33441 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_hthread *thr) { |
| 33442 | /* |
| 33443 | * Return (t - LocalTime(t)) in minutes: |
| 33444 | * |
| 33445 | * t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t)) |
| 33446 | * = -(LocalTZA + DaylightSavingTA(t)) |
| 33447 | * |
| 33448 | * where DaylightSavingTA() is checked for time 't'. |
| 33449 | * |
| 33450 | * Note that the sign of the result is opposite to common usage, |
| 33451 | * e.g. for EE(S)T which normally is +2h or +3h from UTC, this |
| 33452 | * function returns -120 or -180. |
| 33453 | * |
| 33454 | */ |
| 33455 | |
| 33456 | duk_double_t d; |
| 33457 | duk_int_t tzoffset; |
| 33458 | |
| 33459 | /* Note: DST adjustment is determined using UTC time. */ |
| 33460 | d = duk__push_this_get_timeval(thr, 0 /*flags*/); |
| 33461 | DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d)); |
| 33462 | if (DUK_ISNAN(d)) { |
| 33463 | duk_push_nan(thr); |
| 33464 | } else { |
| 33465 | DUK_ASSERT(DUK_ISFINITE(d)); |
| 33466 | tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); |
| 33467 | duk_push_int(thr, -tzoffset / 60); |
| 33468 | } |
| 33469 | return 1; |
| 33470 | } |
| 33471 | |
| 33472 | /* |
| 33473 | * Setters. |
| 33474 | * |
| 33475 | * Setters are a bit more complicated than getters. Component setters |
| 33476 | * break down the current time value into its (normalized) component |
| 33477 | * parts, replace one or more components with -unnormalized- new values, |
| 33478 | * and the components are then converted back into a time value. As an |
| 33479 | * example of using unnormalized values: |
| 33480 | * |
| 33481 | * var d = new Date(1234567890); |
| 33482 | * |
| 33483 | * is equivalent to: |
| 33484 | * |
| 33485 | * var d = new Date(0); |
| 33486 | * d.setUTCMilliseconds(1234567890); |
| 33487 | * |
| 33488 | * A shared native helper to provide almost all setters. Magic value |
| 33489 | * contains a set of flags and also packs the "maxnargs" argument. The |
| 33490 | * helper provides: |
| 33491 | * |
| 33492 | * setMilliseconds() |
| 33493 | * setUTCMilliseconds() |
| 33494 | * setSeconds() |
| 33495 | * setUTCSeconds() |
| 33496 | * setMinutes() |
| 33497 | * setUTCMinutes() |
| 33498 | * setHours() |
| 33499 | * setUTCHours() |
| 33500 | * setDate() |
| 33501 | * setUTCDate() |
| 33502 | * setMonth() |
| 33503 | * setUTCMonth() |
| 33504 | * setFullYear() |
| 33505 | * setUTCFullYear() |
| 33506 | * setYear() |
| 33507 | * |
| 33508 | * Notes: |
| 33509 | * |
| 33510 | * - Date.prototype.setYear() (Section B addition): special year check |
| 33511 | * is omitted. NaN / Infinity will just flow through and ultimately |
| 33512 | * result in a NaN internal time value. |
| 33513 | * |
| 33514 | * - Date.prototype.setYear() does not have optional arguments for |
| 33515 | * setting month and day-in-month (like setFullYear()), but we indicate |
| 33516 | * 'maxnargs' to be 3 to get the year written to the correct component |
| 33517 | * index in duk__set_part_helper(). The function has nargs == 1, so only |
| 33518 | * the year will be set regardless of actual argument count. |
| 33519 | */ |
| 33520 | |
| 33521 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_hthread *thr) { |
| 33522 | duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(thr); |
| 33523 | return duk__set_part_helper(thr, flags_and_maxnargs); |
| 33524 | } |
| 33525 | |
| 33526 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) { |
| 33527 | duk_double_t d; |
| 33528 | |
| 33529 | (void) duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ timeval this ] */ |
| 33530 | d = duk__timeclip(duk_to_number(thr, 0)); |
| 33531 | duk_push_number(thr, d); |
| 33532 | duk_dup_top(thr); |
| 33533 | /* Must force write because .setTime() must work even when |
| 33534 | * the Date instance is frozen. |
| 33535 | */ |
| 33536 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W); |
| 33537 | /* -> [ timeval this timeval ] */ |
| 33538 | |
| 33539 | return 1; |
| 33540 | } |
| 33541 | |
| 33542 | /* |
| 33543 | * Misc. |
| 33544 | */ |
| 33545 | |
| 33546 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 33547 | DUK_INTERNAL duk_ret_t duk_bi_date_prototype_toprimitive(duk_hthread *thr) { |
| 33548 | duk_size_t hintlen; |
| 33549 | const char *hintstr; |
| 33550 | duk_int_t hint; |
| 33551 | |
| 33552 | /* Invokes OrdinaryToPrimitive() with suitable hint. Note that the |
| 33553 | * method is generic, and works on non-Date arguments too. |
| 33554 | * |
| 33555 | * https://www.ecma-international.org/ecma-262/6.0/#sec-date.prototype-@@toprimitive |
| 33556 | */ |
| 33557 | |
| 33558 | duk_push_this(thr); |
| 33559 | duk_require_object(thr, -1); |
| 33560 | DUK_ASSERT_TOP(thr, 2); |
| 33561 | |
| 33562 | hintstr = duk_require_lstring(thr, 0, &hintlen); |
| 33563 | if ((hintlen == 6 && DUK_STRCMP(hintstr, "string" ) == 0) || |
| 33564 | (hintlen == 7 && DUK_STRCMP(hintstr, "default" ) == 0)) { |
| 33565 | hint = DUK_HINT_STRING; |
| 33566 | } else if (hintlen == 6 && DUK_STRCMP(hintstr, "number" ) == 0) { |
| 33567 | hint = DUK_HINT_NUMBER; |
| 33568 | } else { |
| 33569 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 33570 | } |
| 33571 | |
| 33572 | duk_to_primitive_ordinary(thr, -1, hint); |
| 33573 | return 1; |
| 33574 | } |
| 33575 | #endif /* DUK_USE_SYMBOL_BUILTIN */ |
| 33576 | |
| 33577 | #endif /* DUK_USE_DATE_BUILTIN */ |
| 33578 | |
| 33579 | /* automatic undefs */ |
| 33580 | #undef DUK__CF_ACCEPT |
| 33581 | #undef DUK__CF_ACCEPT_NUL |
| 33582 | #undef DUK__CF_NEG |
| 33583 | #undef DUK__DPRINT_DPARTS |
| 33584 | #undef DUK__DPRINT_PARTS |
| 33585 | #undef DUK__DPRINT_PARTS_AND_DPARTS |
| 33586 | #undef DUK__LOCAL_TZOFFSET_MAXITER |
| 33587 | #undef DUK__NUM_ISO8601_PARSER_PARTS |
| 33588 | #undef DUK__PACK_RULE |
| 33589 | #undef DUK__PI_DAY |
| 33590 | #undef DUK__PI_HOUR |
| 33591 | #undef DUK__PI_MILLISECOND |
| 33592 | #undef DUK__PI_MINUTE |
| 33593 | #undef DUK__PI_MONTH |
| 33594 | #undef DUK__PI_SECOND |
| 33595 | #undef DUK__PI_TZHOUR |
| 33596 | #undef DUK__PI_TZMINUTE |
| 33597 | #undef DUK__PI_YEAR |
| 33598 | #undef DUK__PM_DAY |
| 33599 | #undef DUK__PM_HOUR |
| 33600 | #undef DUK__PM_MILLISECOND |
| 33601 | #undef DUK__PM_MINUTE |
| 33602 | #undef DUK__PM_MONTH |
| 33603 | #undef DUK__PM_SECOND |
| 33604 | #undef DUK__PM_TZHOUR |
| 33605 | #undef DUK__PM_TZMINUTE |
| 33606 | #undef DUK__PM_YEAR |
| 33607 | #undef DUK__RULE_MASK_PART_SEP |
| 33608 | #undef DUK__SI_COLON |
| 33609 | #undef DUK__SI_MINUS |
| 33610 | #undef DUK__SI_NUL |
| 33611 | #undef DUK__SI_PERIOD |
| 33612 | #undef DUK__SI_PLUS |
| 33613 | #undef DUK__SI_SPACE |
| 33614 | #undef DUK__SI_T |
| 33615 | #undef DUK__SI_Z |
| 33616 | #undef DUK__SM_COLON |
| 33617 | #undef DUK__SM_MINUS |
| 33618 | #undef DUK__SM_NUL |
| 33619 | #undef DUK__SM_PERIOD |
| 33620 | #undef DUK__SM_PLUS |
| 33621 | #undef DUK__SM_SPACE |
| 33622 | #undef DUK__SM_T |
| 33623 | #undef DUK__SM_Z |
| 33624 | #undef DUK__UNPACK_RULE |
| 33625 | #undef DUK__WEEKDAY_MOD_ADDER |
| 33626 | #undef DUK__YEAR |
| 33627 | #line 1 "duk_bi_date_unix.c" |
| 33628 | /* |
| 33629 | * Unix-like Date providers |
| 33630 | * |
| 33631 | * Generally useful Unix / POSIX / ANSI Date providers. |
| 33632 | */ |
| 33633 | |
| 33634 | /* #include duk_internal.h -> already included */ |
| 33635 | |
| 33636 | /* The necessary #includes are in place in duk_config.h. */ |
| 33637 | |
| 33638 | /* Buffer sizes for some UNIX calls. Larger than strictly necessary |
| 33639 | * to avoid Valgrind errors. |
| 33640 | */ |
| 33641 | #define DUK__STRPTIME_BUF_SIZE 64 |
| 33642 | #define DUK__STRFTIME_BUF_SIZE 64 |
| 33643 | |
| 33644 | #if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY) |
| 33645 | /* Get current ECMAScript time (= UNIX/Posix time, but in milliseconds). */ |
| 33646 | DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) { |
| 33647 | struct timeval tv; |
| 33648 | duk_double_t d; |
| 33649 | |
| 33650 | if (gettimeofday(&tv, NULL) != 0) { |
| 33651 | DUK_D(DUK_DPRINT("gettimeofday() failed" )); |
| 33652 | return 0.0; |
| 33653 | } |
| 33654 | |
| 33655 | /* As of Duktape 2.2.0 allow fractions. */ |
| 33656 | d = ((duk_double_t) tv.tv_sec) * 1000.0 + |
| 33657 | ((duk_double_t) tv.tv_usec) / 1000.0; |
| 33658 | |
| 33659 | return d; |
| 33660 | } |
| 33661 | #endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */ |
| 33662 | |
| 33663 | #if defined(DUK_USE_DATE_NOW_TIME) |
| 33664 | /* Not a very good provider: only full seconds are available. */ |
| 33665 | DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) { |
| 33666 | time_t t; |
| 33667 | |
| 33668 | t = time(NULL); |
| 33669 | if (t == (time_t) -1) { |
| 33670 | DUK_D(DUK_DPRINT("time() failed" )); |
| 33671 | return 0.0; |
| 33672 | } |
| 33673 | return ((duk_double_t) t) * 1000.0; |
| 33674 | } |
| 33675 | #endif /* DUK_USE_DATE_NOW_TIME */ |
| 33676 | |
| 33677 | #if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) |
| 33678 | /* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */ |
| 33679 | DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) { |
| 33680 | time_t t, t1, t2; |
| 33681 | duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; |
| 33682 | duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; |
| 33683 | struct tm tms[2]; |
| 33684 | #if defined(DUK_USE_DATE_TZO_GMTIME) |
| 33685 | struct tm *tm_ptr; |
| 33686 | #endif |
| 33687 | |
| 33688 | /* For NaN/inf, the return value doesn't matter. */ |
| 33689 | if (!DUK_ISFINITE(d)) { |
| 33690 | return 0; |
| 33691 | } |
| 33692 | |
| 33693 | /* If not within ECMAScript range, some integer time calculations |
| 33694 | * won't work correctly (and some asserts will fail), so bail out |
| 33695 | * if so. This fixes test-bug-date-insane-setyear.js. There is |
| 33696 | * a +/- 24h leeway in this range check to avoid a test262 corner |
| 33697 | * case documented in test-bug-date-timeval-edges.js. |
| 33698 | */ |
| 33699 | if (!duk_bi_date_timeval_in_leeway_range(d)) { |
| 33700 | DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows" )); |
| 33701 | return 0; |
| 33702 | } |
| 33703 | |
| 33704 | /* |
| 33705 | * This is a bit tricky to implement portably. The result depends |
| 33706 | * on the timestamp (specifically, DST depends on the timestamp). |
| 33707 | * If e.g. UNIX APIs are used, they'll have portability issues with |
| 33708 | * very small and very large years. |
| 33709 | * |
| 33710 | * Current approach: |
| 33711 | * |
| 33712 | * - Stay within portable UNIX limits by using equivalent year mapping. |
| 33713 | * Avoid year 1970 and 2038 as some conversions start to fail, at |
| 33714 | * least on some platforms. Avoiding 1970 means that there are |
| 33715 | * currently DST discrepancies for 1970. |
| 33716 | * |
| 33717 | * - Create a UTC and local time breakdowns from 't'. Then create |
| 33718 | * a time_t using gmtime() and localtime() and compute the time |
| 33719 | * difference between the two. |
| 33720 | * |
| 33721 | * Equivalent year mapping (E5 Section 15.9.1.8): |
| 33722 | * |
| 33723 | * If the host environment provides functionality for determining |
| 33724 | * daylight saving time, the implementation of ECMAScript is free |
| 33725 | * to map the year in question to an equivalent year (same |
| 33726 | * leap-year-ness and same starting week day for the year) for which |
| 33727 | * the host environment provides daylight saving time information. |
| 33728 | * The only restriction is that all equivalent years should produce |
| 33729 | * the same result. |
| 33730 | * |
| 33731 | * This approach is quite reasonable but not entirely correct, e.g. |
| 33732 | * the specification also states (E5 Section 15.9.1.8): |
| 33733 | * |
| 33734 | * The implementation of ECMAScript should not try to determine |
| 33735 | * whether the exact time was subject to daylight saving time, but |
| 33736 | * just whether daylight saving time would have been in effect if |
| 33737 | * the _current daylight saving time algorithm_ had been used at the |
| 33738 | * time. This avoids complications such as taking into account the |
| 33739 | * years that the locale observed daylight saving time year round. |
| 33740 | * |
| 33741 | * Since we rely on the platform APIs for conversions between local |
| 33742 | * time and UTC, we can't guarantee the above. Rather, if the platform |
| 33743 | * has historical DST rules they will be applied. This seems to be the |
| 33744 | * general preferred direction in ECMAScript standardization (or at least |
| 33745 | * implementations) anyway, and even the equivalent year mapping should |
| 33746 | * be disabled if the platform is known to handle DST properly for the |
| 33747 | * full ECMAScript range. |
| 33748 | * |
| 33749 | * The following has useful discussion and links: |
| 33750 | * |
| 33751 | * https://bugzilla.mozilla.org/show_bug.cgi?id=351066 |
| 33752 | */ |
| 33753 | |
| 33754 | duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/); |
| 33755 | DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038); |
| 33756 | |
| 33757 | d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/); |
| 33758 | DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */ |
| 33759 | t = (time_t) (d / 1000.0); |
| 33760 | DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld" , (double) d, (long) t)); |
| 33761 | |
| 33762 | duk_memzero((void *) tms, sizeof(struct tm) * 2); |
| 33763 | |
| 33764 | #if defined(DUK_USE_DATE_TZO_GMTIME_R) |
| 33765 | (void) gmtime_r(&t, &tms[0]); |
| 33766 | (void) localtime_r(&t, &tms[1]); |
| 33767 | #elif defined(DUK_USE_DATE_TZO_GMTIME_S) |
| 33768 | (void) gmtime_s(&t, &tms[0]); |
| 33769 | (void) localtime_s(&t, &tms[1]); |
| 33770 | #elif defined(DUK_USE_DATE_TZO_GMTIME) |
| 33771 | tm_ptr = gmtime(&t); |
| 33772 | duk_memcpy((void *) &tms[0], tm_ptr, sizeof(struct tm)); |
| 33773 | tm_ptr = localtime(&t); |
| 33774 | duk_memcpy((void *) &tms[1], tm_ptr, sizeof(struct tm)); |
| 33775 | #else |
| 33776 | #error internal error |
| 33777 | #endif |
| 33778 | DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld," |
| 33779 | "wday:%ld,yday:%ld,isdst:%ld}" , |
| 33780 | (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour, |
| 33781 | (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year, |
| 33782 | (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst)); |
| 33783 | DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld," |
| 33784 | "wday:%ld,yday:%ld,isdst:%ld}" , |
| 33785 | (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour, |
| 33786 | (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year, |
| 33787 | (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst)); |
| 33788 | |
| 33789 | /* tm_isdst is both an input and an output to mktime(), use 0 to |
| 33790 | * avoid DST handling in mktime(): |
| 33791 | * - https://github.com/svaarala/duktape/issues/406 |
| 33792 | * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst |
| 33793 | */ |
| 33794 | tms[0].tm_isdst = 0; |
| 33795 | tms[1].tm_isdst = 0; |
| 33796 | t1 = mktime(&tms[0]); /* UTC */ |
| 33797 | t2 = mktime(&tms[1]); /* local */ |
| 33798 | if (t1 == (time_t) -1 || t2 == (time_t) -1) { |
| 33799 | /* This check used to be for (t < 0) but on some platforms |
| 33800 | * time_t is unsigned and apparently the proper way to detect |
| 33801 | * an mktime() error return is the cast above. See e.g.: |
| 33802 | * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html |
| 33803 | */ |
| 33804 | goto mktime_error; |
| 33805 | } |
| 33806 | DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)" , (long) t1, (long) t2)); |
| 33807 | |
| 33808 | /* Compute final offset in seconds, positive if local time ahead of |
| 33809 | * UTC (returned value is UTC-to-local offset). |
| 33810 | * |
| 33811 | * difftime() returns a double, so coercion to int generates quite |
| 33812 | * a lot of code. Direct subtraction is not portable, however. |
| 33813 | * XXX: allow direct subtraction on known platforms. |
| 33814 | */ |
| 33815 | #if 0 |
| 33816 | return (duk_int_t) (t2 - t1); |
| 33817 | #endif |
| 33818 | return (duk_int_t) difftime(t2, t1); |
| 33819 | |
| 33820 | mktime_error: |
| 33821 | /* XXX: return something more useful, so that caller can throw? */ |
| 33822 | DUK_D(DUK_DPRINT("mktime() failed, d=%lf" , (double) d)); |
| 33823 | return 0; |
| 33824 | } |
| 33825 | #endif /* DUK_USE_DATE_TZO_GMTIME */ |
| 33826 | |
| 33827 | #if defined(DUK_USE_DATE_PRS_STRPTIME) |
| 33828 | DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) { |
| 33829 | struct tm tm; |
| 33830 | time_t t; |
| 33831 | char buf[DUK__STRPTIME_BUF_SIZE]; |
| 33832 | |
| 33833 | /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */ |
| 33834 | DUK_ASSERT(str != NULL); |
| 33835 | duk_memzero(buf, sizeof(buf)); /* valgrind whine without this */ |
| 33836 | DUK_SNPRINTF(buf, sizeof(buf), "%s" , (const char *) str); |
| 33837 | buf[sizeof(buf) - 1] = (char) 0; |
| 33838 | |
| 33839 | DUK_DDD(DUK_DDDPRINT("parsing: '%s'" , (const char *) buf)); |
| 33840 | |
| 33841 | duk_memzero(&tm, sizeof(tm)); |
| 33842 | if (strptime((const char *) buf, "%c" , &tm) != NULL) { |
| 33843 | DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld," |
| 33844 | "wday:%ld,yday:%ld,isdst:%ld}" , |
| 33845 | (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour, |
| 33846 | (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year, |
| 33847 | (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst)); |
| 33848 | tm.tm_isdst = -1; /* negative: dst info not available */ |
| 33849 | |
| 33850 | t = mktime(&tm); |
| 33851 | DUK_DDD(DUK_DDDPRINT("mktime() -> %ld" , (long) t)); |
| 33852 | if (t >= 0) { |
| 33853 | duk_push_number(thr, ((duk_double_t) t) * 1000.0); |
| 33854 | return 1; |
| 33855 | } |
| 33856 | } |
| 33857 | |
| 33858 | return 0; |
| 33859 | } |
| 33860 | #endif /* DUK_USE_DATE_PRS_STRPTIME */ |
| 33861 | |
| 33862 | #if defined(DUK_USE_DATE_PRS_GETDATE) |
| 33863 | DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) { |
| 33864 | struct tm tm; |
| 33865 | duk_small_int_t rc; |
| 33866 | time_t t; |
| 33867 | |
| 33868 | /* For this to work, DATEMSK must be set, so this is not very |
| 33869 | * convenient for an embeddable interpreter. |
| 33870 | */ |
| 33871 | |
| 33872 | duk_memzero(&tm, sizeof(struct tm)); |
| 33873 | rc = (duk_small_int_t) getdate_r(str, &tm); |
| 33874 | DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld" , (long) rc)); |
| 33875 | |
| 33876 | if (rc == 0) { |
| 33877 | t = mktime(&tm); |
| 33878 | DUK_DDD(DUK_DDDPRINT("mktime() -> %ld" , (long) t)); |
| 33879 | if (t >= 0) { |
| 33880 | duk_push_number(thr, (duk_double_t) t); |
| 33881 | return 1; |
| 33882 | } |
| 33883 | } |
| 33884 | |
| 33885 | return 0; |
| 33886 | } |
| 33887 | #endif /* DUK_USE_DATE_PRS_GETDATE */ |
| 33888 | |
| 33889 | #if defined(DUK_USE_DATE_FMT_STRFTIME) |
| 33890 | DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_hthread *thr, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) { |
| 33891 | char buf[DUK__STRFTIME_BUF_SIZE]; |
| 33892 | struct tm tm; |
| 33893 | const char *fmt; |
| 33894 | |
| 33895 | DUK_UNREF(tzoffset); |
| 33896 | |
| 33897 | /* If the platform doesn't support the entire ECMAScript range, we need |
| 33898 | * to return 0 so that the caller can fall back to the default formatter. |
| 33899 | * |
| 33900 | * For now, assume that if time_t is 8 bytes or more, the whole ECMAScript |
| 33901 | * range is supported. For smaller time_t values (4 bytes in practice), |
| 33902 | * assumes that the signed 32-bit range is supported. |
| 33903 | * |
| 33904 | * XXX: detect this more correctly per platform. The size of time_t is |
| 33905 | * probably not an accurate guarantee of strftime() supporting or not |
| 33906 | * supporting a large time range (the full ECMAScript range). |
| 33907 | */ |
| 33908 | if (sizeof(time_t) < 8 && |
| 33909 | (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) { |
| 33910 | /* be paranoid for 32-bit time values (even avoiding negative ones) */ |
| 33911 | return 0; |
| 33912 | } |
| 33913 | |
| 33914 | duk_memzero(&tm, sizeof(tm)); |
| 33915 | tm.tm_sec = parts[DUK_DATE_IDX_SECOND]; |
| 33916 | tm.tm_min = parts[DUK_DATE_IDX_MINUTE]; |
| 33917 | tm.tm_hour = parts[DUK_DATE_IDX_HOUR]; |
| 33918 | tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */ |
| 33919 | tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */ |
| 33920 | tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900; |
| 33921 | tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY]; |
| 33922 | tm.tm_isdst = 0; |
| 33923 | |
| 33924 | duk_memzero(buf, sizeof(buf)); |
| 33925 | if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) { |
| 33926 | fmt = "%c" ; |
| 33927 | } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) { |
| 33928 | fmt = "%x" ; |
| 33929 | } else { |
| 33930 | DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME); |
| 33931 | fmt = "%X" ; |
| 33932 | } |
| 33933 | (void) strftime(buf, sizeof(buf) - 1, fmt, &tm); |
| 33934 | DUK_ASSERT(buf[sizeof(buf) - 1] == 0); |
| 33935 | |
| 33936 | duk_push_string(thr, buf); |
| 33937 | return 1; |
| 33938 | } |
| 33939 | #endif /* DUK_USE_DATE_FMT_STRFTIME */ |
| 33940 | |
| 33941 | #if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME) |
| 33942 | DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) { |
| 33943 | struct timespec ts; |
| 33944 | |
| 33945 | if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { |
| 33946 | return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0; |
| 33947 | } else { |
| 33948 | DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed" )); |
| 33949 | return 0.0; |
| 33950 | } |
| 33951 | } |
| 33952 | #endif |
| 33953 | |
| 33954 | /* automatic undefs */ |
| 33955 | #undef DUK__STRFTIME_BUF_SIZE |
| 33956 | #undef DUK__STRPTIME_BUF_SIZE |
| 33957 | #line 1 "duk_bi_date_windows.c" |
| 33958 | /* |
| 33959 | * Windows Date providers |
| 33960 | * |
| 33961 | * Platform specific links: |
| 33962 | * |
| 33963 | * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx |
| 33964 | */ |
| 33965 | |
| 33966 | /* #include duk_internal.h -> already included */ |
| 33967 | |
| 33968 | /* The necessary #includes are in place in duk_config.h. */ |
| 33969 | |
| 33970 | #if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) |
| 33971 | /* Shared Windows helpers. */ |
| 33972 | DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) { |
| 33973 | FILETIME ft; |
| 33974 | if (SystemTimeToFileTime(st, &ft) == 0) { |
| 33975 | DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0" )); |
| 33976 | res->QuadPart = 0; |
| 33977 | } else { |
| 33978 | res->LowPart = ft.dwLowDateTime; |
| 33979 | res->HighPart = ft.dwHighDateTime; |
| 33980 | } |
| 33981 | } |
| 33982 | |
| 33983 | #if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) |
| 33984 | DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) { |
| 33985 | res->LowPart = ft->dwLowDateTime; |
| 33986 | res->HighPart = ft->dwHighDateTime; |
| 33987 | } |
| 33988 | #endif /* DUK_USE_DATE_NOW_WINDOWS_SUBMS */ |
| 33989 | |
| 33990 | DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) { |
| 33991 | duk_memzero((void *) st, sizeof(*st)); |
| 33992 | st->wYear = 1970; |
| 33993 | st->wMonth = 1; |
| 33994 | st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */ |
| 33995 | st->wDay = 1; |
| 33996 | DUK_ASSERT(st->wHour == 0); |
| 33997 | DUK_ASSERT(st->wMinute == 0); |
| 33998 | DUK_ASSERT(st->wSecond == 0); |
| 33999 | DUK_ASSERT(st->wMilliseconds == 0); |
| 34000 | } |
| 34001 | #endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */ |
| 34002 | |
| 34003 | #if defined(DUK_USE_DATE_NOW_WINDOWS) |
| 34004 | DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) { |
| 34005 | /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970: |
| 34006 | * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx |
| 34007 | */ |
| 34008 | SYSTEMTIME st1, st2; |
| 34009 | ULARGE_INTEGER tmp1, tmp2; |
| 34010 | |
| 34011 | GetSystemTime(&st1); |
| 34012 | duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1); |
| 34013 | |
| 34014 | duk__set_systime_jan1970(&st2); |
| 34015 | duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); |
| 34016 | |
| 34017 | /* Difference is in 100ns units, convert to milliseconds, keeping |
| 34018 | * fractions since Duktape 2.2.0. This is only theoretical because |
| 34019 | * SYSTEMTIME is limited to milliseconds. |
| 34020 | */ |
| 34021 | return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0; |
| 34022 | } |
| 34023 | #endif /* DUK_USE_DATE_NOW_WINDOWS */ |
| 34024 | |
| 34025 | #if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS) |
| 34026 | DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) { |
| 34027 | /* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime() |
| 34028 | * for more accuracy. |
| 34029 | */ |
| 34030 | FILETIME ft1; |
| 34031 | SYSTEMTIME st2; |
| 34032 | ULARGE_INTEGER tmp1, tmp2; |
| 34033 | |
| 34034 | GetSystemTimePreciseAsFileTime(&ft1); |
| 34035 | duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1); |
| 34036 | |
| 34037 | duk__set_systime_jan1970(&st2); |
| 34038 | duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); |
| 34039 | |
| 34040 | /* Difference is in 100ns units, convert to milliseconds, keeping |
| 34041 | * fractions since Duktape 2.2.0. |
| 34042 | */ |
| 34043 | return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0; |
| 34044 | } |
| 34045 | #endif /* DUK_USE_DATE_NOW_WINDOWS */ |
| 34046 | |
| 34047 | #if defined(DUK_USE_DATE_TZO_WINDOWS) |
| 34048 | DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) { |
| 34049 | SYSTEMTIME st1; |
| 34050 | SYSTEMTIME st2; |
| 34051 | SYSTEMTIME st3; |
| 34052 | ULARGE_INTEGER tmp1; |
| 34053 | ULARGE_INTEGER tmp2; |
| 34054 | ULARGE_INTEGER tmp3; |
| 34055 | FILETIME ft1; |
| 34056 | |
| 34057 | /* XXX: handling of timestamps outside Windows supported range. |
| 34058 | * How does Windows deal with dates before 1600? Does windows |
| 34059 | * support all ECMAScript years (like -200000 and +200000)? |
| 34060 | * Should equivalent year mapping be used here too? If so, use |
| 34061 | * a shared helper (currently integrated into timeval-to-parts). |
| 34062 | */ |
| 34063 | |
| 34064 | /* Use the approach described in "Remarks" of FileTimeToLocalFileTime: |
| 34065 | * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx |
| 34066 | */ |
| 34067 | |
| 34068 | duk__set_systime_jan1970(&st1); |
| 34069 | duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1); |
| 34070 | tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */ |
| 34071 | tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */ |
| 34072 | |
| 34073 | ft1.dwLowDateTime = tmp2.LowPart; |
| 34074 | ft1.dwHighDateTime = tmp2.HighPart; |
| 34075 | if (FileTimeToSystemTime((const FILETIME *) &ft1, &st2) == 0) { |
| 34076 | DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0" )); |
| 34077 | return 0; |
| 34078 | } |
| 34079 | if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) { |
| 34080 | DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0" )); |
| 34081 | return 0; |
| 34082 | } |
| 34083 | duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3); |
| 34084 | |
| 34085 | /* Positive if local time ahead of UTC. */ |
| 34086 | return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */ |
| 34087 | } |
| 34088 | #endif /* DUK_USE_DATE_TZO_WINDOWS */ |
| 34089 | |
| 34090 | #if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST) |
| 34091 | DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) { |
| 34092 | SYSTEMTIME st1; |
| 34093 | SYSTEMTIME st2; |
| 34094 | FILETIME ft1; |
| 34095 | FILETIME ft2; |
| 34096 | ULARGE_INTEGER tmp1; |
| 34097 | ULARGE_INTEGER tmp2; |
| 34098 | |
| 34099 | /* Do a similar computation to duk_bi_date_get_local_tzoffset_windows |
| 34100 | * but without accounting for daylight savings time. Use this on |
| 34101 | * Windows platforms (like Durango) that don't support the |
| 34102 | * SystemTimeToTzSpecificLocalTime() call. |
| 34103 | */ |
| 34104 | |
| 34105 | /* current time not needed for this computation */ |
| 34106 | DUK_UNREF(d); |
| 34107 | |
| 34108 | duk__set_systime_jan1970(&st1); |
| 34109 | duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1); |
| 34110 | |
| 34111 | ft1.dwLowDateTime = tmp1.LowPart; |
| 34112 | ft1.dwHighDateTime = tmp1.HighPart; |
| 34113 | if (FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2) == 0) { |
| 34114 | DUK_D(DUK_DPRINT("FileTimeToLocalFileTime() failed, return tzoffset 0" )); |
| 34115 | return 0; |
| 34116 | } |
| 34117 | if (FileTimeToSystemTime((const FILETIME *) &ft2, &st2) == 0) { |
| 34118 | DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0" )); |
| 34119 | return 0; |
| 34120 | } |
| 34121 | duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2); |
| 34122 | |
| 34123 | return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */ |
| 34124 | } |
| 34125 | #endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */ |
| 34126 | |
| 34127 | #if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC) |
| 34128 | DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) { |
| 34129 | LARGE_INTEGER count, freq; |
| 34130 | |
| 34131 | /* There are legacy issues with QueryPerformanceCounter(): |
| 34132 | * - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward |
| 34133 | * - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions |
| 34134 | * |
| 34135 | * We avoid these by enabling QPC by default only for Vista or later. |
| 34136 | */ |
| 34137 | |
| 34138 | if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) { |
| 34139 | /* XXX: QueryPerformanceFrequency() can be cached */ |
| 34140 | return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0; |
| 34141 | } else { |
| 34142 | /* MSDN: "On systems that run Windows XP or later, the function |
| 34143 | * will always succeed and will thus never return zero." |
| 34144 | * Provide minimal error path just in case user enables this |
| 34145 | * feature in pre-XP Windows. |
| 34146 | */ |
| 34147 | return 0.0; |
| 34148 | } |
| 34149 | } |
| 34150 | #endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */ |
| 34151 | #line 1 "duk_bi_duktape.c" |
| 34152 | /* |
| 34153 | * Duktape built-ins |
| 34154 | * |
| 34155 | * Size optimization note: it might seem that vararg multipurpose functions |
| 34156 | * like fin(), enc(), and dec() are not very size optimal, but using a single |
| 34157 | * user-visible ECMAScript function saves a lot of run-time footprint; each |
| 34158 | * Function instance takes >100 bytes. Using a shared native helper and a |
| 34159 | * 'magic' value won't save much if there are multiple Function instances |
| 34160 | * anyway. |
| 34161 | */ |
| 34162 | |
| 34163 | /* #include duk_internal.h -> already included */ |
| 34164 | |
| 34165 | #if defined(DUK_USE_DUKTAPE_BUILTIN) |
| 34166 | |
| 34167 | DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) { |
| 34168 | duk_inspect_value(thr, -1); |
| 34169 | return 1; |
| 34170 | } |
| 34171 | |
| 34172 | DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) { |
| 34173 | duk_int_t level; |
| 34174 | |
| 34175 | level = duk_to_int(thr, 0); |
| 34176 | duk_inspect_callstack_entry(thr, level); |
| 34177 | return 1; |
| 34178 | } |
| 34179 | |
| 34180 | DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) { |
| 34181 | duk_small_uint_t flags; |
| 34182 | |
| 34183 | flags = (duk_small_uint_t) duk_get_uint(thr, 0); |
| 34184 | duk_heap_mark_and_sweep(thr->heap, flags); |
| 34185 | |
| 34186 | /* XXX: Not sure what the best return value would be in the API. |
| 34187 | * Return true for now. |
| 34188 | */ |
| 34189 | duk_push_true(thr); |
| 34190 | return 1; |
| 34191 | } |
| 34192 | |
| 34193 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 34194 | DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) { |
| 34195 | (void) duk_require_hobject(thr, 0); |
| 34196 | if (duk_get_top(thr) >= 2) { |
| 34197 | /* Set: currently a finalizer is disabled by setting it to |
| 34198 | * undefined; this does not remove the property at the moment. |
| 34199 | * The value could be type checked to be either a function |
| 34200 | * or something else; if something else, the property could |
| 34201 | * be deleted. Must use duk_set_finalizer() to keep |
| 34202 | * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync. |
| 34203 | */ |
| 34204 | duk_set_top(thr, 2); |
| 34205 | duk_set_finalizer(thr, 0); |
| 34206 | return 0; |
| 34207 | } else { |
| 34208 | /* Get. */ |
| 34209 | DUK_ASSERT(duk_get_top(thr) == 1); |
| 34210 | duk_get_finalizer(thr, 0); |
| 34211 | return 1; |
| 34212 | } |
| 34213 | } |
| 34214 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 34215 | |
| 34216 | DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) { |
| 34217 | duk_hstring *h_str; |
| 34218 | |
| 34219 | /* Vararg function: must be careful to check/require arguments. |
| 34220 | * The JSON helpers accept invalid indices and treat them like |
| 34221 | * non-existent optional parameters. |
| 34222 | */ |
| 34223 | |
| 34224 | h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons. */ |
| 34225 | duk_require_valid_index(thr, 1); |
| 34226 | |
| 34227 | if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { |
| 34228 | duk_set_top(thr, 2); |
| 34229 | duk_hex_encode(thr, 1); |
| 34230 | DUK_ASSERT_TOP(thr, 2); |
| 34231 | } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) { |
| 34232 | duk_set_top(thr, 2); |
| 34233 | duk_base64_encode(thr, 1); |
| 34234 | DUK_ASSERT_TOP(thr, 2); |
| 34235 | #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX) |
| 34236 | } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) { |
| 34237 | duk_bi_json_stringify_helper(thr, |
| 34238 | 1 /*idx_value*/, |
| 34239 | 2 /*idx_replacer*/, |
| 34240 | 3 /*idx_space*/, |
| 34241 | DUK_JSON_FLAG_EXT_CUSTOM | |
| 34242 | DUK_JSON_FLAG_ASCII_ONLY | |
| 34243 | DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/); |
| 34244 | #endif |
| 34245 | #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC) |
| 34246 | } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) { |
| 34247 | duk_bi_json_stringify_helper(thr, |
| 34248 | 1 /*idx_value*/, |
| 34249 | 2 /*idx_replacer*/, |
| 34250 | 3 /*idx_space*/, |
| 34251 | DUK_JSON_FLAG_EXT_COMPATIBLE | |
| 34252 | DUK_JSON_FLAG_ASCII_ONLY /*flags*/); |
| 34253 | #endif |
| 34254 | } else { |
| 34255 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 34256 | } |
| 34257 | return 1; |
| 34258 | } |
| 34259 | |
| 34260 | DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) { |
| 34261 | duk_hstring *h_str; |
| 34262 | |
| 34263 | /* Vararg function: must be careful to check/require arguments. |
| 34264 | * The JSON helpers accept invalid indices and treat them like |
| 34265 | * non-existent optional parameters. |
| 34266 | */ |
| 34267 | |
| 34268 | h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons */ |
| 34269 | duk_require_valid_index(thr, 1); |
| 34270 | |
| 34271 | if (h_str == DUK_HTHREAD_STRING_HEX(thr)) { |
| 34272 | duk_set_top(thr, 2); |
| 34273 | duk_hex_decode(thr, 1); |
| 34274 | DUK_ASSERT_TOP(thr, 2); |
| 34275 | } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) { |
| 34276 | duk_set_top(thr, 2); |
| 34277 | duk_base64_decode(thr, 1); |
| 34278 | DUK_ASSERT_TOP(thr, 2); |
| 34279 | #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX) |
| 34280 | } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) { |
| 34281 | duk_bi_json_parse_helper(thr, |
| 34282 | 1 /*idx_value*/, |
| 34283 | 2 /*idx_replacer*/, |
| 34284 | DUK_JSON_FLAG_EXT_CUSTOM /*flags*/); |
| 34285 | #endif |
| 34286 | #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC) |
| 34287 | } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) { |
| 34288 | duk_bi_json_parse_helper(thr, |
| 34289 | 1 /*idx_value*/, |
| 34290 | 2 /*idx_replacer*/, |
| 34291 | DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/); |
| 34292 | #endif |
| 34293 | } else { |
| 34294 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 34295 | } |
| 34296 | return 1; |
| 34297 | } |
| 34298 | |
| 34299 | /* |
| 34300 | * Compact an object |
| 34301 | */ |
| 34302 | |
| 34303 | DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) { |
| 34304 | DUK_ASSERT_TOP(thr, 1); |
| 34305 | duk_compact(thr, 0); |
| 34306 | return 1; /* return the argument object */ |
| 34307 | } |
| 34308 | |
| 34309 | #endif /* DUK_USE_DUKTAPE_BUILTIN */ |
| 34310 | #line 1 "duk_bi_encoding.c" |
| 34311 | /* |
| 34312 | * WHATWG Encoding API built-ins |
| 34313 | * |
| 34314 | * API specification: https://encoding.spec.whatwg.org/#api |
| 34315 | * Web IDL: https://www.w3.org/TR/WebIDL/ |
| 34316 | */ |
| 34317 | |
| 34318 | /* #include duk_internal.h -> already included */ |
| 34319 | |
| 34320 | /* |
| 34321 | * Data structures for encoding/decoding |
| 34322 | */ |
| 34323 | |
| 34324 | typedef struct { |
| 34325 | duk_uint8_t *out; /* where to write next byte(s) */ |
| 34326 | duk_codepoint_t lead; /* lead surrogate */ |
| 34327 | } duk__encode_context; |
| 34328 | |
| 34329 | typedef struct { |
| 34330 | /* UTF-8 decoding state */ |
| 34331 | duk_codepoint_t codepoint; /* built up incrementally */ |
| 34332 | duk_uint8_t upper; /* max value of next byte (decode error otherwise) */ |
| 34333 | duk_uint8_t lower; /* min value of next byte (ditto) */ |
| 34334 | duk_uint8_t needed; /* how many more bytes we need */ |
| 34335 | duk_uint8_t bom_handled; /* BOM seen or no longer expected */ |
| 34336 | |
| 34337 | /* Decoder configuration */ |
| 34338 | duk_uint8_t fatal; |
| 34339 | duk_uint8_t ignore_bom; |
| 34340 | } duk__decode_context; |
| 34341 | |
| 34342 | /* The signed duk_codepoint_t type is used to signal a decoded codepoint |
| 34343 | * (>= 0) or various other states using negative values. |
| 34344 | */ |
| 34345 | #define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */ |
| 34346 | #define DUK__CP_ERROR (-2) /* decoding error */ |
| 34347 | #define DUK__CP_RETRY (-3) /* decoding error; retry last byte */ |
| 34348 | |
| 34349 | /* |
| 34350 | * Raw helpers for encoding/decoding |
| 34351 | */ |
| 34352 | |
| 34353 | /* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */ |
| 34354 | DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) { |
| 34355 | *ptr++ = 0xef; |
| 34356 | *ptr++ = 0xbf; |
| 34357 | *ptr++ = 0xbd; |
| 34358 | return ptr; |
| 34359 | } |
| 34360 | |
| 34361 | DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) { |
| 34362 | /* (Re)init the decoding state of 'dec_ctx' but leave decoder |
| 34363 | * configuration fields untouched. |
| 34364 | */ |
| 34365 | dec_ctx->codepoint = 0x0000L; |
| 34366 | dec_ctx->upper = 0xbf; |
| 34367 | dec_ctx->lower = 0x80; |
| 34368 | dec_ctx->needed = 0; |
| 34369 | dec_ctx->bom_handled = 0; |
| 34370 | } |
| 34371 | |
| 34372 | DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) { |
| 34373 | /* |
| 34374 | * UTF-8 algorithm based on the Encoding specification: |
| 34375 | * https://encoding.spec.whatwg.org/#utf-8-decoder |
| 34376 | * |
| 34377 | * Two main states: decoding initial byte vs. decoding continuation |
| 34378 | * bytes. Shortest length encoding is validated by restricting the |
| 34379 | * allowed range of first continuation byte using 'lower' and 'upper'. |
| 34380 | */ |
| 34381 | |
| 34382 | if (dec_ctx->needed == 0) { |
| 34383 | /* process initial byte */ |
| 34384 | if (x <= 0x7f) { |
| 34385 | /* U+0000-U+007F, 1 byte (ASCII) */ |
| 34386 | return (duk_codepoint_t) x; |
| 34387 | } else if (x >= 0xc2 && x <= 0xdf) { |
| 34388 | /* U+0080-U+07FF, 2 bytes */ |
| 34389 | dec_ctx->needed = 1; |
| 34390 | dec_ctx->codepoint = x & 0x1f; |
| 34391 | DUK_ASSERT(dec_ctx->lower == 0x80); |
| 34392 | DUK_ASSERT(dec_ctx->upper == 0xbf); |
| 34393 | return DUK__CP_CONTINUE; |
| 34394 | } else if (x >= 0xe0 && x <= 0xef) { |
| 34395 | /* U+0800-U+FFFF, 3 bytes */ |
| 34396 | if (x == 0xe0) { |
| 34397 | dec_ctx->lower = 0xa0; |
| 34398 | DUK_ASSERT(dec_ctx->upper == 0xbf); |
| 34399 | } else if (x == 0xed) { |
| 34400 | DUK_ASSERT(dec_ctx->lower == 0x80); |
| 34401 | dec_ctx->upper = 0x9f; |
| 34402 | } |
| 34403 | dec_ctx->needed = 2; |
| 34404 | dec_ctx->codepoint = x & 0x0f; |
| 34405 | return DUK__CP_CONTINUE; |
| 34406 | } else if (x >= 0xf0 && x <= 0xf4) { |
| 34407 | /* U+010000-U+10FFFF, 4 bytes */ |
| 34408 | if (x == 0xf0) { |
| 34409 | dec_ctx->lower = 0x90; |
| 34410 | DUK_ASSERT(dec_ctx->upper == 0xbf); |
| 34411 | } else if (x == 0xf4) { |
| 34412 | DUK_ASSERT(dec_ctx->lower == 0x80); |
| 34413 | dec_ctx->upper = 0x8f; |
| 34414 | } |
| 34415 | dec_ctx->needed = 3; |
| 34416 | dec_ctx->codepoint = x & 0x07; |
| 34417 | return DUK__CP_CONTINUE; |
| 34418 | } else { |
| 34419 | /* not a legal initial byte */ |
| 34420 | return DUK__CP_ERROR; |
| 34421 | } |
| 34422 | } else { |
| 34423 | /* process continuation byte */ |
| 34424 | if (x >= dec_ctx->lower && x <= dec_ctx->upper) { |
| 34425 | dec_ctx->lower = 0x80; |
| 34426 | dec_ctx->upper = 0xbf; |
| 34427 | dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f); |
| 34428 | if (--dec_ctx->needed > 0) { |
| 34429 | /* need more bytes */ |
| 34430 | return DUK__CP_CONTINUE; |
| 34431 | } else { |
| 34432 | /* got a codepoint */ |
| 34433 | duk_codepoint_t ret; |
| 34434 | DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */ |
| 34435 | ret = dec_ctx->codepoint; |
| 34436 | dec_ctx->codepoint = 0x0000L; |
| 34437 | dec_ctx->needed = 0; |
| 34438 | return ret; |
| 34439 | } |
| 34440 | } else { |
| 34441 | /* We just encountered an illegal UTF-8 continuation byte. This might |
| 34442 | * be the initial byte of the next character; if we return a plain |
| 34443 | * error status and the decoder is in replacement mode, the character |
| 34444 | * will be masked. We still need to alert the caller to the error |
| 34445 | * though. |
| 34446 | */ |
| 34447 | dec_ctx->codepoint = 0x0000L; |
| 34448 | dec_ctx->needed = 0; |
| 34449 | dec_ctx->lower = 0x80; |
| 34450 | dec_ctx->upper = 0xbf; |
| 34451 | return DUK__CP_RETRY; |
| 34452 | } |
| 34453 | } |
| 34454 | } |
| 34455 | |
| 34456 | #if defined(DUK_USE_ENCODING_BUILTINS) |
| 34457 | DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) { |
| 34458 | duk__encode_context *enc_ctx; |
| 34459 | |
| 34460 | DUK_ASSERT(codepoint >= 0); |
| 34461 | enc_ctx = (duk__encode_context *) udata; |
| 34462 | DUK_ASSERT(enc_ctx != NULL); |
| 34463 | |
| 34464 | #if !defined(DUK_USE_PREFER_SIZE) |
| 34465 | if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) { |
| 34466 | /* Fast path for ASCII. */ |
| 34467 | *enc_ctx->out++ = (duk_uint8_t) codepoint; |
| 34468 | return; |
| 34469 | } |
| 34470 | #endif |
| 34471 | |
| 34472 | if (DUK_UNLIKELY(codepoint > 0x10ffffL)) { |
| 34473 | /* cannot legally encode in UTF-8 */ |
| 34474 | codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; |
| 34475 | } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) { |
| 34476 | if (codepoint <= 0xdbffL) { |
| 34477 | /* high surrogate */ |
| 34478 | duk_codepoint_t prev_lead = enc_ctx->lead; |
| 34479 | enc_ctx->lead = codepoint; |
| 34480 | if (prev_lead == 0x0000L) { |
| 34481 | /* high surrogate, no output */ |
| 34482 | return; |
| 34483 | } else { |
| 34484 | /* consecutive high surrogates, consider first one unpaired */ |
| 34485 | codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; |
| 34486 | } |
| 34487 | } else { |
| 34488 | /* low surrogate */ |
| 34489 | if (enc_ctx->lead != 0x0000L) { |
| 34490 | codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L)); |
| 34491 | enc_ctx->lead = 0x0000L; |
| 34492 | } else { |
| 34493 | /* unpaired low surrogate */ |
| 34494 | DUK_ASSERT(enc_ctx->lead == 0x0000L); |
| 34495 | codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; |
| 34496 | } |
| 34497 | } |
| 34498 | } else { |
| 34499 | if (enc_ctx->lead != 0x0000L) { |
| 34500 | /* unpaired high surrogate: emit replacement character and the input codepoint */ |
| 34501 | enc_ctx->lead = 0x0000L; |
| 34502 | enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out); |
| 34503 | } |
| 34504 | } |
| 34505 | |
| 34506 | /* Codepoint may be original input, a decoded surrogate pair, or may |
| 34507 | * have been replaced with U+FFFD. |
| 34508 | */ |
| 34509 | enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out); |
| 34510 | } |
| 34511 | #endif /* DUK_USE_ENCODING_BUILTINS */ |
| 34512 | |
| 34513 | /* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8 |
| 34514 | * decoder. |
| 34515 | */ |
| 34516 | DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) { |
| 34517 | const duk_uint8_t *input; |
| 34518 | duk_size_t len = 0; |
| 34519 | duk_size_t len_tmp; |
| 34520 | duk_bool_t stream = 0; |
| 34521 | duk_codepoint_t codepoint; |
| 34522 | duk_uint8_t *output; |
| 34523 | const duk_uint8_t *in; |
| 34524 | duk_uint8_t *out; |
| 34525 | |
| 34526 | DUK_ASSERT(dec_ctx != NULL); |
| 34527 | |
| 34528 | /* Careful with input buffer pointer: any side effects involving |
| 34529 | * code execution (e.g. getters, coercion calls, and finalizers) |
| 34530 | * may cause a resize and invalidate a pointer we've read. This |
| 34531 | * is why the pointer is actually looked up at the last minute. |
| 34532 | * Argument validation must still happen first to match WHATWG |
| 34533 | * required side effect order. |
| 34534 | */ |
| 34535 | |
| 34536 | if (duk_is_undefined(thr, 0)) { |
| 34537 | duk_push_fixed_buffer_nozero(thr, 0); |
| 34538 | duk_replace(thr, 0); |
| 34539 | } |
| 34540 | (void) duk_require_buffer_data(thr, 0, &len); /* Need 'len', avoid pointer. */ |
| 34541 | |
| 34542 | if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED | |
| 34543 | DUK_TYPE_MASK_NULL | |
| 34544 | DUK_TYPE_MASK_NONE)) { |
| 34545 | /* Use defaults, treat missing value like undefined. */ |
| 34546 | } else { |
| 34547 | duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED | |
| 34548 | DUK_TYPE_MASK_NULL | |
| 34549 | DUK_TYPE_MASK_LIGHTFUNC | |
| 34550 | DUK_TYPE_MASK_BUFFER | |
| 34551 | DUK_TYPE_MASK_OBJECT); |
| 34552 | if (duk_get_prop_literal(thr, 1, "stream" )) { |
| 34553 | stream = duk_to_boolean(thr, -1); |
| 34554 | } |
| 34555 | } |
| 34556 | |
| 34557 | /* Allowance is 3*len in the general case because all bytes may potentially |
| 34558 | * become U+FFFD. If the first byte completes a non-BMP codepoint it will |
| 34559 | * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to |
| 34560 | * compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because |
| 34561 | * the 4->6 expansion is well under the 3x allowance. |
| 34562 | * |
| 34563 | * XXX: As with TextEncoder, need a better buffer allocation strategy here. |
| 34564 | */ |
| 34565 | if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) { |
| 34566 | DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG); |
| 34567 | DUK_WO_NORETURN(return 0;); |
| 34568 | } |
| 34569 | output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */ |
| 34570 | |
| 34571 | input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp); |
| 34572 | DUK_ASSERT(input != NULL || len == 0); |
| 34573 | if (DUK_UNLIKELY(len != len_tmp)) { |
| 34574 | /* Very unlikely but possible: source buffer was resized by |
| 34575 | * a side effect when fixed buffer was pushed. Output buffer |
| 34576 | * may not be large enough to hold output, so just fail if |
| 34577 | * length has changed. |
| 34578 | */ |
| 34579 | DUK_D(DUK_DPRINT("input buffer resized by side effect, fail" )); |
| 34580 | goto fail_type; |
| 34581 | } |
| 34582 | |
| 34583 | /* From this point onwards it's critical that no side effect occur |
| 34584 | * which may disturb 'input': finalizer execution, property accesses, |
| 34585 | * active coercions, etc. Even an allocation related mark-and-sweep |
| 34586 | * may affect the pointer because it may trigger a pending finalizer. |
| 34587 | */ |
| 34588 | |
| 34589 | in = input; |
| 34590 | out = output; |
| 34591 | while (in < input + len) { |
| 34592 | codepoint = duk__utf8_decode_next(dec_ctx, *in++); |
| 34593 | if (codepoint < 0) { |
| 34594 | if (codepoint == DUK__CP_CONTINUE) { |
| 34595 | continue; |
| 34596 | } |
| 34597 | |
| 34598 | /* Decoding error with or without retry. */ |
| 34599 | DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY); |
| 34600 | if (codepoint == DUK__CP_RETRY) { |
| 34601 | --in; /* retry last byte */ |
| 34602 | } |
| 34603 | /* replacement mode: replace with U+FFFD */ |
| 34604 | codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; |
| 34605 | if (dec_ctx->fatal) { |
| 34606 | /* fatal mode: throw a TypeError */ |
| 34607 | goto fail_type; |
| 34608 | } |
| 34609 | /* Continue with 'codepoint', Unicode replacement. */ |
| 34610 | } |
| 34611 | DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL); |
| 34612 | |
| 34613 | if (!dec_ctx->bom_handled) { |
| 34614 | dec_ctx->bom_handled = 1; |
| 34615 | if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) { |
| 34616 | continue; |
| 34617 | } |
| 34618 | } |
| 34619 | |
| 34620 | out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out); |
| 34621 | DUK_ASSERT(out <= output + (3 + (3 * len))); |
| 34622 | } |
| 34623 | |
| 34624 | if (!stream) { |
| 34625 | if (dec_ctx->needed != 0) { |
| 34626 | /* truncated sequence at end of buffer */ |
| 34627 | if (dec_ctx->fatal) { |
| 34628 | goto fail_type; |
| 34629 | } else { |
| 34630 | out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out); |
| 34631 | DUK_ASSERT(out <= output + (3 + (3 * len))); |
| 34632 | } |
| 34633 | } |
| 34634 | duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */ |
| 34635 | } |
| 34636 | |
| 34637 | /* Output buffer is fixed and thus stable even if there had been |
| 34638 | * side effects (which there shouldn't be). |
| 34639 | */ |
| 34640 | duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output)); |
| 34641 | return 1; |
| 34642 | |
| 34643 | fail_type: |
| 34644 | DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED); |
| 34645 | DUK_WO_NORETURN(return 0;); |
| 34646 | } |
| 34647 | |
| 34648 | /* |
| 34649 | * Built-in bindings |
| 34650 | */ |
| 34651 | |
| 34652 | #if defined(DUK_USE_ENCODING_BUILTINS) |
| 34653 | DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) { |
| 34654 | /* TextEncoder currently requires no persistent state, so the constructor |
| 34655 | * does nothing on purpose. |
| 34656 | */ |
| 34657 | |
| 34658 | duk_require_constructor_call(thr); |
| 34659 | return 0; |
| 34660 | } |
| 34661 | |
| 34662 | DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) { |
| 34663 | duk_push_literal(thr, "utf-8" ); |
| 34664 | return 1; |
| 34665 | } |
| 34666 | |
| 34667 | DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) { |
| 34668 | duk__encode_context enc_ctx; |
| 34669 | duk_size_t len; |
| 34670 | duk_size_t final_len; |
| 34671 | duk_uint8_t *output; |
| 34672 | |
| 34673 | DUK_ASSERT_TOP(thr, 1); |
| 34674 | if (duk_is_undefined(thr, 0)) { |
| 34675 | len = 0; |
| 34676 | } else { |
| 34677 | duk_hstring *h_input; |
| 34678 | |
| 34679 | h_input = duk_to_hstring(thr, 0); |
| 34680 | DUK_ASSERT(h_input != NULL); |
| 34681 | |
| 34682 | len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input); |
| 34683 | if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) { |
| 34684 | DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG); |
| 34685 | DUK_WO_NORETURN(return 0;); |
| 34686 | } |
| 34687 | } |
| 34688 | |
| 34689 | /* Allowance is 3*len because all bytes can potentially be replaced with |
| 34690 | * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8. |
| 34691 | * Rely on dynamic buffer data pointer stability: no other code has |
| 34692 | * access to the data pointer. |
| 34693 | * |
| 34694 | * XXX: The buffer allocation strategy used here is rather inefficient. |
| 34695 | * Maybe switch to a chunk-based strategy, or preprocess the string to |
| 34696 | * figure out the space needed ahead of time? |
| 34697 | */ |
| 34698 | DUK_ASSERT(3 * len >= len); |
| 34699 | output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len); |
| 34700 | |
| 34701 | if (len > 0) { |
| 34702 | DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */ |
| 34703 | |
| 34704 | /* XXX: duk_decode_string() is used to process the input |
| 34705 | * string. For standard ECMAScript strings, represented |
| 34706 | * internally as CESU-8, this is fine. However, behavior |
| 34707 | * beyond CESU-8 is not very strict: codepoints using an |
| 34708 | * extended form of UTF-8 are also accepted, and invalid |
| 34709 | * codepoint sequences (which are allowed in Duktape strings) |
| 34710 | * are not handled as well as they could (e.g. invalid |
| 34711 | * continuation bytes may mask following codepoints). |
| 34712 | * This is how ECMAScript code would also see such strings. |
| 34713 | * Maybe replace duk_decode_string() with an explicit strict |
| 34714 | * CESU-8 decoder here? |
| 34715 | */ |
| 34716 | enc_ctx.lead = 0x0000L; |
| 34717 | enc_ctx.out = output; |
| 34718 | duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx); |
| 34719 | if (enc_ctx.lead != 0x0000L) { |
| 34720 | /* unpaired high surrogate at end of string */ |
| 34721 | enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out); |
| 34722 | DUK_ASSERT(enc_ctx.out <= output + (3 * len)); |
| 34723 | } |
| 34724 | |
| 34725 | /* The output buffer is usually very much oversized, so shrink it to |
| 34726 | * actually needed size. Pointer stability assumed up to this point. |
| 34727 | */ |
| 34728 | DUK_ASSERT_TOP(thr, 2); |
| 34729 | DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL)); |
| 34730 | |
| 34731 | final_len = (duk_size_t) (enc_ctx.out - output); |
| 34732 | duk_resize_buffer(thr, -1, final_len); |
| 34733 | /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */ |
| 34734 | } else { |
| 34735 | final_len = 0; |
| 34736 | } |
| 34737 | |
| 34738 | /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will |
| 34739 | * be backed by a dynamic buffer which differs from e.g. Uint8Arrays |
| 34740 | * created as 'new Uint8Array(N)'. ECMAScript code won't see the |
| 34741 | * difference but C code will. When bufferobjects are not supported, |
| 34742 | * returns a plain dynamic buffer. |
| 34743 | */ |
| 34744 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 34745 | duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY); |
| 34746 | #endif |
| 34747 | return 1; |
| 34748 | } |
| 34749 | |
| 34750 | DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) { |
| 34751 | duk__decode_context *dec_ctx; |
| 34752 | duk_bool_t fatal = 0; |
| 34753 | duk_bool_t ignore_bom = 0; |
| 34754 | |
| 34755 | DUK_ASSERT_TOP(thr, 2); |
| 34756 | duk_require_constructor_call(thr); |
| 34757 | if (!duk_is_undefined(thr, 0)) { |
| 34758 | /* XXX: For now ignore 'label' (encoding identifier). */ |
| 34759 | duk_to_string(thr, 0); |
| 34760 | } |
| 34761 | if (!duk_is_null_or_undefined(thr, 1)) { |
| 34762 | if (duk_get_prop_literal(thr, 1, "fatal" )) { |
| 34763 | fatal = duk_to_boolean(thr, -1); |
| 34764 | } |
| 34765 | if (duk_get_prop_literal(thr, 1, "ignoreBOM" )) { |
| 34766 | ignore_bom = duk_to_boolean(thr, -1); |
| 34767 | } |
| 34768 | } |
| 34769 | |
| 34770 | duk_push_this(thr); |
| 34771 | |
| 34772 | /* The decode context is not assumed to be zeroed; all fields are |
| 34773 | * initialized explicitly. |
| 34774 | */ |
| 34775 | dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context)); |
| 34776 | dec_ctx->fatal = (duk_uint8_t) fatal; |
| 34777 | dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom; |
| 34778 | duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */ |
| 34779 | |
| 34780 | duk_put_prop_literal(thr, -2, DUK_INTERNAL_SYMBOL("Context" )); |
| 34781 | return 0; |
| 34782 | } |
| 34783 | |
| 34784 | /* Get TextDecoder context from 'this'; leaves garbage on stack. */ |
| 34785 | DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) { |
| 34786 | duk__decode_context *dec_ctx; |
| 34787 | duk_push_this(thr); |
| 34788 | duk_get_prop_literal(thr, -1, DUK_INTERNAL_SYMBOL("Context" )); |
| 34789 | dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL); |
| 34790 | DUK_ASSERT(dec_ctx != NULL); |
| 34791 | return dec_ctx; |
| 34792 | } |
| 34793 | |
| 34794 | DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) { |
| 34795 | duk__decode_context *dec_ctx; |
| 34796 | duk_int_t magic; |
| 34797 | |
| 34798 | dec_ctx = duk__get_textdecoder_context(thr); |
| 34799 | magic = duk_get_current_magic(thr); |
| 34800 | switch (magic) { |
| 34801 | case 0: |
| 34802 | /* Encoding is now fixed, so _Context lookup is only needed to |
| 34803 | * validate the 'this' binding (TypeError if not TextDecoder-like). |
| 34804 | */ |
| 34805 | duk_push_literal(thr, "utf-8" ); |
| 34806 | break; |
| 34807 | case 1: |
| 34808 | duk_push_boolean(thr, dec_ctx->fatal); |
| 34809 | break; |
| 34810 | default: |
| 34811 | duk_push_boolean(thr, dec_ctx->ignore_bom); |
| 34812 | break; |
| 34813 | } |
| 34814 | |
| 34815 | return 1; |
| 34816 | } |
| 34817 | |
| 34818 | DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) { |
| 34819 | duk__decode_context *dec_ctx; |
| 34820 | |
| 34821 | dec_ctx = duk__get_textdecoder_context(thr); |
| 34822 | return duk__decode_helper(thr, dec_ctx); |
| 34823 | } |
| 34824 | #endif /* DUK_USE_ENCODING_BUILTINS */ |
| 34825 | |
| 34826 | /* |
| 34827 | * Internal helper for Node.js Buffer |
| 34828 | */ |
| 34829 | |
| 34830 | /* Internal helper used for Node.js Buffer .toString(). Value stack convention |
| 34831 | * is currently odd: it mimics TextDecoder .decode() so that argument must be at |
| 34832 | * index 0, and decode options (not present for Buffer) at index 1. Return value |
| 34833 | * is a Duktape/C function return value. |
| 34834 | */ |
| 34835 | DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) { |
| 34836 | duk__decode_context dec_ctx; |
| 34837 | |
| 34838 | dec_ctx.fatal = 0; /* use replacement chars */ |
| 34839 | dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */ |
| 34840 | duk__utf8_decode_init(&dec_ctx); |
| 34841 | |
| 34842 | return duk__decode_helper(thr, &dec_ctx); |
| 34843 | } |
| 34844 | |
| 34845 | /* automatic undefs */ |
| 34846 | #undef DUK__CP_CONTINUE |
| 34847 | #undef DUK__CP_ERROR |
| 34848 | #undef DUK__CP_RETRY |
| 34849 | #line 1 "duk_bi_error.c" |
| 34850 | /* |
| 34851 | * Error built-ins |
| 34852 | */ |
| 34853 | |
| 34854 | /* #include duk_internal.h -> already included */ |
| 34855 | |
| 34856 | DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) { |
| 34857 | /* Behavior for constructor and non-constructor call is |
| 34858 | * the same except for augmenting the created error. When |
| 34859 | * called as a constructor, the caller (duk_new()) will handle |
| 34860 | * augmentation; when called as normal function, we need to do |
| 34861 | * it here. |
| 34862 | */ |
| 34863 | |
| 34864 | duk_small_int_t bidx_prototype = duk_get_current_magic(thr); |
| 34865 | |
| 34866 | /* same for both error and each subclass like TypeError */ |
| 34867 | duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 34868 | DUK_HOBJECT_FLAG_FASTREFS | |
| 34869 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR); |
| 34870 | |
| 34871 | (void) duk_push_object_helper(thr, flags_and_class, bidx_prototype); |
| 34872 | |
| 34873 | /* If message is undefined, the own property 'message' is not set at |
| 34874 | * all to save property space. An empty message is inherited anyway. |
| 34875 | */ |
| 34876 | if (!duk_is_undefined(thr, 0)) { |
| 34877 | duk_to_string(thr, 0); |
| 34878 | duk_dup_0(thr); /* [ message error message ] */ |
| 34879 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC); |
| 34880 | } |
| 34881 | |
| 34882 | /* Augment the error if called as a normal function. __FILE__ and __LINE__ |
| 34883 | * are not desirable in this case. |
| 34884 | */ |
| 34885 | |
| 34886 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 34887 | if (!duk_is_constructor_call(thr)) { |
| 34888 | duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE); |
| 34889 | } |
| 34890 | #endif |
| 34891 | |
| 34892 | return 1; |
| 34893 | } |
| 34894 | |
| 34895 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) { |
| 34896 | /* XXX: optimize with more direct internal access */ |
| 34897 | |
| 34898 | duk_push_this(thr); |
| 34899 | (void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 34900 | |
| 34901 | /* [ ... this ] */ |
| 34902 | |
| 34903 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME); |
| 34904 | if (duk_is_undefined(thr, -1)) { |
| 34905 | duk_pop(thr); |
| 34906 | duk_push_literal(thr, "Error" ); |
| 34907 | } else { |
| 34908 | duk_to_string(thr, -1); |
| 34909 | } |
| 34910 | |
| 34911 | /* [ ... this name ] */ |
| 34912 | |
| 34913 | /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by |
| 34914 | * accident or are they actually needed? The first ToString() |
| 34915 | * could conceivably return 'undefined'. |
| 34916 | */ |
| 34917 | duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE); |
| 34918 | if (duk_is_undefined(thr, -1)) { |
| 34919 | duk_pop(thr); |
| 34920 | duk_push_hstring_empty(thr); |
| 34921 | } else { |
| 34922 | duk_to_string(thr, -1); |
| 34923 | } |
| 34924 | |
| 34925 | /* [ ... this name message ] */ |
| 34926 | |
| 34927 | if (duk_get_length(thr, -2) == 0) { |
| 34928 | /* name is empty -> return message */ |
| 34929 | return 1; |
| 34930 | } |
| 34931 | if (duk_get_length(thr, -1) == 0) { |
| 34932 | /* message is empty -> return name */ |
| 34933 | duk_pop(thr); |
| 34934 | return 1; |
| 34935 | } |
| 34936 | duk_push_literal(thr, ": " ); |
| 34937 | duk_insert(thr, -2); /* ... name ': ' message */ |
| 34938 | duk_concat(thr, 3); |
| 34939 | |
| 34940 | return 1; |
| 34941 | } |
| 34942 | |
| 34943 | #if defined(DUK_USE_TRACEBACKS) |
| 34944 | |
| 34945 | /* |
| 34946 | * Traceback handling |
| 34947 | * |
| 34948 | * The unified helper decodes the traceback and produces various requested |
| 34949 | * outputs. It should be optimized for size, and may leave garbage on stack, |
| 34950 | * only the topmost return value matters. For instance, traceback separator |
| 34951 | * and decoded strings are pushed even when looking for filename only. |
| 34952 | * |
| 34953 | * NOTE: although _Tracedata is an internal property, user code can currently |
| 34954 | * write to the array (or replace it with something other than an array). |
| 34955 | * The code below must tolerate arbitrary _Tracedata. It can throw errors |
| 34956 | * etc, but cannot cause a segfault or memory unsafe behavior. |
| 34957 | */ |
| 34958 | |
| 34959 | /* constants arbitrary, chosen for small loads */ |
| 34960 | #define DUK__OUTPUT_TYPE_TRACEBACK (-1) |
| 34961 | #define DUK__OUTPUT_TYPE_FILENAME 0 |
| 34962 | #define DUK__OUTPUT_TYPE_LINENUMBER 1 |
| 34963 | |
| 34964 | DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) { |
| 34965 | duk_idx_t idx_td; |
| 34966 | duk_small_int_t i; /* traceback depth fits into 16 bits */ |
| 34967 | duk_small_int_t t; /* stack type fits into 16 bits */ |
| 34968 | duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */ |
| 34969 | const char *str_tailcall = " tailcall" ; |
| 34970 | const char *str_strict = " strict" ; |
| 34971 | const char *str_construct = " construct" ; |
| 34972 | const char *str_prevyield = " preventsyield" ; |
| 34973 | const char *str_directeval = " directeval" ; |
| 34974 | const char *str_empty = "" ; |
| 34975 | |
| 34976 | DUK_ASSERT_TOP(thr, 0); /* fixed arg count */ |
| 34977 | |
| 34978 | duk_push_this(thr); |
| 34979 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA); |
| 34980 | idx_td = duk_get_top_index(thr); |
| 34981 | |
| 34982 | duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE); |
| 34983 | duk_push_this(thr); |
| 34984 | |
| 34985 | /* [ ... this tracedata sep this ] */ |
| 34986 | |
| 34987 | /* XXX: skip null filename? */ |
| 34988 | |
| 34989 | if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) { |
| 34990 | /* Current tracedata contains 2 entries per callstack entry. */ |
| 34991 | for (i = 0; ; i += 2) { |
| 34992 | duk_int_t pc; |
| 34993 | duk_uint_t line; |
| 34994 | duk_uint_t flags; |
| 34995 | duk_double_t d; |
| 34996 | const char *funcname; |
| 34997 | const char *filename; |
| 34998 | duk_hobject *h_func; |
| 34999 | duk_hstring *h_name; |
| 35000 | |
| 35001 | duk_require_stack(thr, 5); |
| 35002 | duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i); |
| 35003 | duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1)); |
| 35004 | d = duk_to_number_m1(thr); |
| 35005 | pc = duk_double_to_int_t(DUK_FMOD(d, DUK_DOUBLE_2TO32)); |
| 35006 | flags = duk_double_to_uint_t(DUK_FLOOR(d / DUK_DOUBLE_2TO32)); |
| 35007 | t = (duk_small_int_t) duk_get_type(thr, -2); |
| 35008 | |
| 35009 | if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) { |
| 35010 | /* |
| 35011 | * ECMAScript/native function call or lightfunc call |
| 35012 | */ |
| 35013 | |
| 35014 | count_func++; |
| 35015 | |
| 35016 | /* [ ... v1(func) v2(pc+flags) ] */ |
| 35017 | |
| 35018 | /* These may be systematically omitted by Duktape |
| 35019 | * with certain config options, but allow user to |
| 35020 | * set them on a case-by-case basis. |
| 35021 | */ |
| 35022 | duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME); |
| 35023 | duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME); |
| 35024 | |
| 35025 | #if defined(DUK_USE_PC2LINE) |
| 35026 | line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc); |
| 35027 | #else |
| 35028 | line = 0; |
| 35029 | #endif |
| 35030 | |
| 35031 | /* [ ... v1 v2 name filename ] */ |
| 35032 | |
| 35033 | /* When looking for .fileName/.lineNumber, blame first |
| 35034 | * function which has a .fileName. |
| 35035 | */ |
| 35036 | if (duk_is_string_notsymbol(thr, -1)) { |
| 35037 | if (output_type == DUK__OUTPUT_TYPE_FILENAME) { |
| 35038 | return 1; |
| 35039 | } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { |
| 35040 | duk_push_uint(thr, line); |
| 35041 | return 1; |
| 35042 | } |
| 35043 | } |
| 35044 | |
| 35045 | /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */ |
| 35046 | /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */ |
| 35047 | h_name = duk_get_hstring_notsymbol(thr, -2); /* may be NULL */ |
| 35048 | funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ? |
| 35049 | "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name); |
| 35050 | filename = duk_get_string_notsymbol(thr, -1); |
| 35051 | filename = filename ? filename : "" ; |
| 35052 | DUK_ASSERT(funcname != NULL); |
| 35053 | DUK_ASSERT(filename != NULL); |
| 35054 | |
| 35055 | h_func = duk_get_hobject(thr, -4); /* NULL for lightfunc */ |
| 35056 | |
| 35057 | if (h_func == NULL) { |
| 35058 | duk_push_sprintf(thr, "at %s light%s%s%s%s%s" , |
| 35059 | (const char *) funcname, |
| 35060 | (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), |
| 35061 | (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), |
| 35062 | (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), |
| 35063 | (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), |
| 35064 | (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); |
| 35065 | } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) { |
| 35066 | duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s" , |
| 35067 | (const char *) funcname, |
| 35068 | (const char *) filename, |
| 35069 | (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), |
| 35070 | (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), |
| 35071 | (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), |
| 35072 | (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), |
| 35073 | (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); |
| 35074 | } else { |
| 35075 | duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s" , |
| 35076 | (const char *) funcname, |
| 35077 | (const char *) filename, |
| 35078 | (unsigned long) line, |
| 35079 | (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty), |
| 35080 | (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty), |
| 35081 | (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty), |
| 35082 | (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty), |
| 35083 | (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty)); |
| 35084 | } |
| 35085 | duk_replace(thr, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */ |
| 35086 | duk_pop_3(thr); /* -> [ ... str ] */ |
| 35087 | } else if (t == DUK_TYPE_STRING) { |
| 35088 | const char *str_file; |
| 35089 | |
| 35090 | /* |
| 35091 | * __FILE__ / __LINE__ entry, here 'pc' is line number directly. |
| 35092 | * Sometimes __FILE__ / __LINE__ is reported as the source for |
| 35093 | * the error (fileName, lineNumber), sometimes not. |
| 35094 | */ |
| 35095 | |
| 35096 | /* [ ... v1(filename) v2(line+flags) ] */ |
| 35097 | |
| 35098 | /* When looking for .fileName/.lineNumber, blame compilation |
| 35099 | * or C call site unless flagged not to do so. |
| 35100 | */ |
| 35101 | if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) { |
| 35102 | if (output_type == DUK__OUTPUT_TYPE_FILENAME) { |
| 35103 | duk_pop(thr); |
| 35104 | return 1; |
| 35105 | } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) { |
| 35106 | duk_push_int(thr, pc); |
| 35107 | return 1; |
| 35108 | } |
| 35109 | } |
| 35110 | |
| 35111 | /* Tracedata is trusted but avoid any risk of using a NULL |
| 35112 | * for %s format because it has undefined behavior. Symbols |
| 35113 | * don't need to be explicitly rejected as they pose no memory |
| 35114 | * safety issues. |
| 35115 | */ |
| 35116 | str_file = (const char *) duk_get_string(thr, -2); |
| 35117 | duk_push_sprintf(thr, "at [anon] (%s:%ld) internal" , |
| 35118 | (const char *) (str_file ? str_file : "null" ), (long) pc); |
| 35119 | duk_replace(thr, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */ |
| 35120 | duk_pop(thr); /* -> [ ... str ] */ |
| 35121 | } else { |
| 35122 | /* unknown, ignore */ |
| 35123 | duk_pop_2(thr); |
| 35124 | break; |
| 35125 | } |
| 35126 | } |
| 35127 | |
| 35128 | if (count_func >= DUK_USE_TRACEBACK_DEPTH) { |
| 35129 | /* Possibly truncated; there is no explicit truncation |
| 35130 | * marker so this is the best we can do. |
| 35131 | */ |
| 35132 | |
| 35133 | duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS); |
| 35134 | } |
| 35135 | } |
| 35136 | |
| 35137 | /* [ ... this tracedata sep this str1 ... strN ] */ |
| 35138 | |
| 35139 | if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) { |
| 35140 | return 0; |
| 35141 | } else { |
| 35142 | /* The 'this' after 'sep' will get ToString() coerced by |
| 35143 | * duk_join() automatically. We don't want to do that |
| 35144 | * coercion when providing .fileName or .lineNumber (GH-254). |
| 35145 | */ |
| 35146 | duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/); |
| 35147 | return 1; |
| 35148 | } |
| 35149 | } |
| 35150 | |
| 35151 | /* XXX: Output type could be encoded into native function 'magic' value to |
| 35152 | * save space. For setters the stridx could be encoded into 'magic'. |
| 35153 | */ |
| 35154 | |
| 35155 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) { |
| 35156 | return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK); |
| 35157 | } |
| 35158 | |
| 35159 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) { |
| 35160 | return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME); |
| 35161 | } |
| 35162 | |
| 35163 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) { |
| 35164 | return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER); |
| 35165 | } |
| 35166 | |
| 35167 | #else /* DUK_USE_TRACEBACKS */ |
| 35168 | |
| 35169 | /* |
| 35170 | * Traceback handling when tracebacks disabled. |
| 35171 | * |
| 35172 | * The fileName / lineNumber stubs are now necessary because built-in |
| 35173 | * data will include the accessor properties in Error.prototype. If those |
| 35174 | * are removed for builds without tracebacks, these can also be removed. |
| 35175 | * 'stack' should still be present and produce a ToString() equivalent: |
| 35176 | * this is useful for user code which prints a stacktrace and expects to |
| 35177 | * see something useful. A normal stacktrace also begins with a ToString() |
| 35178 | * of the error so this makes sense. |
| 35179 | */ |
| 35180 | |
| 35181 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) { |
| 35182 | /* XXX: remove this native function and map 'stack' accessor |
| 35183 | * to the toString() implementation directly. |
| 35184 | */ |
| 35185 | return duk_bi_error_prototype_to_string(thr); |
| 35186 | } |
| 35187 | |
| 35188 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) { |
| 35189 | DUK_UNREF(thr); |
| 35190 | return 0; |
| 35191 | } |
| 35192 | |
| 35193 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) { |
| 35194 | DUK_UNREF(thr); |
| 35195 | return 0; |
| 35196 | } |
| 35197 | |
| 35198 | #endif /* DUK_USE_TRACEBACKS */ |
| 35199 | |
| 35200 | DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, duk_small_uint_t stridx_key) { |
| 35201 | /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if |
| 35202 | * user code called Object.defineProperty() to create an overriding |
| 35203 | * own property. This allows user code to overwrite .fileName etc |
| 35204 | * intuitively as e.g. "err.fileName = 'dummy'" as one might expect. |
| 35205 | * See https://github.com/svaarala/duktape/issues/387. |
| 35206 | */ |
| 35207 | |
| 35208 | DUK_ASSERT_TOP(thr, 1); /* fixed arg count: value */ |
| 35209 | |
| 35210 | duk_push_this(thr); |
| 35211 | duk_push_hstring_stridx(thr, stridx_key); |
| 35212 | duk_dup_0(thr); |
| 35213 | |
| 35214 | /* [ ... obj key value ] */ |
| 35215 | |
| 35216 | DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T" , |
| 35217 | duk_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1))); |
| 35218 | |
| 35219 | duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | |
| 35220 | DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE | |
| 35221 | DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/ |
| 35222 | DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE); |
| 35223 | return 0; |
| 35224 | } |
| 35225 | |
| 35226 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_hthread *thr) { |
| 35227 | return duk__error_setter_helper(thr, DUK_STRIDX_STACK); |
| 35228 | } |
| 35229 | |
| 35230 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_hthread *thr) { |
| 35231 | return duk__error_setter_helper(thr, DUK_STRIDX_FILE_NAME); |
| 35232 | } |
| 35233 | |
| 35234 | DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) { |
| 35235 | return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER); |
| 35236 | } |
| 35237 | |
| 35238 | /* automatic undefs */ |
| 35239 | #undef DUK__OUTPUT_TYPE_FILENAME |
| 35240 | #undef DUK__OUTPUT_TYPE_LINENUMBER |
| 35241 | #undef DUK__OUTPUT_TYPE_TRACEBACK |
| 35242 | #line 1 "duk_bi_function.c" |
| 35243 | /* |
| 35244 | * Function built-ins |
| 35245 | */ |
| 35246 | |
| 35247 | /* #include duk_internal.h -> already included */ |
| 35248 | |
| 35249 | /* Needed even when Function built-in is disabled. */ |
| 35250 | DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) { |
| 35251 | /* ignore arguments, return undefined (E5 Section 15.3.4) */ |
| 35252 | DUK_UNREF(thr); |
| 35253 | return 0; |
| 35254 | } |
| 35255 | |
| 35256 | #if defined(DUK_USE_FUNCTION_BUILTIN) |
| 35257 | DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) { |
| 35258 | duk_hstring *h_sourcecode; |
| 35259 | duk_idx_t nargs; |
| 35260 | duk_idx_t i; |
| 35261 | duk_small_uint_t comp_flags; |
| 35262 | duk_hcompfunc *func; |
| 35263 | duk_hobject *outer_lex_env; |
| 35264 | duk_hobject *outer_var_env; |
| 35265 | |
| 35266 | /* normal and constructor calls have identical semantics */ |
| 35267 | |
| 35268 | nargs = duk_get_top(thr); |
| 35269 | for (i = 0; i < nargs; i++) { |
| 35270 | duk_to_string(thr, i); /* Rejects Symbols during coercion. */ |
| 35271 | } |
| 35272 | |
| 35273 | if (nargs == 0) { |
| 35274 | duk_push_hstring_empty(thr); |
| 35275 | duk_push_hstring_empty(thr); |
| 35276 | } else if (nargs == 1) { |
| 35277 | /* XXX: cover this with the generic >1 case? */ |
| 35278 | duk_push_hstring_empty(thr); |
| 35279 | } else { |
| 35280 | duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */ |
| 35281 | duk_push_literal(thr, "," ); |
| 35282 | duk_insert(thr, 1); |
| 35283 | duk_join(thr, nargs - 1); |
| 35284 | } |
| 35285 | |
| 35286 | /* [ body formals ], formals is comma separated list that needs to be parsed */ |
| 35287 | |
| 35288 | DUK_ASSERT_TOP(thr, 2); |
| 35289 | |
| 35290 | /* XXX: this placeholder is not always correct, but use for now. |
| 35291 | * It will fail in corner cases; see test-dev-func-cons-args.js. |
| 35292 | */ |
| 35293 | duk_push_literal(thr, "function(" ); |
| 35294 | duk_dup_1(thr); |
| 35295 | duk_push_literal(thr, "){" ); |
| 35296 | duk_dup_0(thr); |
| 35297 | duk_push_literal(thr, "\n}" ); /* Newline is important to handle trailing // comment. */ |
| 35298 | duk_concat(thr, 5); |
| 35299 | |
| 35300 | /* [ body formals source ] */ |
| 35301 | |
| 35302 | DUK_ASSERT_TOP(thr, 3); |
| 35303 | |
| 35304 | /* strictness is not inherited, intentional */ |
| 35305 | comp_flags = DUK_COMPILE_FUNCEXPR; |
| 35306 | |
| 35307 | duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */ |
| 35308 | h_sourcecode = duk_require_hstring(thr, -2); /* no symbol check needed; -2 is concat'd code */ |
| 35309 | duk_js_compile(thr, |
| 35310 | (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode), |
| 35311 | (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode), |
| 35312 | comp_flags); |
| 35313 | |
| 35314 | /* Force .name to 'anonymous' (ES2015). */ |
| 35315 | duk_push_literal(thr, "anonymous" ); |
| 35316 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); |
| 35317 | |
| 35318 | func = (duk_hcompfunc *) duk_known_hobject(thr, -1); |
| 35319 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func)); |
| 35320 | DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func)); |
| 35321 | |
| 35322 | /* [ body formals source template ] */ |
| 35323 | |
| 35324 | /* only outer_lex_env matters, as functions always get a new |
| 35325 | * variable declaration environment. |
| 35326 | */ |
| 35327 | |
| 35328 | outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 35329 | outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 35330 | |
| 35331 | duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/); |
| 35332 | |
| 35333 | /* [ body formals source template closure ] */ |
| 35334 | |
| 35335 | return 1; |
| 35336 | } |
| 35337 | #endif /* DUK_USE_FUNCTION_BUILTIN */ |
| 35338 | |
| 35339 | #if defined(DUK_USE_FUNCTION_BUILTIN) |
| 35340 | DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) { |
| 35341 | duk_tval *tv; |
| 35342 | |
| 35343 | /* |
| 35344 | * E5 Section 15.3.4.2 places few requirements on the output of |
| 35345 | * this function: the result is implementation dependent, must |
| 35346 | * follow FunctionDeclaration syntax (in particular, must have a |
| 35347 | * name even for anonymous functions or functions with empty name). |
| 35348 | * The output does NOT need to compile into anything useful. |
| 35349 | * |
| 35350 | * E6 Section 19.2.3.5 changes the requirements completely: the |
| 35351 | * result must either eval() to a functionally equivalent object |
| 35352 | * OR eval() to a SyntaxError. |
| 35353 | * |
| 35354 | * We opt for the SyntaxError approach for now, with a syntax that |
| 35355 | * mimics V8's native function syntax: |
| 35356 | * |
| 35357 | * 'function cos() { [native code] }' |
| 35358 | * |
| 35359 | * but extended with [ecmascript code], [bound code], and |
| 35360 | * [lightfunc code]. |
| 35361 | */ |
| 35362 | |
| 35363 | duk_push_this(thr); |
| 35364 | tv = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 35365 | DUK_ASSERT(tv != NULL); |
| 35366 | |
| 35367 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 35368 | duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv); |
| 35369 | const char *func_name; |
| 35370 | |
| 35371 | /* Function name: missing/undefined is mapped to empty string, |
| 35372 | * otherwise coerce to string. No handling for invalid identifier |
| 35373 | * characters or e.g. '{' in the function name. This doesn't |
| 35374 | * really matter as long as a SyntaxError results. Technically |
| 35375 | * if the name contained a suitable prefix followed by '//' it |
| 35376 | * might cause the result to parse without error. |
| 35377 | */ |
| 35378 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME); |
| 35379 | if (duk_is_undefined(thr, -1)) { |
| 35380 | func_name = "" ; |
| 35381 | } else { |
| 35382 | func_name = duk_to_string(thr, -1); |
| 35383 | DUK_ASSERT(func_name != NULL); |
| 35384 | } |
| 35385 | |
| 35386 | if (DUK_HOBJECT_IS_COMPFUNC(obj)) { |
| 35387 | duk_push_sprintf(thr, "function %s() { [ecmascript code] }" , (const char *) func_name); |
| 35388 | } else if (DUK_HOBJECT_IS_NATFUNC(obj)) { |
| 35389 | duk_push_sprintf(thr, "function %s() { [native code] }" , (const char *) func_name); |
| 35390 | } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) { |
| 35391 | duk_push_sprintf(thr, "function %s() { [bound code] }" , (const char *) func_name); |
| 35392 | } else { |
| 35393 | goto type_error; |
| 35394 | } |
| 35395 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { |
| 35396 | duk_push_lightfunc_tostring(thr, tv); |
| 35397 | } else { |
| 35398 | goto type_error; |
| 35399 | } |
| 35400 | |
| 35401 | return 1; |
| 35402 | |
| 35403 | type_error: |
| 35404 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 35405 | } |
| 35406 | #endif |
| 35407 | |
| 35408 | /* Always present because the native function pointer is needed in call |
| 35409 | * handling. |
| 35410 | */ |
| 35411 | DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) { |
| 35412 | /* .call() is dealt with in call handling by simulating its |
| 35413 | * effects so this function is actually never called. |
| 35414 | */ |
| 35415 | DUK_UNREF(thr); |
| 35416 | return DUK_RET_TYPE_ERROR; |
| 35417 | } |
| 35418 | |
| 35419 | DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) { |
| 35420 | /* Like .call(), never actually called. */ |
| 35421 | DUK_UNREF(thr); |
| 35422 | return DUK_RET_TYPE_ERROR; |
| 35423 | } |
| 35424 | |
| 35425 | DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) { |
| 35426 | /* Like .call(), never actually called. */ |
| 35427 | DUK_UNREF(thr); |
| 35428 | return DUK_RET_TYPE_ERROR; |
| 35429 | } |
| 35430 | |
| 35431 | DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) { |
| 35432 | /* Like .call(), never actually called. */ |
| 35433 | DUK_UNREF(thr); |
| 35434 | return DUK_RET_TYPE_ERROR; |
| 35435 | } |
| 35436 | |
| 35437 | #if defined(DUK_USE_FUNCTION_BUILTIN) |
| 35438 | /* Create a bound function which points to a target function which may |
| 35439 | * be bound or non-bound. If the target is bound, the argument lists |
| 35440 | * and 'this' binding of the functions are merged and the resulting |
| 35441 | * function points directly to the non-bound target. |
| 35442 | */ |
| 35443 | DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) { |
| 35444 | duk_hboundfunc *h_bound; |
| 35445 | duk_idx_t nargs; /* bound args, not counting 'this' binding */ |
| 35446 | duk_idx_t bound_nargs; |
| 35447 | duk_int_t bound_len; |
| 35448 | duk_tval *tv_prevbound; |
| 35449 | duk_idx_t n_prevbound; |
| 35450 | duk_tval *tv_res; |
| 35451 | duk_tval *tv_tmp; |
| 35452 | |
| 35453 | /* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */ |
| 35454 | |
| 35455 | /* Vararg function, careful arg handling, e.g. thisArg may not |
| 35456 | * be present. |
| 35457 | */ |
| 35458 | nargs = duk_get_top(thr) - 1; /* actual args, not counting 'this' binding */ |
| 35459 | if (nargs < 0) { |
| 35460 | nargs++; |
| 35461 | duk_push_undefined(thr); |
| 35462 | } |
| 35463 | DUK_ASSERT(nargs >= 0); |
| 35464 | |
| 35465 | /* Limit 'nargs' for bound functions to guarantee arithmetic |
| 35466 | * below will never wrap. |
| 35467 | */ |
| 35468 | if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) { |
| 35469 | DUK_DCERROR_RANGE_INVALID_COUNT(thr); |
| 35470 | } |
| 35471 | |
| 35472 | duk_push_this(thr); |
| 35473 | duk_require_callable(thr, -1); |
| 35474 | |
| 35475 | /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs+1 total) */ |
| 35476 | DUK_ASSERT_TOP(thr, nargs + 2); |
| 35477 | |
| 35478 | /* Create bound function object. */ |
| 35479 | h_bound = duk_push_hboundfunc(thr); |
| 35480 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target)); |
| 35481 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding)); |
| 35482 | DUK_ASSERT(h_bound->args == NULL); |
| 35483 | DUK_ASSERT(h_bound->nargs == 0); |
| 35484 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL); |
| 35485 | |
| 35486 | /* [ thisArg arg1 ... argN func boundFunc ] */ |
| 35487 | |
| 35488 | /* If the target is a bound function, argument lists must be |
| 35489 | * merged. The 'this' binding closest to the target function |
| 35490 | * wins because in call handling the 'this' gets replaced over |
| 35491 | * and over again until we call the non-bound function. |
| 35492 | */ |
| 35493 | tv_prevbound = NULL; |
| 35494 | n_prevbound = 0; |
| 35495 | tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0); |
| 35496 | DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp); |
| 35497 | tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2); |
| 35498 | DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp); |
| 35499 | |
| 35500 | if (DUK_TVAL_IS_OBJECT(tv_tmp)) { |
| 35501 | duk_hobject *h_target; |
| 35502 | duk_hobject *bound_proto; |
| 35503 | |
| 35504 | h_target = DUK_TVAL_GET_OBJECT(tv_tmp); |
| 35505 | DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target)); |
| 35506 | |
| 35507 | /* Internal prototype must be copied from the target. |
| 35508 | * For lightfuncs Function.prototype is used and is already |
| 35509 | * in place. |
| 35510 | */ |
| 35511 | bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target); |
| 35512 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto); |
| 35513 | |
| 35514 | /* The 'strict' flag is copied to get the special [[Get]] of E5.1 |
| 35515 | * Section 15.3.5.4 to apply when a 'caller' value is a strict bound |
| 35516 | * function. Not sure if this is correct, because the specification |
| 35517 | * is a bit ambiguous on this point but it would make sense. |
| 35518 | */ |
| 35519 | /* Strictness is inherited from target. */ |
| 35520 | if (DUK_HOBJECT_HAS_STRICT(h_target)) { |
| 35521 | DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound); |
| 35522 | } |
| 35523 | |
| 35524 | if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) { |
| 35525 | duk_hboundfunc *h_boundtarget; |
| 35526 | |
| 35527 | h_boundtarget = (duk_hboundfunc *) (void *) h_target; |
| 35528 | |
| 35529 | /* The final function should always be non-bound, unless |
| 35530 | * there's a bug in the internals. Assert for it. |
| 35531 | */ |
| 35532 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) || |
| 35533 | (DUK_TVAL_IS_OBJECT(&h_boundtarget->target) && |
| 35534 | DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) && |
| 35535 | !DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)))); |
| 35536 | |
| 35537 | DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target); |
| 35538 | DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding); |
| 35539 | |
| 35540 | tv_prevbound = h_boundtarget->args; |
| 35541 | n_prevbound = h_boundtarget->nargs; |
| 35542 | } |
| 35543 | } else { |
| 35544 | /* Lightfuncs are always strict. */ |
| 35545 | duk_hobject *bound_proto; |
| 35546 | |
| 35547 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp)); |
| 35548 | DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound); |
| 35549 | bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]; |
| 35550 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto); |
| 35551 | } |
| 35552 | |
| 35553 | DUK_TVAL_INCREF(thr, &h_bound->target); /* old values undefined, no decref needed */ |
| 35554 | DUK_TVAL_INCREF(thr, &h_bound->this_binding); |
| 35555 | |
| 35556 | bound_nargs = n_prevbound + nargs; |
| 35557 | if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) { |
| 35558 | DUK_DCERROR_RANGE_INVALID_COUNT(thr); |
| 35559 | } |
| 35560 | tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval)); |
| 35561 | DUK_ASSERT(tv_res != NULL || bound_nargs == 0); |
| 35562 | DUK_ASSERT(h_bound->args == NULL); |
| 35563 | DUK_ASSERT(h_bound->nargs == 0); |
| 35564 | h_bound->args = tv_res; |
| 35565 | h_bound->nargs = bound_nargs; |
| 35566 | |
| 35567 | DUK_ASSERT(n_prevbound >= 0); |
| 35568 | duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound); |
| 35569 | DUK_ASSERT(nargs >= 0); |
| 35570 | duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs); |
| 35571 | |
| 35572 | /* [ thisArg arg1 ... argN func boundFunc ] */ |
| 35573 | |
| 35574 | /* Bound function 'length' property is interesting. |
| 35575 | * For lightfuncs, simply read the virtual property. |
| 35576 | */ |
| 35577 | duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH); |
| 35578 | bound_len = duk_get_int(thr, -1); /* ES2015: no coercion */ |
| 35579 | if (bound_len < nargs) { |
| 35580 | bound_len = 0; |
| 35581 | } else { |
| 35582 | bound_len -= nargs; |
| 35583 | } |
| 35584 | if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) { |
| 35585 | bound_len = (duk_int_t) DUK_UINT32_MAX; |
| 35586 | } |
| 35587 | duk_pop(thr); |
| 35588 | DUK_ASSERT(bound_len >= 0); |
| 35589 | tv_tmp = thr->valstack_top++; |
| 35590 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp)); |
| 35591 | DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp)); |
| 35592 | DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len); /* in-place update, fastint */ |
| 35593 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */ |
| 35594 | |
| 35595 | /* XXX: could these be virtual? */ |
| 35596 | /* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */ |
| 35597 | duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER); |
| 35598 | duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS); |
| 35599 | |
| 35600 | /* Function name and fileName (non-standard). */ |
| 35601 | duk_push_literal(thr, "bound " ); /* ES2015 19.2.3.2. */ |
| 35602 | duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME); |
| 35603 | if (!duk_is_string_notsymbol(thr, -1)) { |
| 35604 | /* ES2015 has requirement to check that .name of target is a string |
| 35605 | * (also must check for Symbol); if not, targetName should be the |
| 35606 | * empty string. ES2015 19.2.3.2. |
| 35607 | */ |
| 35608 | duk_pop(thr); |
| 35609 | duk_push_hstring_empty(thr); |
| 35610 | } |
| 35611 | duk_concat(thr, 2); |
| 35612 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); |
| 35613 | #if defined(DUK_USE_FUNC_FILENAME_PROPERTY) |
| 35614 | duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME); |
| 35615 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C); |
| 35616 | #endif |
| 35617 | |
| 35618 | DUK_DDD(DUK_DDDPRINT("created bound function: %!iT" , (duk_tval *) duk_get_tval(thr, -1))); |
| 35619 | |
| 35620 | return 1; |
| 35621 | } |
| 35622 | #endif /* DUK_USE_FUNCTION_BUILTIN */ |
| 35623 | |
| 35624 | /* %NativeFunctionPrototype% .length getter. */ |
| 35625 | DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) { |
| 35626 | duk_tval *tv; |
| 35627 | duk_hnatfunc *h; |
| 35628 | duk_int16_t func_nargs; |
| 35629 | |
| 35630 | tv = duk_get_borrowed_this_tval(thr); |
| 35631 | DUK_ASSERT(tv != NULL); |
| 35632 | |
| 35633 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 35634 | h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv); |
| 35635 | DUK_ASSERT(h != NULL); |
| 35636 | if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) { |
| 35637 | goto fail_type; |
| 35638 | } |
| 35639 | func_nargs = h->nargs; |
| 35640 | duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs); |
| 35641 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { |
| 35642 | duk_small_uint_t lf_flags; |
| 35643 | duk_small_uint_t lf_len; |
| 35644 | |
| 35645 | lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); |
| 35646 | lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags); |
| 35647 | duk_push_uint(thr, lf_len); |
| 35648 | } else { |
| 35649 | goto fail_type; |
| 35650 | } |
| 35651 | return 1; |
| 35652 | |
| 35653 | fail_type: |
| 35654 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 35655 | } |
| 35656 | |
| 35657 | /* %NativeFunctionPrototype% .name getter. */ |
| 35658 | DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) { |
| 35659 | duk_tval *tv; |
| 35660 | duk_hnatfunc *h; |
| 35661 | |
| 35662 | tv = duk_get_borrowed_this_tval(thr); |
| 35663 | DUK_ASSERT(tv != NULL); |
| 35664 | |
| 35665 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 35666 | h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv); |
| 35667 | DUK_ASSERT(h != NULL); |
| 35668 | if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) { |
| 35669 | goto fail_type; |
| 35670 | } |
| 35671 | #if 0 |
| 35672 | duk_push_hnatfunc_name(thr, h); |
| 35673 | #endif |
| 35674 | duk_push_hstring_empty(thr); |
| 35675 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { |
| 35676 | duk_push_lightfunc_name(thr, tv); |
| 35677 | } else { |
| 35678 | goto fail_type; |
| 35679 | } |
| 35680 | return 1; |
| 35681 | |
| 35682 | fail_type: |
| 35683 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 35684 | } |
| 35685 | |
| 35686 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 35687 | DUK_INTERNAL duk_ret_t duk_bi_function_prototype_hasinstance(duk_hthread *thr) { |
| 35688 | /* This binding: RHS, stack index 0: LHS. */ |
| 35689 | duk_bool_t ret; |
| 35690 | |
| 35691 | ret = duk_js_instanceof_ordinary(thr, DUK_GET_TVAL_POSIDX(thr, 0), DUK_GET_THIS_TVAL_PTR(thr)); |
| 35692 | duk_push_boolean(thr, ret); |
| 35693 | return 1; |
| 35694 | } |
| 35695 | #endif /* DUK_USE_SYMBOL_BUILTIN */ |
| 35696 | #line 1 "duk_bi_global.c" |
| 35697 | /* |
| 35698 | * Global object built-ins |
| 35699 | */ |
| 35700 | |
| 35701 | /* #include duk_internal.h -> already included */ |
| 35702 | |
| 35703 | /* |
| 35704 | * Encoding/decoding helpers |
| 35705 | */ |
| 35706 | |
| 35707 | /* XXX: Could add fast path (for each transform callback) with direct byte |
| 35708 | * lookups (no shifting) and no explicit check for x < 0x80 before table |
| 35709 | * lookup. |
| 35710 | */ |
| 35711 | |
| 35712 | /* Macros for creating and checking bitmasks for character encoding. |
| 35713 | * Bit number is a bit counterintuitive, but minimizes code size. |
| 35714 | */ |
| 35715 | #define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \ |
| 35716 | ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \ |
| 35717 | ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \ |
| 35718 | )) |
| 35719 | #define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07))) |
| 35720 | |
| 35721 | /* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */ |
| 35722 | DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = { |
| 35723 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ |
| 35724 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ |
| 35725 | DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */ |
| 35726 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */ |
| 35727 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ |
| 35728 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ |
| 35729 | DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ |
| 35730 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */ |
| 35731 | }; |
| 35732 | |
| 35733 | /* E5.1 Section 15.1.3.4: uriUnescaped */ |
| 35734 | DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = { |
| 35735 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ |
| 35736 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ |
| 35737 | DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */ |
| 35738 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ |
| 35739 | DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ |
| 35740 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ |
| 35741 | DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ |
| 35742 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */ |
| 35743 | }; |
| 35744 | |
| 35745 | /* E5.1 Section 15.1.3.1: uriReserved + '#' */ |
| 35746 | DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = { |
| 35747 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ |
| 35748 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ |
| 35749 | DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */ |
| 35750 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */ |
| 35751 | DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */ |
| 35752 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */ |
| 35753 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */ |
| 35754 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */ |
| 35755 | }; |
| 35756 | |
| 35757 | /* E5.1 Section 15.1.3.2: empty */ |
| 35758 | DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = { |
| 35759 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ |
| 35760 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ |
| 35761 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */ |
| 35762 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ |
| 35763 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */ |
| 35764 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */ |
| 35765 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */ |
| 35766 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */ |
| 35767 | }; |
| 35768 | |
| 35769 | #if defined(DUK_USE_SECTION_B) |
| 35770 | /* E5.1 Section B.2.2, step 7. */ |
| 35771 | DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = { |
| 35772 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */ |
| 35773 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */ |
| 35774 | DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */ |
| 35775 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */ |
| 35776 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */ |
| 35777 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */ |
| 35778 | DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */ |
| 35779 | DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */ |
| 35780 | }; |
| 35781 | #endif /* DUK_USE_SECTION_B */ |
| 35782 | |
| 35783 | typedef struct { |
| 35784 | duk_hthread *thr; |
| 35785 | duk_hstring *h_str; |
| 35786 | duk_bufwriter_ctx bw; |
| 35787 | const duk_uint8_t *p; |
| 35788 | const duk_uint8_t *p_start; |
| 35789 | const duk_uint8_t *p_end; |
| 35790 | } duk__transform_context; |
| 35791 | |
| 35792 | typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp); |
| 35793 | |
| 35794 | /* XXX: refactor and share with other code */ |
| 35795 | DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) { |
| 35796 | duk_small_int_t ch; |
| 35797 | duk_small_int_t t = 0; |
| 35798 | |
| 35799 | while (n > 0) { |
| 35800 | t = t * 16; |
| 35801 | ch = (duk_small_int_t) duk_hex_dectab[*p++]; |
| 35802 | if (DUK_LIKELY(ch >= 0)) { |
| 35803 | t += ch; |
| 35804 | } else { |
| 35805 | return -1; |
| 35806 | } |
| 35807 | n--; |
| 35808 | } |
| 35809 | return t; |
| 35810 | } |
| 35811 | |
| 35812 | DUK_LOCAL int duk__transform_helper(duk_hthread *thr, duk__transform_callback callback, const void *udata) { |
| 35813 | duk__transform_context tfm_ctx_alloc; |
| 35814 | duk__transform_context *tfm_ctx = &tfm_ctx_alloc; |
| 35815 | duk_codepoint_t cp; |
| 35816 | |
| 35817 | tfm_ctx->thr = thr; |
| 35818 | |
| 35819 | tfm_ctx->h_str = duk_to_hstring(thr, 0); |
| 35820 | DUK_ASSERT(tfm_ctx->h_str != NULL); |
| 35821 | |
| 35822 | DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */ |
| 35823 | |
| 35824 | tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str); |
| 35825 | tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str); |
| 35826 | tfm_ctx->p = tfm_ctx->p_start; |
| 35827 | |
| 35828 | while (tfm_ctx->p < tfm_ctx->p_end) { |
| 35829 | cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end); |
| 35830 | callback(tfm_ctx, udata, cp); |
| 35831 | } |
| 35832 | |
| 35833 | DUK_BW_COMPACT(thr, &tfm_ctx->bw); |
| 35834 | |
| 35835 | (void) duk_buffer_to_string(thr, -1); /* Safe if transform is safe. */ |
| 35836 | return 1; |
| 35837 | } |
| 35838 | |
| 35839 | DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { |
| 35840 | duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH]; |
| 35841 | duk_small_int_t len; |
| 35842 | duk_codepoint_t cp1, cp2; |
| 35843 | duk_small_int_t i, t; |
| 35844 | const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata; |
| 35845 | |
| 35846 | /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes. |
| 35847 | * Codepoint range is restricted so this is a slightly too large |
| 35848 | * but doesn't matter. |
| 35849 | */ |
| 35850 | DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH); |
| 35851 | |
| 35852 | if (cp < 0) { |
| 35853 | goto uri_error; |
| 35854 | } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) { |
| 35855 | DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp); |
| 35856 | return; |
| 35857 | } else if (cp >= 0xdc00L && cp <= 0xdfffL) { |
| 35858 | goto uri_error; |
| 35859 | } else if (cp >= 0xd800L && cp <= 0xdbffL) { |
| 35860 | /* Needs lookahead */ |
| 35861 | if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) { |
| 35862 | goto uri_error; |
| 35863 | } |
| 35864 | if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) { |
| 35865 | goto uri_error; |
| 35866 | } |
| 35867 | cp1 = cp; |
| 35868 | cp = (duk_codepoint_t) (((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L); |
| 35869 | } else if (cp > 0x10ffffL) { |
| 35870 | /* Although we can allow non-BMP characters (they'll decode |
| 35871 | * back into surrogate pairs), we don't allow extended UTF-8 |
| 35872 | * characters; they would encode to URIs which won't decode |
| 35873 | * back because of strict UTF-8 checks in URI decoding. |
| 35874 | * (However, we could just as well allow them here.) |
| 35875 | */ |
| 35876 | goto uri_error; |
| 35877 | } else { |
| 35878 | /* Non-BMP characters within valid UTF-8 range: encode as is. |
| 35879 | * They'll decode back into surrogate pairs if the escaped |
| 35880 | * output is decoded. |
| 35881 | */ |
| 35882 | ; |
| 35883 | } |
| 35884 | |
| 35885 | len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf); |
| 35886 | for (i = 0; i < len; i++) { |
| 35887 | t = (duk_small_int_t) xutf8_buf[i]; |
| 35888 | DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, |
| 35889 | &tfm_ctx->bw, |
| 35890 | DUK_ASC_PERCENT, |
| 35891 | (duk_uint8_t) duk_uc_nybbles[t >> 4], |
| 35892 | (duk_uint8_t) duk_uc_nybbles[t & 0x0f]); |
| 35893 | } |
| 35894 | |
| 35895 | return; |
| 35896 | |
| 35897 | uri_error: |
| 35898 | DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); |
| 35899 | DUK_WO_NORETURN(return;); |
| 35900 | } |
| 35901 | |
| 35902 | DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { |
| 35903 | const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata; |
| 35904 | duk_small_uint_t utf8_blen; |
| 35905 | duk_codepoint_t min_cp; |
| 35906 | duk_small_int_t t; /* must be signed */ |
| 35907 | duk_small_uint_t i; |
| 35908 | |
| 35909 | /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH, |
| 35910 | * percent escape path writes max two times CESU-8 encoded BMP length. |
| 35911 | */ |
| 35912 | DUK_BW_ENSURE(tfm_ctx->thr, |
| 35913 | &tfm_ctx->bw, |
| 35914 | (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ? |
| 35915 | DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH)); |
| 35916 | |
| 35917 | if (cp == (duk_codepoint_t) '%') { |
| 35918 | const duk_uint8_t *p = tfm_ctx->p; |
| 35919 | duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */ |
| 35920 | |
| 35921 | DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld" , (long) left)); |
| 35922 | |
| 35923 | if (left < 2) { |
| 35924 | goto uri_error; |
| 35925 | } |
| 35926 | |
| 35927 | t = duk__decode_hex_escape(p, 2); |
| 35928 | DUK_DDD(DUK_DDDPRINT("first byte: %ld" , (long) t)); |
| 35929 | if (t < 0) { |
| 35930 | goto uri_error; |
| 35931 | } |
| 35932 | |
| 35933 | if (t < 0x80) { |
| 35934 | if (DUK__CHECK_BITMASK(reserved_table, t)) { |
| 35935 | /* decode '%xx' to '%xx' if decoded char in reserved set */ |
| 35936 | DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start); |
| 35937 | DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, |
| 35938 | &tfm_ctx->bw, |
| 35939 | DUK_ASC_PERCENT, |
| 35940 | p[0], |
| 35941 | p[1]); |
| 35942 | } else { |
| 35943 | DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t); |
| 35944 | } |
| 35945 | tfm_ctx->p += 2; |
| 35946 | return; |
| 35947 | } |
| 35948 | |
| 35949 | /* Decode UTF-8 codepoint from a sequence of hex escapes. The |
| 35950 | * first byte of the sequence has been decoded to 't'. |
| 35951 | * |
| 35952 | * Note that UTF-8 validation must be strict according to the |
| 35953 | * specification: E5.1 Section 15.1.3, decode algorithm step |
| 35954 | * 4.d.vii.8. URIError from non-shortest encodings is also |
| 35955 | * specifically noted in the spec. |
| 35956 | */ |
| 35957 | |
| 35958 | DUK_ASSERT(t >= 0x80); |
| 35959 | if (t < 0xc0) { |
| 35960 | /* continuation byte */ |
| 35961 | goto uri_error; |
| 35962 | } else if (t < 0xe0) { |
| 35963 | /* 110x xxxx; 2 bytes */ |
| 35964 | utf8_blen = 2; |
| 35965 | min_cp = 0x80L; |
| 35966 | cp = t & 0x1f; |
| 35967 | } else if (t < 0xf0) { |
| 35968 | /* 1110 xxxx; 3 bytes */ |
| 35969 | utf8_blen = 3; |
| 35970 | min_cp = 0x800L; |
| 35971 | cp = t & 0x0f; |
| 35972 | } else if (t < 0xf8) { |
| 35973 | /* 1111 0xxx; 4 bytes */ |
| 35974 | utf8_blen = 4; |
| 35975 | min_cp = 0x10000L; |
| 35976 | cp = t & 0x07; |
| 35977 | } else { |
| 35978 | /* extended utf-8 not allowed for URIs */ |
| 35979 | goto uri_error; |
| 35980 | } |
| 35981 | |
| 35982 | if (left < utf8_blen * 3 - 1) { |
| 35983 | /* '%xx%xx...%xx', p points to char after first '%' */ |
| 35984 | goto uri_error; |
| 35985 | } |
| 35986 | |
| 35987 | p += 3; |
| 35988 | for (i = 1; i < utf8_blen; i++) { |
| 35989 | /* p points to digit part ('%xy', p points to 'x') */ |
| 35990 | t = duk__decode_hex_escape(p, 2); |
| 35991 | DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx" , |
| 35992 | (long) i, (long) utf8_blen, (long) cp, (unsigned long) t)); |
| 35993 | if (t < 0) { |
| 35994 | goto uri_error; |
| 35995 | } |
| 35996 | if ((t & 0xc0) != 0x80) { |
| 35997 | goto uri_error; |
| 35998 | } |
| 35999 | cp = (cp << 6) + (t & 0x3f); |
| 36000 | p += 3; |
| 36001 | } |
| 36002 | p--; /* p overshoots */ |
| 36003 | tfm_ctx->p = p; |
| 36004 | |
| 36005 | DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld" , (long) cp, (long) min_cp)); |
| 36006 | |
| 36007 | if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) { |
| 36008 | goto uri_error; |
| 36009 | } |
| 36010 | |
| 36011 | /* The E5.1 algorithm checks whether or not a decoded codepoint |
| 36012 | * is below 0x80 and perhaps may be in the "reserved" set. |
| 36013 | * This seems pointless because the single byte UTF-8 case is |
| 36014 | * handled separately, and non-shortest encodings are rejected. |
| 36015 | * So, 'cp' cannot be below 0x80 here, and thus cannot be in |
| 36016 | * the reserved set. |
| 36017 | */ |
| 36018 | |
| 36019 | /* utf-8 validation ensures these */ |
| 36020 | DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL); |
| 36021 | |
| 36022 | if (cp >= 0x10000L) { |
| 36023 | cp -= 0x10000L; |
| 36024 | DUK_ASSERT(cp < 0x100000L); |
| 36025 | |
| 36026 | DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L)); |
| 36027 | DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffL) + 0xdc00L)); |
| 36028 | } else { |
| 36029 | DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); |
| 36030 | } |
| 36031 | } else { |
| 36032 | DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); |
| 36033 | } |
| 36034 | return; |
| 36035 | |
| 36036 | uri_error: |
| 36037 | DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT); |
| 36038 | DUK_WO_NORETURN(return;); |
| 36039 | } |
| 36040 | |
| 36041 | #if defined(DUK_USE_SECTION_B) |
| 36042 | DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { |
| 36043 | DUK_UNREF(udata); |
| 36044 | |
| 36045 | DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6); |
| 36046 | |
| 36047 | if (cp < 0) { |
| 36048 | goto esc_error; |
| 36049 | } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) { |
| 36050 | DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp); |
| 36051 | } else if (cp < 0x100L) { |
| 36052 | DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, |
| 36053 | &tfm_ctx->bw, |
| 36054 | (duk_uint8_t) DUK_ASC_PERCENT, |
| 36055 | (duk_uint8_t) duk_uc_nybbles[cp >> 4], |
| 36056 | (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]); |
| 36057 | } else if (cp < 0x10000L) { |
| 36058 | DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr, |
| 36059 | &tfm_ctx->bw, |
| 36060 | (duk_uint8_t) DUK_ASC_PERCENT, |
| 36061 | (duk_uint8_t) DUK_ASC_LC_U, |
| 36062 | (duk_uint8_t) duk_uc_nybbles[cp >> 12], |
| 36063 | (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f], |
| 36064 | (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f], |
| 36065 | (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]); |
| 36066 | } else { |
| 36067 | /* Characters outside BMP cannot be escape()'d. We could |
| 36068 | * encode them as surrogate pairs (for codepoints inside |
| 36069 | * valid UTF-8 range, but not extended UTF-8). Because |
| 36070 | * escape() and unescape() are legacy functions, we don't. |
| 36071 | */ |
| 36072 | goto esc_error; |
| 36073 | } |
| 36074 | |
| 36075 | return; |
| 36076 | |
| 36077 | esc_error: |
| 36078 | DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT); |
| 36079 | DUK_WO_NORETURN(return;); |
| 36080 | } |
| 36081 | |
| 36082 | DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) { |
| 36083 | duk_small_int_t t; |
| 36084 | |
| 36085 | DUK_UNREF(udata); |
| 36086 | |
| 36087 | if (cp == (duk_codepoint_t) '%') { |
| 36088 | const duk_uint8_t *p = tfm_ctx->p; |
| 36089 | duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */ |
| 36090 | |
| 36091 | if (left >= 5 && p[0] == 'u' && |
| 36092 | ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) { |
| 36093 | cp = (duk_codepoint_t) t; |
| 36094 | tfm_ctx->p += 5; |
| 36095 | } else if (left >= 2 && |
| 36096 | ((t = duk__decode_hex_escape(p, 2)) >= 0)) { |
| 36097 | cp = (duk_codepoint_t) t; |
| 36098 | tfm_ctx->p += 2; |
| 36099 | } |
| 36100 | } |
| 36101 | |
| 36102 | DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp); |
| 36103 | } |
| 36104 | #endif /* DUK_USE_SECTION_B */ |
| 36105 | |
| 36106 | /* |
| 36107 | * Eval |
| 36108 | * |
| 36109 | * Eval needs to handle both a "direct eval" and an "indirect eval". |
| 36110 | * Direct eval handling needs access to the caller's activation so that its |
| 36111 | * lexical environment can be accessed. A direct eval is only possible from |
| 36112 | * ECMAScript code; an indirect eval call is possible also from C code. |
| 36113 | * When an indirect eval call is made from C code, there may not be a |
| 36114 | * calling activation at all which needs careful handling. |
| 36115 | */ |
| 36116 | |
| 36117 | DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) { |
| 36118 | duk_hstring *h; |
| 36119 | duk_activation *act_caller; |
| 36120 | duk_activation *act_eval; |
| 36121 | duk_hcompfunc *func; |
| 36122 | duk_hobject *outer_lex_env; |
| 36123 | duk_hobject *outer_var_env; |
| 36124 | duk_bool_t this_to_global = 1; |
| 36125 | duk_small_uint_t comp_flags; |
| 36126 | duk_int_t level = -2; |
| 36127 | duk_small_uint_t call_flags; |
| 36128 | |
| 36129 | DUK_ASSERT(duk_get_top(thr) == 1 || duk_get_top(thr) == 2); /* 2 when called by debugger */ |
| 36130 | DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */ |
| 36131 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 36132 | DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */ |
| 36133 | (thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */ |
| 36134 | |
| 36135 | /* |
| 36136 | * callstack_top - 1 --> this function |
| 36137 | * callstack_top - 2 --> caller (may not exist) |
| 36138 | * |
| 36139 | * If called directly from C, callstack_top might be 1. If calling |
| 36140 | * activation doesn't exist, call must be indirect. |
| 36141 | */ |
| 36142 | |
| 36143 | h = duk_get_hstring_notsymbol(thr, 0); |
| 36144 | if (!h) { |
| 36145 | /* Symbol must be returned as is, like any non-string values. */ |
| 36146 | return 1; /* return arg as-is */ |
| 36147 | } |
| 36148 | |
| 36149 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 36150 | /* NOTE: level is used only by the debugger and should never be present |
| 36151 | * for an ECMAScript eval(). |
| 36152 | */ |
| 36153 | DUK_ASSERT(level == -2); /* by default, use caller's environment */ |
| 36154 | if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) { |
| 36155 | level = duk_get_int(thr, 1); |
| 36156 | } |
| 36157 | DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */ |
| 36158 | #endif |
| 36159 | |
| 36160 | /* [ source ] */ |
| 36161 | |
| 36162 | comp_flags = DUK_COMPILE_EVAL; |
| 36163 | act_eval = thr->callstack_curr; /* this function */ |
| 36164 | DUK_ASSERT(act_eval != NULL); |
| 36165 | act_caller = duk_hthread_get_activation_for_level(thr, level); |
| 36166 | if (act_caller != NULL) { |
| 36167 | /* Have a calling activation, check for direct eval (otherwise |
| 36168 | * assume indirect eval. |
| 36169 | */ |
| 36170 | if ((act_caller->flags & DUK_ACT_FLAG_STRICT) && |
| 36171 | (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) { |
| 36172 | /* Only direct eval inherits strictness from calling code |
| 36173 | * (E5.1 Section 10.1.1). |
| 36174 | */ |
| 36175 | comp_flags |= DUK_COMPILE_STRICT; |
| 36176 | } |
| 36177 | } else { |
| 36178 | DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0); |
| 36179 | } |
| 36180 | |
| 36181 | duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT); /* XXX: copy from caller? */ |
| 36182 | duk_js_compile(thr, |
| 36183 | (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), |
| 36184 | (duk_size_t) DUK_HSTRING_GET_BYTELEN(h), |
| 36185 | comp_flags); |
| 36186 | func = (duk_hcompfunc *) duk_known_hobject(thr, -1); |
| 36187 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func)); |
| 36188 | |
| 36189 | /* [ source template ] */ |
| 36190 | |
| 36191 | /* E5 Section 10.4.2 */ |
| 36192 | |
| 36193 | if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) { |
| 36194 | DUK_ASSERT(thr->callstack_top >= 2); |
| 36195 | DUK_ASSERT(act_caller != NULL); |
| 36196 | if (act_caller->lex_env == NULL) { |
| 36197 | DUK_ASSERT(act_caller->var_env == NULL); |
| 36198 | DUK_DDD(DUK_DDDPRINT("delayed environment initialization" )); |
| 36199 | |
| 36200 | /* this may have side effects, so re-lookup act */ |
| 36201 | duk_js_init_activation_environment_records_delayed(thr, act_caller); |
| 36202 | } |
| 36203 | DUK_ASSERT(act_caller->lex_env != NULL); |
| 36204 | DUK_ASSERT(act_caller->var_env != NULL); |
| 36205 | |
| 36206 | this_to_global = 0; |
| 36207 | |
| 36208 | if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) { |
| 36209 | duk_hdecenv *new_env; |
| 36210 | duk_hobject *act_lex_env; |
| 36211 | |
| 36212 | DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> " |
| 36213 | "var_env and lex_env to a fresh env, " |
| 36214 | "this_binding to caller's this_binding" )); |
| 36215 | |
| 36216 | act_lex_env = act_caller->lex_env; |
| 36217 | |
| 36218 | new_env = duk_hdecenv_alloc(thr, |
| 36219 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 36220 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); |
| 36221 | DUK_ASSERT(new_env != NULL); |
| 36222 | duk_push_hobject(thr, (duk_hobject *) new_env); |
| 36223 | |
| 36224 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); |
| 36225 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act_lex_env); |
| 36226 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, act_lex_env); |
| 36227 | DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO" , (duk_heaphdr *) new_env)); |
| 36228 | |
| 36229 | outer_lex_env = (duk_hobject *) new_env; |
| 36230 | outer_var_env = (duk_hobject *) new_env; |
| 36231 | |
| 36232 | duk_insert(thr, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */ |
| 36233 | |
| 36234 | /* compiler's responsibility */ |
| 36235 | DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func)); |
| 36236 | } else { |
| 36237 | DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> " |
| 36238 | "var_env and lex_env to caller's envs, " |
| 36239 | "this_binding to caller's this_binding" )); |
| 36240 | |
| 36241 | outer_lex_env = act_caller->lex_env; |
| 36242 | outer_var_env = act_caller->var_env; |
| 36243 | |
| 36244 | /* compiler's responsibility */ |
| 36245 | DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func)); |
| 36246 | } |
| 36247 | } else { |
| 36248 | DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to " |
| 36249 | "global object, this_binding to global object" )); |
| 36250 | |
| 36251 | this_to_global = 1; |
| 36252 | outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 36253 | outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 36254 | } |
| 36255 | |
| 36256 | /* Eval code doesn't need an automatic .prototype object. */ |
| 36257 | duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/); |
| 36258 | |
| 36259 | /* [ env? source template closure ] */ |
| 36260 | |
| 36261 | if (this_to_global) { |
| 36262 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 36263 | duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL); |
| 36264 | } else { |
| 36265 | duk_tval *tv; |
| 36266 | DUK_ASSERT(thr->callstack_top >= 2); |
| 36267 | DUK_ASSERT(act_caller != NULL); |
| 36268 | tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act_caller->bottom_byteoff - sizeof(duk_tval)); /* this is just beneath bottom */ |
| 36269 | DUK_ASSERT(tv >= thr->valstack); |
| 36270 | duk_push_tval(thr, tv); |
| 36271 | } |
| 36272 | |
| 36273 | DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T" , |
| 36274 | (duk_heaphdr *) outer_lex_env, |
| 36275 | (duk_heaphdr *) outer_var_env, |
| 36276 | duk_get_tval(thr, -1))); |
| 36277 | |
| 36278 | /* [ env? source template closure this ] */ |
| 36279 | |
| 36280 | call_flags = 0; |
| 36281 | if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) { |
| 36282 | /* Set DIRECT_EVAL flag for the call; it's not strictly |
| 36283 | * needed for the 'inner' eval call (the eval body) but |
| 36284 | * current new.target implementation expects to find it |
| 36285 | * so it can traverse direct eval chains up to the real |
| 36286 | * calling function. |
| 36287 | */ |
| 36288 | call_flags |= DUK_CALL_FLAG_DIRECT_EVAL; |
| 36289 | } |
| 36290 | duk_handle_call_unprotected_nargs(thr, 0, call_flags); |
| 36291 | |
| 36292 | /* [ env? source template result ] */ |
| 36293 | |
| 36294 | return 1; |
| 36295 | } |
| 36296 | |
| 36297 | /* |
| 36298 | * Parsing of ints and floats |
| 36299 | */ |
| 36300 | |
| 36301 | #if defined(DUK_USE_GLOBAL_BUILTIN) |
| 36302 | DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) { |
| 36303 | duk_int32_t radix; |
| 36304 | duk_small_uint_t s2n_flags; |
| 36305 | |
| 36306 | DUK_ASSERT_TOP(thr, 2); |
| 36307 | duk_to_string(thr, 0); /* Reject symbols. */ |
| 36308 | |
| 36309 | radix = duk_to_int32(thr, 1); |
| 36310 | |
| 36311 | /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize |
| 36312 | * ES2015 0o123 or 0b10001. |
| 36313 | */ |
| 36314 | s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | |
| 36315 | DUK_S2N_FLAG_ALLOW_GARBAGE | |
| 36316 | DUK_S2N_FLAG_ALLOW_PLUS | |
| 36317 | DUK_S2N_FLAG_ALLOW_MINUS | |
| 36318 | DUK_S2N_FLAG_ALLOW_LEADING_ZERO | |
| 36319 | DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; |
| 36320 | |
| 36321 | /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT. |
| 36322 | * |
| 36323 | * Don't autodetect octals (from leading zeroes), require user code to |
| 36324 | * provide an explicit radix 8 for parsing octal. See write-up from Mozilla: |
| 36325 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation |
| 36326 | */ |
| 36327 | |
| 36328 | if (radix != 0) { |
| 36329 | if (radix < 2 || radix > 36) { |
| 36330 | goto ret_nan; |
| 36331 | } |
| 36332 | if (radix != 16) { |
| 36333 | s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT; |
| 36334 | } |
| 36335 | } else { |
| 36336 | radix = 10; |
| 36337 | } |
| 36338 | |
| 36339 | duk_dup_0(thr); |
| 36340 | duk_numconv_parse(thr, (duk_small_int_t) radix, s2n_flags); |
| 36341 | return 1; |
| 36342 | |
| 36343 | ret_nan: |
| 36344 | duk_push_nan(thr); |
| 36345 | return 1; |
| 36346 | } |
| 36347 | #endif /* DUK_USE_GLOBAL_BUILTIN */ |
| 36348 | |
| 36349 | #if defined(DUK_USE_GLOBAL_BUILTIN) |
| 36350 | DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) { |
| 36351 | duk_small_uint_t s2n_flags; |
| 36352 | |
| 36353 | DUK_ASSERT_TOP(thr, 1); |
| 36354 | duk_to_string(thr, 0); /* Reject symbols. */ |
| 36355 | |
| 36356 | /* XXX: check flags */ |
| 36357 | s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | |
| 36358 | DUK_S2N_FLAG_ALLOW_EXP | |
| 36359 | DUK_S2N_FLAG_ALLOW_GARBAGE | |
| 36360 | DUK_S2N_FLAG_ALLOW_PLUS | |
| 36361 | DUK_S2N_FLAG_ALLOW_MINUS | |
| 36362 | DUK_S2N_FLAG_ALLOW_INF | |
| 36363 | DUK_S2N_FLAG_ALLOW_FRAC | |
| 36364 | DUK_S2N_FLAG_ALLOW_NAKED_FRAC | |
| 36365 | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | |
| 36366 | DUK_S2N_FLAG_ALLOW_LEADING_ZERO; |
| 36367 | |
| 36368 | duk_numconv_parse(thr, 10 /*radix*/, s2n_flags); |
| 36369 | return 1; |
| 36370 | } |
| 36371 | #endif /* DUK_USE_GLOBAL_BUILTIN */ |
| 36372 | |
| 36373 | /* |
| 36374 | * Number checkers |
| 36375 | */ |
| 36376 | |
| 36377 | #if defined(DUK_USE_GLOBAL_BUILTIN) |
| 36378 | DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) { |
| 36379 | duk_double_t d = duk_to_number(thr, 0); |
| 36380 | duk_push_boolean(thr, (duk_bool_t) DUK_ISNAN(d)); |
| 36381 | return 1; |
| 36382 | } |
| 36383 | #endif /* DUK_USE_GLOBAL_BUILTIN */ |
| 36384 | |
| 36385 | #if defined(DUK_USE_GLOBAL_BUILTIN) |
| 36386 | DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) { |
| 36387 | duk_double_t d = duk_to_number(thr, 0); |
| 36388 | duk_push_boolean(thr, (duk_bool_t) DUK_ISFINITE(d)); |
| 36389 | return 1; |
| 36390 | } |
| 36391 | #endif /* DUK_USE_GLOBAL_BUILTIN */ |
| 36392 | |
| 36393 | /* |
| 36394 | * URI handling |
| 36395 | */ |
| 36396 | |
| 36397 | #if defined(DUK_USE_GLOBAL_BUILTIN) |
| 36398 | DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) { |
| 36399 | return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table); |
| 36400 | } |
| 36401 | |
| 36402 | DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_hthread *thr) { |
| 36403 | return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table); |
| 36404 | } |
| 36405 | |
| 36406 | DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) { |
| 36407 | return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table); |
| 36408 | } |
| 36409 | |
| 36410 | DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_hthread *thr) { |
| 36411 | return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table); |
| 36412 | } |
| 36413 | |
| 36414 | #if defined(DUK_USE_SECTION_B) |
| 36415 | DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) { |
| 36416 | return duk__transform_helper(thr, duk__transform_callback_escape, (const void *) NULL); |
| 36417 | } |
| 36418 | |
| 36419 | DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) { |
| 36420 | return duk__transform_helper(thr, duk__transform_callback_unescape, (const void *) NULL); |
| 36421 | } |
| 36422 | #endif /* DUK_USE_SECTION_B */ |
| 36423 | #endif /* DUK_USE_GLOBAL_BUILTIN */ |
| 36424 | |
| 36425 | /* automatic undefs */ |
| 36426 | #undef DUK__CHECK_BITMASK |
| 36427 | #undef DUK__MKBITS |
| 36428 | #line 1 "duk_bi_json.c" |
| 36429 | /* |
| 36430 | * JSON built-ins. |
| 36431 | * |
| 36432 | * See doc/json.rst. |
| 36433 | * |
| 36434 | * Codepoints are handled as duk_uint_fast32_t to ensure that the full |
| 36435 | * unsigned 32-bit range is supported. This matters to e.g. JX. |
| 36436 | * |
| 36437 | * Input parsing doesn't do an explicit end-of-input check at all. This is |
| 36438 | * safe: input string data is always NUL-terminated (0x00) and valid JSON |
| 36439 | * inputs never contain plain NUL characters, so that as long as syntax checks |
| 36440 | * are correct, we'll never read past the NUL. This approach reduces code size |
| 36441 | * and improves parsing performance, but it's critical that syntax checks are |
| 36442 | * indeed correct! |
| 36443 | */ |
| 36444 | |
| 36445 | /* #include duk_internal.h -> already included */ |
| 36446 | |
| 36447 | #if defined(DUK_USE_JSON_SUPPORT) |
| 36448 | |
| 36449 | /* |
| 36450 | * Local defines and forward declarations. |
| 36451 | */ |
| 36452 | |
| 36453 | #define DUK__JSON_DECSTR_BUFSIZE 128 |
| 36454 | #define DUK__JSON_DECSTR_CHUNKSIZE 64 |
| 36455 | #define DUK__JSON_ENCSTR_CHUNKSIZE 64 |
| 36456 | #define DUK__JSON_STRINGIFY_BUFSIZE 128 |
| 36457 | #define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */ |
| 36458 | |
| 36459 | DUK_LOCAL_DECL void duk__json_dec_syntax_error(duk_json_dec_ctx *js_ctx); |
| 36460 | DUK_LOCAL_DECL void duk__json_dec_eat_white(duk_json_dec_ctx *js_ctx); |
| 36461 | #if defined(DUK_USE_JX) |
| 36462 | DUK_LOCAL_DECL duk_uint8_t duk__json_dec_peek(duk_json_dec_ctx *js_ctx); |
| 36463 | #endif |
| 36464 | DUK_LOCAL_DECL duk_uint8_t duk__json_dec_get(duk_json_dec_ctx *js_ctx); |
| 36465 | DUK_LOCAL_DECL duk_uint8_t duk__json_dec_get_nonwhite(duk_json_dec_ctx *js_ctx); |
| 36466 | DUK_LOCAL_DECL duk_uint_fast32_t duk__json_dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n); |
| 36467 | DUK_LOCAL_DECL void duk__json_dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx); |
| 36468 | DUK_LOCAL_DECL void duk__json_dec_string(duk_json_dec_ctx *js_ctx); |
| 36469 | #if defined(DUK_USE_JX) |
| 36470 | DUK_LOCAL_DECL void duk__json_dec_plain_string(duk_json_dec_ctx *js_ctx); |
| 36471 | DUK_LOCAL_DECL void duk__json_dec_pointer(duk_json_dec_ctx *js_ctx); |
| 36472 | DUK_LOCAL_DECL void duk__json_dec_buffer(duk_json_dec_ctx *js_ctx); |
| 36473 | #endif |
| 36474 | DUK_LOCAL_DECL void duk__json_dec_number(duk_json_dec_ctx *js_ctx); |
| 36475 | DUK_LOCAL_DECL void duk__json_dec_objarr_entry(duk_json_dec_ctx *js_ctx); |
| 36476 | DUK_LOCAL_DECL void duk__json_dec_objarr_exit(duk_json_dec_ctx *js_ctx); |
| 36477 | DUK_LOCAL_DECL void duk__json_dec_object(duk_json_dec_ctx *js_ctx); |
| 36478 | DUK_LOCAL_DECL void duk__json_dec_array(duk_json_dec_ctx *js_ctx); |
| 36479 | DUK_LOCAL_DECL void duk__json_dec_value(duk_json_dec_ctx *js_ctx); |
| 36480 | DUK_LOCAL_DECL void duk__json_dec_reviver_walk(duk_json_dec_ctx *js_ctx); |
| 36481 | |
| 36482 | DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch); |
| 36483 | DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2); |
| 36484 | DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx); |
| 36485 | DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h); |
| 36486 | #if defined(DUK_USE_FASTINT) |
| 36487 | DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p); |
| 36488 | #endif |
| 36489 | DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx); |
| 36490 | DUK_LOCAL_DECL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q); |
| 36491 | DUK_LOCAL_DECL void duk__json_enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k); |
| 36492 | DUK_LOCAL_DECL void duk__json_enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str); |
| 36493 | DUK_LOCAL_DECL void duk__json_enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); |
| 36494 | DUK_LOCAL_DECL void duk__json_enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top); |
| 36495 | DUK_LOCAL_DECL void duk__json_enc_object(duk_json_enc_ctx *js_ctx); |
| 36496 | DUK_LOCAL_DECL void duk__json_enc_array(duk_json_enc_ctx *js_ctx); |
| 36497 | DUK_LOCAL_DECL duk_bool_t duk__json_enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder); |
| 36498 | DUK_LOCAL_DECL duk_bool_t duk__json_enc_allow_into_proplist(duk_tval *tv); |
| 36499 | DUK_LOCAL_DECL void duk__json_enc_double(duk_json_enc_ctx *js_ctx); |
| 36500 | #if defined(DUK_USE_FASTINT) |
| 36501 | DUK_LOCAL_DECL void duk__json_enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv); |
| 36502 | #endif |
| 36503 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 36504 | DUK_LOCAL_DECL void duk__json_enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); |
| 36505 | DUK_LOCAL_DECL void duk__json_enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr); |
| 36506 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 36507 | DUK_LOCAL_DECL void duk__json_enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj); |
| 36508 | #endif |
| 36509 | #endif |
| 36510 | #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) |
| 36511 | DUK_LOCAL_DECL void duk__json_enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h); |
| 36512 | #endif |
| 36513 | DUK_LOCAL_DECL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth); |
| 36514 | |
| 36515 | /* |
| 36516 | * Helper tables |
| 36517 | */ |
| 36518 | |
| 36519 | #if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH) |
| 36520 | DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = { |
| 36521 | /* 0x00 ... 0x7f: as is |
| 36522 | * 0x80: escape generically |
| 36523 | * 0x81: slow path |
| 36524 | * 0xa0 ... 0xff: backslash + one char |
| 36525 | */ |
| 36526 | |
| 36527 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80, |
| 36528 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
| 36529 | 0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, |
| 36530 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, |
| 36531 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, |
| 36532 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f, |
| 36533 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, |
| 36534 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81, |
| 36535 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 36536 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 36537 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 36538 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 36539 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 36540 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 36541 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 36542 | 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81 |
| 36543 | }; |
| 36544 | #else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ |
| 36545 | DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = { |
| 36546 | DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, |
| 36547 | DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, |
| 36548 | DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL, |
| 36549 | DUK_ASC_LC_F, DUK_ASC_LC_R |
| 36550 | }; |
| 36551 | #endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ |
| 36552 | |
| 36553 | #if defined(DUK_USE_JSON_DECSTRING_FASTPATH) |
| 36554 | DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = { |
| 36555 | /* 0x00: slow path |
| 36556 | * other: as is |
| 36557 | */ |
| 36558 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36559 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36560 | 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, |
| 36561 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, |
| 36562 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, |
| 36563 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f, |
| 36564 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, |
| 36565 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, |
| 36566 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, |
| 36567 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, |
| 36568 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, |
| 36569 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, |
| 36570 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, |
| 36571 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, |
| 36572 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, |
| 36573 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff |
| 36574 | }; |
| 36575 | #endif /* DUK_USE_JSON_DECSTRING_FASTPATH */ |
| 36576 | |
| 36577 | #if defined(DUK_USE_JSON_EATWHITE_FASTPATH) |
| 36578 | DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = { |
| 36579 | /* 0x00: finish (non-white) |
| 36580 | * 0x01: continue |
| 36581 | */ |
| 36582 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, |
| 36583 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36584 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36585 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36586 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36587 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36588 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36589 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36590 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36591 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36592 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36593 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36594 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36595 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36596 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36597 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| 36598 | }; |
| 36599 | #endif /* DUK_USE_JSON_EATWHITE_FASTPATH */ |
| 36600 | |
| 36601 | #if defined(DUK_USE_JSON_DECNUMBER_FASTPATH) |
| 36602 | DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = { |
| 36603 | /* 0x00: finish (not part of number) |
| 36604 | * 0x01: continue |
| 36605 | */ |
| 36606 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36607 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36608 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, |
| 36609 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36610 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36611 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36612 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36613 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36614 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36615 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36616 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36617 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36618 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36619 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36620 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 36621 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
| 36622 | }; |
| 36623 | #endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */ |
| 36624 | |
| 36625 | /* |
| 36626 | * Parsing implementation. |
| 36627 | * |
| 36628 | * JSON lexer is now separate from duk_lexer.c because there are numerous |
| 36629 | * small differences making it difficult to share the lexer. |
| 36630 | * |
| 36631 | * The parser here works with raw bytes directly; this works because all |
| 36632 | * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values |
| 36633 | * inside strings will be passed on without normalization; this is not a |
| 36634 | * compliance concern because compliant inputs will always be valid |
| 36635 | * CESU-8 encodings. |
| 36636 | */ |
| 36637 | |
| 36638 | DUK_LOCAL void duk__json_dec_syntax_error(duk_json_dec_ctx *js_ctx) { |
| 36639 | /* Shared handler to minimize parser size. Cause will be |
| 36640 | * hidden, unfortunately, but we'll have an offset which |
| 36641 | * is often quite enough. |
| 36642 | */ |
| 36643 | DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON, |
| 36644 | (long) (js_ctx->p - js_ctx->p_start)); |
| 36645 | DUK_WO_NORETURN(return;); |
| 36646 | } |
| 36647 | |
| 36648 | DUK_LOCAL void duk__json_dec_eat_white(duk_json_dec_ctx *js_ctx) { |
| 36649 | const duk_uint8_t *p; |
| 36650 | duk_uint8_t t; |
| 36651 | |
| 36652 | p = js_ctx->p; |
| 36653 | for (;;) { |
| 36654 | DUK_ASSERT(p <= js_ctx->p_end); |
| 36655 | t = *p; |
| 36656 | |
| 36657 | #if defined(DUK_USE_JSON_EATWHITE_FASTPATH) |
| 36658 | /* This fast path is pretty marginal in practice. |
| 36659 | * XXX: candidate for removal. |
| 36660 | */ |
| 36661 | DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */ |
| 36662 | if (duk__json_eatwhite_lookup[t] == 0) { |
| 36663 | break; |
| 36664 | } |
| 36665 | #else /* DUK_USE_JSON_EATWHITE_FASTPATH */ |
| 36666 | if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) { |
| 36667 | /* NUL also comes here. Comparison order matters, 0x20 |
| 36668 | * is most common whitespace. |
| 36669 | */ |
| 36670 | break; |
| 36671 | } |
| 36672 | #endif /* DUK_USE_JSON_EATWHITE_FASTPATH */ |
| 36673 | p++; |
| 36674 | } |
| 36675 | js_ctx->p = p; |
| 36676 | } |
| 36677 | |
| 36678 | #if defined(DUK_USE_JX) |
| 36679 | DUK_LOCAL duk_uint8_t duk__json_dec_peek(duk_json_dec_ctx *js_ctx) { |
| 36680 | DUK_ASSERT(js_ctx->p <= js_ctx->p_end); |
| 36681 | return *js_ctx->p; |
| 36682 | } |
| 36683 | #endif |
| 36684 | |
| 36685 | DUK_LOCAL duk_uint8_t duk__json_dec_get(duk_json_dec_ctx *js_ctx) { |
| 36686 | DUK_ASSERT(js_ctx->p <= js_ctx->p_end); |
| 36687 | return *js_ctx->p++; |
| 36688 | } |
| 36689 | |
| 36690 | DUK_LOCAL duk_uint8_t duk__json_dec_get_nonwhite(duk_json_dec_ctx *js_ctx) { |
| 36691 | duk__json_dec_eat_white(js_ctx); |
| 36692 | return duk__json_dec_get(js_ctx); |
| 36693 | } |
| 36694 | |
| 36695 | /* For JX, expressing the whole unsigned 32-bit range matters. */ |
| 36696 | DUK_LOCAL duk_uint_fast32_t duk__json_dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) { |
| 36697 | duk_small_uint_t i; |
| 36698 | duk_uint_fast32_t res = 0; |
| 36699 | duk_uint8_t x; |
| 36700 | duk_small_int_t t; |
| 36701 | |
| 36702 | for (i = 0; i < n; i++) { |
| 36703 | /* XXX: share helper from lexer; duk_lexer.c / hexval(). */ |
| 36704 | |
| 36705 | x = duk__json_dec_get(js_ctx); |
| 36706 | DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld" , |
| 36707 | (long) i, (long) n, (long) res, (long) x)); |
| 36708 | |
| 36709 | /* x == 0x00 (EOF) causes syntax_error */ |
| 36710 | DUK_ASSERT(duk_hex_dectab[0] == -1); |
| 36711 | t = duk_hex_dectab[x & 0xff]; |
| 36712 | if (DUK_LIKELY(t >= 0)) { |
| 36713 | res = (res * 16) + (duk_uint_fast32_t) t; |
| 36714 | } else { |
| 36715 | /* catches EOF and invalid digits */ |
| 36716 | goto syntax_error; |
| 36717 | } |
| 36718 | } |
| 36719 | |
| 36720 | DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld" , (long) res)); |
| 36721 | return res; |
| 36722 | |
| 36723 | syntax_error: |
| 36724 | duk__json_dec_syntax_error(js_ctx); |
| 36725 | DUK_UNREACHABLE(); |
| 36726 | return 0; |
| 36727 | } |
| 36728 | |
| 36729 | DUK_LOCAL void duk__json_dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) { |
| 36730 | duk_hstring *h; |
| 36731 | const duk_uint8_t *p; |
| 36732 | duk_uint8_t x, y; |
| 36733 | |
| 36734 | /* First character has already been eaten and checked by the caller. |
| 36735 | * We can scan until a NUL in stridx string because no built-in strings |
| 36736 | * have internal NULs. |
| 36737 | */ |
| 36738 | |
| 36739 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 36740 | h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); |
| 36741 | DUK_ASSERT(h != NULL); |
| 36742 | |
| 36743 | p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1; |
| 36744 | DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */ |
| 36745 | |
| 36746 | for (;;) { |
| 36747 | x = *p; |
| 36748 | if (x == 0) { |
| 36749 | break; |
| 36750 | } |
| 36751 | y = duk__json_dec_get(js_ctx); |
| 36752 | if (x != y) { |
| 36753 | /* Catches EOF of JSON input. */ |
| 36754 | goto syntax_error; |
| 36755 | } |
| 36756 | p++; |
| 36757 | } |
| 36758 | |
| 36759 | return; |
| 36760 | |
| 36761 | syntax_error: |
| 36762 | duk__json_dec_syntax_error(js_ctx); |
| 36763 | DUK_UNREACHABLE(); |
| 36764 | } |
| 36765 | |
| 36766 | DUK_LOCAL duk_small_int_t duk__json_dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) { |
| 36767 | duk_uint_fast32_t cp; |
| 36768 | |
| 36769 | /* EOF (-1) will be cast to an unsigned value first |
| 36770 | * and then re-cast for the switch. In any case, it |
| 36771 | * will match the default case (syntax error). |
| 36772 | */ |
| 36773 | cp = (duk_uint_fast32_t) duk__json_dec_get(js_ctx); |
| 36774 | switch (cp) { |
| 36775 | case DUK_ASC_BACKSLASH: break; |
| 36776 | case DUK_ASC_DOUBLEQUOTE: break; |
| 36777 | case DUK_ASC_SLASH: break; |
| 36778 | case DUK_ASC_LC_T: cp = 0x09; break; |
| 36779 | case DUK_ASC_LC_N: cp = 0x0a; break; |
| 36780 | case DUK_ASC_LC_R: cp = 0x0d; break; |
| 36781 | case DUK_ASC_LC_F: cp = 0x0c; break; |
| 36782 | case DUK_ASC_LC_B: cp = 0x08; break; |
| 36783 | case DUK_ASC_LC_U: { |
| 36784 | cp = duk__json_dec_decode_hex_escape(js_ctx, 4); |
| 36785 | break; |
| 36786 | } |
| 36787 | #if defined(DUK_USE_JX) |
| 36788 | case DUK_ASC_UC_U: { |
| 36789 | if (js_ctx->flag_ext_custom) { |
| 36790 | cp = duk__json_dec_decode_hex_escape(js_ctx, 8); |
| 36791 | } else { |
| 36792 | return 1; /* syntax error */ |
| 36793 | } |
| 36794 | break; |
| 36795 | } |
| 36796 | case DUK_ASC_LC_X: { |
| 36797 | if (js_ctx->flag_ext_custom) { |
| 36798 | cp = duk__json_dec_decode_hex_escape(js_ctx, 2); |
| 36799 | } else { |
| 36800 | return 1; /* syntax error */ |
| 36801 | } |
| 36802 | break; |
| 36803 | } |
| 36804 | #endif /* DUK_USE_JX */ |
| 36805 | default: |
| 36806 | /* catches EOF (0x00) */ |
| 36807 | return 1; /* syntax error */ |
| 36808 | } |
| 36809 | |
| 36810 | DUK_RAW_WRITEINC_XUTF8(*ext_p, cp); |
| 36811 | |
| 36812 | return 0; |
| 36813 | } |
| 36814 | |
| 36815 | DUK_LOCAL void duk__json_dec_string(duk_json_dec_ctx *js_ctx) { |
| 36816 | duk_hthread *thr = js_ctx->thr; |
| 36817 | duk_bufwriter_ctx bw_alloc; |
| 36818 | duk_bufwriter_ctx *bw; |
| 36819 | duk_uint8_t *q; |
| 36820 | |
| 36821 | /* '"' was eaten by caller */ |
| 36822 | |
| 36823 | /* Note that we currently parse -bytes-, not codepoints. |
| 36824 | * All non-ASCII extended UTF-8 will encode to bytes >= 0x80, |
| 36825 | * so they'll simply pass through (valid UTF-8 or not). |
| 36826 | */ |
| 36827 | |
| 36828 | bw = &bw_alloc; |
| 36829 | DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE); |
| 36830 | q = DUK_BW_GET_PTR(js_ctx->thr, bw); |
| 36831 | |
| 36832 | #if defined(DUK_USE_JSON_DECSTRING_FASTPATH) |
| 36833 | for (;;) { |
| 36834 | duk_small_uint_t safe; |
| 36835 | duk_uint8_t b, x; |
| 36836 | const duk_uint8_t *p; |
| 36837 | |
| 36838 | /* Select a safe loop count where no output checks are |
| 36839 | * needed assuming we won't encounter escapes. Input |
| 36840 | * bound checks are not necessary as a NUL (guaranteed) |
| 36841 | * will cause a SyntaxError before we read out of bounds. |
| 36842 | */ |
| 36843 | |
| 36844 | safe = DUK__JSON_DECSTR_CHUNKSIZE; |
| 36845 | |
| 36846 | /* Ensure space for 1:1 output plus one escape. */ |
| 36847 | q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q); |
| 36848 | |
| 36849 | p = js_ctx->p; /* temp copy, write back for next loop */ |
| 36850 | for (;;) { |
| 36851 | if (safe == 0) { |
| 36852 | js_ctx->p = p; |
| 36853 | break; |
| 36854 | } |
| 36855 | safe--; |
| 36856 | |
| 36857 | /* End of input (NUL) goes through slow path and causes SyntaxError. */ |
| 36858 | DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00); |
| 36859 | |
| 36860 | b = *p++; |
| 36861 | x = (duk_small_int_t) duk__json_decstr_lookup[b]; |
| 36862 | if (DUK_LIKELY(x != 0)) { |
| 36863 | /* Fast path, decode as is. */ |
| 36864 | *q++ = b; |
| 36865 | } else if (b == DUK_ASC_DOUBLEQUOTE) { |
| 36866 | js_ctx->p = p; |
| 36867 | goto found_quote; |
| 36868 | } else if (b == DUK_ASC_BACKSLASH) { |
| 36869 | /* We've ensured space for one escaped input; then |
| 36870 | * bail out and recheck (this makes escape handling |
| 36871 | * quite slow but it's uncommon). |
| 36872 | */ |
| 36873 | js_ctx->p = p; |
| 36874 | if (duk__json_dec_string_escape(js_ctx, &q) != 0) { |
| 36875 | goto syntax_error; |
| 36876 | } |
| 36877 | break; |
| 36878 | } else { |
| 36879 | js_ctx->p = p; |
| 36880 | goto syntax_error; |
| 36881 | } |
| 36882 | } |
| 36883 | } |
| 36884 | found_quote: |
| 36885 | #else /* DUK_USE_JSON_DECSTRING_FASTPATH */ |
| 36886 | for (;;) { |
| 36887 | duk_uint8_t x; |
| 36888 | |
| 36889 | q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q); |
| 36890 | |
| 36891 | x = duk__json_dec_get(js_ctx); |
| 36892 | |
| 36893 | if (x == DUK_ASC_DOUBLEQUOTE) { |
| 36894 | break; |
| 36895 | } else if (x == DUK_ASC_BACKSLASH) { |
| 36896 | if (duk__json_dec_string_escape(js_ctx, &q) != 0) { |
| 36897 | goto syntax_error; |
| 36898 | } |
| 36899 | } else if (x < 0x20) { |
| 36900 | /* catches EOF (NUL) */ |
| 36901 | goto syntax_error; |
| 36902 | } else { |
| 36903 | *q++ = (duk_uint8_t) x; |
| 36904 | } |
| 36905 | } |
| 36906 | #endif /* DUK_USE_JSON_DECSTRING_FASTPATH */ |
| 36907 | |
| 36908 | DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q); |
| 36909 | (void) duk_buffer_to_string(thr, -1); /* Safe if input string is safe. */ |
| 36910 | |
| 36911 | /* [ ... str ] */ |
| 36912 | |
| 36913 | return; |
| 36914 | |
| 36915 | syntax_error: |
| 36916 | duk__json_dec_syntax_error(js_ctx); |
| 36917 | DUK_UNREACHABLE(); |
| 36918 | } |
| 36919 | |
| 36920 | #if defined(DUK_USE_JX) |
| 36921 | /* Decode a plain string consisting entirely of identifier characters. |
| 36922 | * Used to parse plain keys (e.g. "foo: 123"). |
| 36923 | */ |
| 36924 | DUK_LOCAL void duk__json_dec_plain_string(duk_json_dec_ctx *js_ctx) { |
| 36925 | duk_hthread *thr = js_ctx->thr; |
| 36926 | const duk_uint8_t *p; |
| 36927 | duk_small_int_t x; |
| 36928 | |
| 36929 | /* Caller has already eaten the first char so backtrack one byte. */ |
| 36930 | |
| 36931 | js_ctx->p--; /* safe */ |
| 36932 | p = js_ctx->p; |
| 36933 | |
| 36934 | /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of |
| 36935 | * parsing (which is correct except if there are non-shortest encodings). |
| 36936 | * There is also no need to check explicitly for end of input buffer as |
| 36937 | * the input is NUL padded and NUL will exit the parsing loop. |
| 36938 | * |
| 36939 | * Because no unescaping takes place, we can just scan to the end of the |
| 36940 | * plain string and intern from the input buffer. |
| 36941 | */ |
| 36942 | |
| 36943 | for (;;) { |
| 36944 | x = *p; |
| 36945 | |
| 36946 | /* There is no need to check the first character specially here |
| 36947 | * (i.e. reject digits): the caller only accepts valid initial |
| 36948 | * characters and won't call us if the first character is a digit. |
| 36949 | * This also ensures that the plain string won't be empty. |
| 36950 | */ |
| 36951 | |
| 36952 | if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) { |
| 36953 | break; |
| 36954 | } |
| 36955 | p++; |
| 36956 | } |
| 36957 | |
| 36958 | duk_push_lstring(thr, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p)); |
| 36959 | js_ctx->p = p; |
| 36960 | |
| 36961 | /* [ ... str ] */ |
| 36962 | } |
| 36963 | #endif /* DUK_USE_JX */ |
| 36964 | |
| 36965 | #if defined(DUK_USE_JX) |
| 36966 | DUK_LOCAL void duk__json_dec_pointer(duk_json_dec_ctx *js_ctx) { |
| 36967 | duk_hthread *thr = js_ctx->thr; |
| 36968 | const duk_uint8_t *p; |
| 36969 | duk_small_int_t x; |
| 36970 | void *voidptr; |
| 36971 | |
| 36972 | /* Caller has already eaten the first character ('(') which we don't need. */ |
| 36973 | |
| 36974 | p = js_ctx->p; |
| 36975 | |
| 36976 | for (;;) { |
| 36977 | x = *p; |
| 36978 | |
| 36979 | /* Assume that the native representation never contains a closing |
| 36980 | * parenthesis. |
| 36981 | */ |
| 36982 | |
| 36983 | if (x == DUK_ASC_RPAREN) { |
| 36984 | break; |
| 36985 | } else if (x <= 0) { |
| 36986 | /* NUL term or -1 (EOF), NUL check would suffice */ |
| 36987 | goto syntax_error; |
| 36988 | } |
| 36989 | p++; |
| 36990 | } |
| 36991 | |
| 36992 | /* There is no need to NUL delimit the sscanf() call: trailing garbage is |
| 36993 | * ignored and there is always a NUL terminator which will force an error |
| 36994 | * if no error is encountered before it. It's possible that the scan |
| 36995 | * would scan further than between [js_ctx->p,p[ though and we'd advance |
| 36996 | * by less than the scanned value. |
| 36997 | * |
| 36998 | * Because pointers are platform specific, a failure to scan a pointer |
| 36999 | * results in a null pointer which is a better placeholder than a missing |
| 37000 | * value or an error. |
| 37001 | */ |
| 37002 | |
| 37003 | voidptr = NULL; |
| 37004 | (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr); |
| 37005 | duk_push_pointer(thr, voidptr); |
| 37006 | js_ctx->p = p + 1; /* skip ')' */ |
| 37007 | |
| 37008 | /* [ ... ptr ] */ |
| 37009 | |
| 37010 | return; |
| 37011 | |
| 37012 | syntax_error: |
| 37013 | duk__json_dec_syntax_error(js_ctx); |
| 37014 | DUK_UNREACHABLE(); |
| 37015 | } |
| 37016 | #endif /* DUK_USE_JX */ |
| 37017 | |
| 37018 | #if defined(DUK_USE_JX) |
| 37019 | DUK_LOCAL void duk__json_dec_buffer(duk_json_dec_ctx *js_ctx) { |
| 37020 | duk_hthread *thr = js_ctx->thr; |
| 37021 | const duk_uint8_t *p; |
| 37022 | duk_uint8_t *buf; |
| 37023 | duk_size_t src_len; |
| 37024 | duk_small_int_t x; |
| 37025 | |
| 37026 | /* Caller has already eaten the first character ('|') which we don't need. */ |
| 37027 | |
| 37028 | p = js_ctx->p; |
| 37029 | |
| 37030 | /* XXX: Would be nice to share the fast path loop from duk_hex_decode() |
| 37031 | * and avoid creating a temporary buffer. However, there are some |
| 37032 | * differences which prevent trivial sharing: |
| 37033 | * |
| 37034 | * - Pipe char detection |
| 37035 | * - EOF detection |
| 37036 | * - Unknown length of input and output |
| 37037 | * |
| 37038 | * The best approach here would be a bufwriter and a reasonaly sized |
| 37039 | * safe inner loop (e.g. 64 output bytes at a time). |
| 37040 | */ |
| 37041 | |
| 37042 | for (;;) { |
| 37043 | x = *p; |
| 37044 | |
| 37045 | /* This loop intentionally does not ensure characters are valid |
| 37046 | * ([0-9a-fA-F]) because the hex decode call below will do that. |
| 37047 | */ |
| 37048 | if (x == DUK_ASC_PIPE) { |
| 37049 | break; |
| 37050 | } else if (x <= 0) { |
| 37051 | /* NUL term or -1 (EOF), NUL check would suffice */ |
| 37052 | goto syntax_error; |
| 37053 | } |
| 37054 | p++; |
| 37055 | } |
| 37056 | |
| 37057 | /* XXX: this is not very nice; unnecessary copy is made. */ |
| 37058 | src_len = (duk_size_t) (p - js_ctx->p); |
| 37059 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len); |
| 37060 | DUK_ASSERT(buf != NULL); |
| 37061 | duk_memcpy((void *) buf, (const void *) js_ctx->p, src_len); |
| 37062 | duk_hex_decode(thr, -1); |
| 37063 | |
| 37064 | js_ctx->p = p + 1; /* skip '|' */ |
| 37065 | |
| 37066 | /* [ ... buf ] */ |
| 37067 | |
| 37068 | return; |
| 37069 | |
| 37070 | syntax_error: |
| 37071 | duk__json_dec_syntax_error(js_ctx); |
| 37072 | DUK_UNREACHABLE(); |
| 37073 | } |
| 37074 | #endif /* DUK_USE_JX */ |
| 37075 | |
| 37076 | /* Parse a number, other than NaN or +/- Infinity */ |
| 37077 | DUK_LOCAL void duk__json_dec_number(duk_json_dec_ctx *js_ctx) { |
| 37078 | duk_hthread *thr = js_ctx->thr; |
| 37079 | const duk_uint8_t *p_start; |
| 37080 | const duk_uint8_t *p; |
| 37081 | duk_uint8_t x; |
| 37082 | duk_small_uint_t s2n_flags; |
| 37083 | |
| 37084 | DUK_DDD(DUK_DDDPRINT("parse_number" )); |
| 37085 | |
| 37086 | p_start = js_ctx->p; |
| 37087 | |
| 37088 | /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a |
| 37089 | * string for strict number parsing. |
| 37090 | */ |
| 37091 | |
| 37092 | p = js_ctx->p; |
| 37093 | for (;;) { |
| 37094 | x = *p; |
| 37095 | |
| 37096 | DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld" , |
| 37097 | (const void *) p_start, (const void *) p, |
| 37098 | (const void *) js_ctx->p_end, (long) x)); |
| 37099 | |
| 37100 | #if defined(DUK_USE_JSON_DECNUMBER_FASTPATH) |
| 37101 | /* This fast path is pretty marginal in practice. |
| 37102 | * XXX: candidate for removal. |
| 37103 | */ |
| 37104 | DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */ |
| 37105 | if (duk__json_decnumber_lookup[x] == 0) { |
| 37106 | break; |
| 37107 | } |
| 37108 | #else /* DUK_USE_JSON_DECNUMBER_FASTPATH */ |
| 37109 | if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) || |
| 37110 | (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E || |
| 37111 | x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) { |
| 37112 | /* Plus sign must be accepted for positive exponents |
| 37113 | * (e.g. '1.5e+2'). This clause catches NULs. |
| 37114 | */ |
| 37115 | break; |
| 37116 | } |
| 37117 | #endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */ |
| 37118 | p++; /* safe, because matched (NUL causes a break) */ |
| 37119 | } |
| 37120 | js_ctx->p = p; |
| 37121 | |
| 37122 | DUK_ASSERT(js_ctx->p > p_start); |
| 37123 | duk_push_lstring(thr, (const char *) p_start, (duk_size_t) (p - p_start)); |
| 37124 | |
| 37125 | s2n_flags = DUK_S2N_FLAG_ALLOW_EXP | |
| 37126 | DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */ |
| 37127 | DUK_S2N_FLAG_ALLOW_FRAC; |
| 37128 | |
| 37129 | DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T" , |
| 37130 | (duk_tval *) duk_get_tval(thr, -1))); |
| 37131 | duk_numconv_parse(thr, 10 /*radix*/, s2n_flags); |
| 37132 | if (duk_is_nan(thr, -1)) { |
| 37133 | duk__json_dec_syntax_error(js_ctx); |
| 37134 | } |
| 37135 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 37136 | DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T" , |
| 37137 | (duk_tval *) duk_get_tval(thr, -1))); |
| 37138 | |
| 37139 | /* [ ... num ] */ |
| 37140 | } |
| 37141 | |
| 37142 | DUK_LOCAL void duk__json_dec_objarr_entry(duk_json_dec_ctx *js_ctx) { |
| 37143 | duk_hthread *thr = js_ctx->thr; |
| 37144 | duk_require_stack(thr, DUK_JSON_DEC_REQSTACK); |
| 37145 | |
| 37146 | /* c recursion check */ |
| 37147 | |
| 37148 | duk_native_stack_check(thr); |
| 37149 | |
| 37150 | DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */ |
| 37151 | DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); |
| 37152 | if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { |
| 37153 | DUK_ERROR_RANGE(thr, DUK_STR_DEC_RECLIMIT); |
| 37154 | DUK_WO_NORETURN(return;); |
| 37155 | } |
| 37156 | js_ctx->recursion_depth++; |
| 37157 | } |
| 37158 | |
| 37159 | DUK_LOCAL void duk__json_dec_objarr_exit(duk_json_dec_ctx *js_ctx) { |
| 37160 | /* c recursion check */ |
| 37161 | |
| 37162 | DUK_ASSERT(js_ctx->recursion_depth > 0); |
| 37163 | DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); |
| 37164 | js_ctx->recursion_depth--; |
| 37165 | } |
| 37166 | |
| 37167 | DUK_LOCAL void duk__json_dec_object(duk_json_dec_ctx *js_ctx) { |
| 37168 | duk_hthread *thr = js_ctx->thr; |
| 37169 | duk_int_t key_count; /* XXX: a "first" flag would suffice */ |
| 37170 | duk_uint8_t x; |
| 37171 | |
| 37172 | DUK_DDD(DUK_DDDPRINT("parse_object" )); |
| 37173 | |
| 37174 | duk__json_dec_objarr_entry(js_ctx); |
| 37175 | |
| 37176 | duk_push_object(thr); |
| 37177 | |
| 37178 | /* Initial '{' has been checked and eaten by caller. */ |
| 37179 | |
| 37180 | key_count = 0; |
| 37181 | for (;;) { |
| 37182 | x = duk__json_dec_get_nonwhite(js_ctx); |
| 37183 | |
| 37184 | DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld" , |
| 37185 | (duk_tval *) duk_get_tval(thr, -1), |
| 37186 | (long) x, (long) key_count)); |
| 37187 | |
| 37188 | /* handle comma and closing brace */ |
| 37189 | |
| 37190 | if (x == DUK_ASC_COMMA && key_count > 0) { |
| 37191 | /* accept comma, expect new value */ |
| 37192 | x = duk__json_dec_get_nonwhite(js_ctx); |
| 37193 | } else if (x == DUK_ASC_RCURLY) { |
| 37194 | /* eat closing brace */ |
| 37195 | break; |
| 37196 | } else if (key_count == 0) { |
| 37197 | /* accept anything, expect first value (EOF will be |
| 37198 | * caught by key parsing below. |
| 37199 | */ |
| 37200 | ; |
| 37201 | } else { |
| 37202 | /* catches EOF (NUL) and initial comma */ |
| 37203 | goto syntax_error; |
| 37204 | } |
| 37205 | |
| 37206 | /* parse key and value */ |
| 37207 | |
| 37208 | if (x == DUK_ASC_DOUBLEQUOTE) { |
| 37209 | duk__json_dec_string(js_ctx); |
| 37210 | #if defined(DUK_USE_JX) |
| 37211 | } else if (js_ctx->flag_ext_custom && |
| 37212 | duk_unicode_is_identifier_start((duk_codepoint_t) x)) { |
| 37213 | duk__json_dec_plain_string(js_ctx); |
| 37214 | #endif |
| 37215 | } else { |
| 37216 | goto syntax_error; |
| 37217 | } |
| 37218 | |
| 37219 | /* [ ... obj key ] */ |
| 37220 | |
| 37221 | x = duk__json_dec_get_nonwhite(js_ctx); |
| 37222 | if (x != DUK_ASC_COLON) { |
| 37223 | goto syntax_error; |
| 37224 | } |
| 37225 | |
| 37226 | duk__json_dec_value(js_ctx); |
| 37227 | |
| 37228 | /* [ ... obj key val ] */ |
| 37229 | |
| 37230 | duk_xdef_prop_wec(thr, -3); |
| 37231 | |
| 37232 | /* [ ... obj ] */ |
| 37233 | |
| 37234 | key_count++; |
| 37235 | } |
| 37236 | |
| 37237 | /* [ ... obj ] */ |
| 37238 | |
| 37239 | DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T" , |
| 37240 | (duk_tval *) duk_get_tval(thr, -1))); |
| 37241 | |
| 37242 | duk__json_dec_objarr_exit(js_ctx); |
| 37243 | return; |
| 37244 | |
| 37245 | syntax_error: |
| 37246 | duk__json_dec_syntax_error(js_ctx); |
| 37247 | DUK_UNREACHABLE(); |
| 37248 | } |
| 37249 | |
| 37250 | DUK_LOCAL void duk__json_dec_array(duk_json_dec_ctx *js_ctx) { |
| 37251 | duk_hthread *thr = js_ctx->thr; |
| 37252 | duk_uarridx_t arr_idx; |
| 37253 | duk_uint8_t x; |
| 37254 | |
| 37255 | DUK_DDD(DUK_DDDPRINT("parse_array" )); |
| 37256 | |
| 37257 | duk__json_dec_objarr_entry(js_ctx); |
| 37258 | |
| 37259 | duk_push_array(thr); |
| 37260 | |
| 37261 | /* Initial '[' has been checked and eaten by caller. */ |
| 37262 | |
| 37263 | arr_idx = 0; |
| 37264 | for (;;) { |
| 37265 | x = duk__json_dec_get_nonwhite(js_ctx); |
| 37266 | |
| 37267 | DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld" , |
| 37268 | (duk_tval *) duk_get_tval(thr, -1), |
| 37269 | (long) x, (long) arr_idx)); |
| 37270 | |
| 37271 | /* handle comma and closing bracket */ |
| 37272 | |
| 37273 | if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) { |
| 37274 | /* accept comma, expect new value */ |
| 37275 | ; |
| 37276 | } else if (x == DUK_ASC_RBRACKET) { |
| 37277 | /* eat closing bracket */ |
| 37278 | break; |
| 37279 | } else if (arr_idx == 0) { |
| 37280 | /* accept anything, expect first value (EOF will be |
| 37281 | * caught by duk__json_dec_value() below. |
| 37282 | */ |
| 37283 | js_ctx->p--; /* backtrack (safe) */ |
| 37284 | } else { |
| 37285 | /* catches EOF (NUL) and initial comma */ |
| 37286 | goto syntax_error; |
| 37287 | } |
| 37288 | |
| 37289 | /* parse value */ |
| 37290 | |
| 37291 | duk__json_dec_value(js_ctx); |
| 37292 | |
| 37293 | /* [ ... arr val ] */ |
| 37294 | |
| 37295 | duk_xdef_prop_index_wec(thr, -2, arr_idx); |
| 37296 | arr_idx++; |
| 37297 | } |
| 37298 | |
| 37299 | /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to |
| 37300 | * set the values. |
| 37301 | */ |
| 37302 | |
| 37303 | duk_set_length(thr, -1, arr_idx); |
| 37304 | |
| 37305 | /* [ ... arr ] */ |
| 37306 | |
| 37307 | DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T" , |
| 37308 | (duk_tval *) duk_get_tval(thr, -1))); |
| 37309 | |
| 37310 | duk__json_dec_objarr_exit(js_ctx); |
| 37311 | return; |
| 37312 | |
| 37313 | syntax_error: |
| 37314 | duk__json_dec_syntax_error(js_ctx); |
| 37315 | DUK_UNREACHABLE(); |
| 37316 | } |
| 37317 | |
| 37318 | DUK_LOCAL void duk__json_dec_value(duk_json_dec_ctx *js_ctx) { |
| 37319 | duk_hthread *thr = js_ctx->thr; |
| 37320 | duk_uint8_t x; |
| 37321 | |
| 37322 | x = duk__json_dec_get_nonwhite(js_ctx); |
| 37323 | |
| 37324 | DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld" , (long) x)); |
| 37325 | |
| 37326 | /* Note: duk__json_dec_req_stridx() backtracks one char */ |
| 37327 | |
| 37328 | if (x == DUK_ASC_DOUBLEQUOTE) { |
| 37329 | duk__json_dec_string(js_ctx); |
| 37330 | } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) { |
| 37331 | #if defined(DUK_USE_JX) |
| 37332 | if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__json_dec_peek(js_ctx) == DUK_ASC_UC_I) { |
| 37333 | duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */ |
| 37334 | duk_push_number(thr, -DUK_DOUBLE_INFINITY); |
| 37335 | } else { |
| 37336 | #else |
| 37337 | { /* unconditional block */ |
| 37338 | #endif |
| 37339 | /* We already ate 'x', so backup one byte. */ |
| 37340 | js_ctx->p--; /* safe */ |
| 37341 | duk__json_dec_number(js_ctx); |
| 37342 | } |
| 37343 | } else if (x == DUK_ASC_LC_T) { |
| 37344 | duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_TRUE); |
| 37345 | duk_push_true(thr); |
| 37346 | } else if (x == DUK_ASC_LC_F) { |
| 37347 | duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_FALSE); |
| 37348 | duk_push_false(thr); |
| 37349 | } else if (x == DUK_ASC_LC_N) { |
| 37350 | duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL); |
| 37351 | duk_push_null(thr); |
| 37352 | #if defined(DUK_USE_JX) |
| 37353 | } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) { |
| 37354 | duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED); |
| 37355 | duk_push_undefined(thr); |
| 37356 | } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) { |
| 37357 | duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_NAN); |
| 37358 | duk_push_nan(thr); |
| 37359 | } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) { |
| 37360 | duk__json_dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY); |
| 37361 | duk_push_number(thr, DUK_DOUBLE_INFINITY); |
| 37362 | } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) { |
| 37363 | duk__json_dec_pointer(js_ctx); |
| 37364 | } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) { |
| 37365 | duk__json_dec_buffer(js_ctx); |
| 37366 | #endif |
| 37367 | } else if (x == DUK_ASC_LCURLY) { |
| 37368 | duk__json_dec_object(js_ctx); |
| 37369 | } else if (x == DUK_ASC_LBRACKET) { |
| 37370 | duk__json_dec_array(js_ctx); |
| 37371 | } else { |
| 37372 | /* catches EOF (NUL) */ |
| 37373 | goto syntax_error; |
| 37374 | } |
| 37375 | |
| 37376 | duk__json_dec_eat_white(js_ctx); |
| 37377 | |
| 37378 | /* [ ... val ] */ |
| 37379 | return; |
| 37380 | |
| 37381 | syntax_error: |
| 37382 | duk__json_dec_syntax_error(js_ctx); |
| 37383 | DUK_UNREACHABLE(); |
| 37384 | } |
| 37385 | |
| 37386 | /* Recursive value reviver, implements the Walk() algorithm. The parsing |
| 37387 | * step ensures there is a reasonable depth limit to the input. However, |
| 37388 | * the reviver may create more depth by editing object or array entries, so |
| 37389 | * we have both C recursion limit and native stack checks here. |
| 37390 | */ |
| 37391 | DUK_LOCAL void duk__json_dec_reviver_walk(duk_json_dec_ctx *js_ctx) { |
| 37392 | duk_hthread *thr = js_ctx->thr; |
| 37393 | duk_hobject *h; |
| 37394 | duk_uarridx_t i, arr_len; |
| 37395 | |
| 37396 | duk__json_dec_objarr_entry(js_ctx); |
| 37397 | |
| 37398 | DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T" , |
| 37399 | (long) duk_get_top(thr), |
| 37400 | (duk_tval *) duk_get_tval(thr, -2), |
| 37401 | (duk_tval *) duk_get_tval(thr, -1))); |
| 37402 | |
| 37403 | duk_dup_top(thr); |
| 37404 | duk_get_prop(thr, -3); /* -> [ ... holder name val ] */ |
| 37405 | |
| 37406 | h = duk_get_hobject(thr, -1); |
| 37407 | if (h != NULL) { |
| 37408 | if (duk_js_isarray_hobject(h)) { |
| 37409 | arr_len = (duk_uarridx_t) duk_get_length(thr, -1); |
| 37410 | for (i = 0; i < arr_len; i++) { |
| 37411 | /* [ ... holder name val ] */ |
| 37412 | |
| 37413 | DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T" , |
| 37414 | (long) duk_get_top(thr), (long) i, (long) arr_len, |
| 37415 | (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2), |
| 37416 | (duk_tval *) duk_get_tval(thr, -1))); |
| 37417 | |
| 37418 | duk_dup_top(thr); |
| 37419 | (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */ |
| 37420 | duk__json_dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */ |
| 37421 | |
| 37422 | if (duk_is_undefined(thr, -1)) { |
| 37423 | duk_pop(thr); |
| 37424 | duk_del_prop_index(thr, -1, i); |
| 37425 | } else { |
| 37426 | /* XXX: duk_xdef_prop_index_wec() would be more appropriate |
| 37427 | * here but it currently makes some assumptions that might |
| 37428 | * not hold (e.g. that previous property is not an accessor). |
| 37429 | */ |
| 37430 | duk_put_prop_index(thr, -2, i); |
| 37431 | } |
| 37432 | } |
| 37433 | } else { |
| 37434 | /* [ ... holder name val ] */ |
| 37435 | duk_enum(thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); |
| 37436 | while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) { |
| 37437 | DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T" , |
| 37438 | (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -5), |
| 37439 | (duk_tval *) duk_get_tval(thr, -4), (duk_tval *) duk_get_tval(thr, -3), |
| 37440 | (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); |
| 37441 | |
| 37442 | /* [ ... holder name val enum obj_key ] */ |
| 37443 | duk_dup_m3(thr); |
| 37444 | duk_dup_m2(thr); |
| 37445 | |
| 37446 | /* [ ... holder name val enum obj_key val obj_key ] */ |
| 37447 | duk__json_dec_reviver_walk(js_ctx); |
| 37448 | |
| 37449 | /* [ ... holder name val enum obj_key new_elem ] */ |
| 37450 | if (duk_is_undefined(thr, -1)) { |
| 37451 | duk_pop(thr); |
| 37452 | duk_del_prop(thr, -3); |
| 37453 | } else { |
| 37454 | /* XXX: duk_xdef_prop_index_wec() would be more appropriate |
| 37455 | * here but it currently makes some assumptions that might |
| 37456 | * not hold (e.g. that previous property is not an accessor). |
| 37457 | * |
| 37458 | * Using duk_put_prop() works incorrectly with '__proto__' |
| 37459 | * if the own property with that name has been deleted. This |
| 37460 | * does not happen normally, but a clever reviver can trigger |
| 37461 | * that, see complex reviver case in: test-bug-json-parse-__proto__.js. |
| 37462 | */ |
| 37463 | duk_put_prop(thr, -4); |
| 37464 | } |
| 37465 | } |
| 37466 | duk_pop(thr); /* pop enum */ |
| 37467 | } |
| 37468 | } |
| 37469 | |
| 37470 | /* [ ... holder name val ] */ |
| 37471 | |
| 37472 | duk_dup(thr, js_ctx->idx_reviver); |
| 37473 | duk_insert(thr, -4); /* -> [ ... reviver holder name val ] */ |
| 37474 | duk_call_method(thr, 2); /* -> [ ... res ] */ |
| 37475 | |
| 37476 | duk__json_dec_objarr_exit(js_ctx); |
| 37477 | |
| 37478 | DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T" , |
| 37479 | (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1))); |
| 37480 | } |
| 37481 | |
| 37482 | /* |
| 37483 | * Stringify implementation. |
| 37484 | */ |
| 37485 | |
| 37486 | #define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch)) |
| 37487 | #define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2)) |
| 37488 | #define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h)) |
| 37489 | #if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 37490 | #define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p)) |
| 37491 | #endif |
| 37492 | #define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i)) |
| 37493 | #define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx)) |
| 37494 | |
| 37495 | DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) { |
| 37496 | DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch); |
| 37497 | } |
| 37498 | |
| 37499 | DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) { |
| 37500 | DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2); |
| 37501 | } |
| 37502 | |
| 37503 | DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) { |
| 37504 | DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h); |
| 37505 | } |
| 37506 | |
| 37507 | #if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 37508 | DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) { |
| 37509 | DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str); |
| 37510 | } |
| 37511 | #endif |
| 37512 | |
| 37513 | DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) { |
| 37514 | duk_hstring *h; |
| 37515 | |
| 37516 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 37517 | h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx); |
| 37518 | DUK_ASSERT(h != NULL); |
| 37519 | |
| 37520 | DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h); |
| 37521 | } |
| 37522 | |
| 37523 | DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) { |
| 37524 | DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1); |
| 37525 | DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1); |
| 37526 | } |
| 37527 | |
| 37528 | #define DUK__MKESC(nybbles,esc1,esc2) \ |
| 37529 | (((duk_uint_fast32_t) (nybbles)) << 16) | \ |
| 37530 | (((duk_uint_fast32_t) (esc1)) << 8) | \ |
| 37531 | ((duk_uint_fast32_t) (esc2)) |
| 37532 | |
| 37533 | DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) { |
| 37534 | duk_uint_fast32_t tmp; |
| 37535 | duk_small_uint_t dig; |
| 37536 | |
| 37537 | DUK_UNREF(js_ctx); |
| 37538 | |
| 37539 | /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */ |
| 37540 | |
| 37541 | /* Select appropriate escape format automatically, and set 'tmp' to a |
| 37542 | * value encoding both the escape format character and the nybble count: |
| 37543 | * |
| 37544 | * (nybble_count << 16) | (escape_char1) | (escape_char2) |
| 37545 | */ |
| 37546 | |
| 37547 | #if defined(DUK_USE_JX) |
| 37548 | if (DUK_LIKELY(cp < 0x100UL)) { |
| 37549 | if (DUK_UNLIKELY(js_ctx->flag_ext_custom != 0U)) { |
| 37550 | tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X); |
| 37551 | } else { |
| 37552 | tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U); |
| 37553 | } |
| 37554 | } else |
| 37555 | #endif |
| 37556 | if (DUK_LIKELY(cp < 0x10000UL)) { |
| 37557 | tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U); |
| 37558 | } else { |
| 37559 | #if defined(DUK_USE_JX) |
| 37560 | if (DUK_LIKELY(js_ctx->flag_ext_custom != 0U)) { |
| 37561 | tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U); |
| 37562 | } else |
| 37563 | #endif |
| 37564 | { |
| 37565 | /* In compatible mode and standard JSON mode, output |
| 37566 | * something useful for non-BMP characters. This won't |
| 37567 | * roundtrip but will still be more or less readable and |
| 37568 | * more useful than an error. |
| 37569 | */ |
| 37570 | tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS); |
| 37571 | } |
| 37572 | } |
| 37573 | |
| 37574 | *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff); |
| 37575 | *q++ = (duk_uint8_t) (tmp & 0xff); |
| 37576 | |
| 37577 | tmp = tmp >> 16; |
| 37578 | while (tmp > 0) { |
| 37579 | tmp--; |
| 37580 | dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f); |
| 37581 | *q++ = duk_lc_digits[dig]; |
| 37582 | } |
| 37583 | |
| 37584 | return q; |
| 37585 | } |
| 37586 | |
| 37587 | DUK_LOCAL void duk__json_enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) { |
| 37588 | const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */ |
| 37589 | duk_size_t k_len; |
| 37590 | duk_codepoint_t cp; |
| 37591 | |
| 37592 | DUK_ASSERT(k != NULL); |
| 37593 | |
| 37594 | /* Accept ASCII strings which conform to identifier requirements |
| 37595 | * as being emitted without key quotes. Since we only accept ASCII |
| 37596 | * there's no need for actual decoding: 'p' is intentionally signed |
| 37597 | * so that bytes >= 0x80 extend to negative values and are rejected |
| 37598 | * as invalid identifier codepoints. |
| 37599 | */ |
| 37600 | |
| 37601 | if (js_ctx->flag_avoid_key_quotes) { |
| 37602 | k_len = DUK_HSTRING_GET_BYTELEN(k); |
| 37603 | p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k); |
| 37604 | p_end = p_start + k_len; |
| 37605 | p = p_start; |
| 37606 | |
| 37607 | if (p == p_end) { |
| 37608 | /* Zero length string is not accepted without quotes */ |
| 37609 | goto quote_normally; |
| 37610 | } |
| 37611 | cp = (duk_codepoint_t) (*p++); |
| 37612 | if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) { |
| 37613 | goto quote_normally; |
| 37614 | } |
| 37615 | while (p < p_end) { |
| 37616 | cp = (duk_codepoint_t) (*p++); |
| 37617 | if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) { |
| 37618 | goto quote_normally; |
| 37619 | } |
| 37620 | } |
| 37621 | |
| 37622 | /* This seems faster than emitting bytes one at a time and |
| 37623 | * then potentially rewinding. |
| 37624 | */ |
| 37625 | DUK__EMIT_HSTR(js_ctx, k); |
| 37626 | return; |
| 37627 | } |
| 37628 | |
| 37629 | quote_normally: |
| 37630 | duk__json_enc_quote_string(js_ctx, k); |
| 37631 | } |
| 37632 | |
| 37633 | /* The Quote(value) operation: quote a string. |
| 37634 | * |
| 37635 | * Stack policy: [ ] -> [ ]. |
| 37636 | */ |
| 37637 | |
| 37638 | DUK_LOCAL void duk__json_enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) { |
| 37639 | duk_hthread *thr = js_ctx->thr; |
| 37640 | const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp; |
| 37641 | duk_uint8_t *q; |
| 37642 | duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */ |
| 37643 | |
| 37644 | DUK_DDD(DUK_DDDPRINT("duk__json_enc_quote_string: h_str=%!O" , (duk_heaphdr *) h_str)); |
| 37645 | |
| 37646 | DUK_ASSERT(h_str != NULL); |
| 37647 | p_start = DUK_HSTRING_GET_DATA(h_str); |
| 37648 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str); |
| 37649 | p = p_start; |
| 37650 | |
| 37651 | DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE); |
| 37652 | |
| 37653 | /* Encode string in small chunks, estimating the maximum expansion so that |
| 37654 | * there's no need to ensure space while processing the chunk. |
| 37655 | */ |
| 37656 | |
| 37657 | while (p < p_end) { |
| 37658 | duk_size_t left, now, space; |
| 37659 | |
| 37660 | left = (duk_size_t) (p_end - p); |
| 37661 | now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ? |
| 37662 | DUK__JSON_ENCSTR_CHUNKSIZE : left); |
| 37663 | |
| 37664 | /* Maximum expansion per input byte is 6: |
| 37665 | * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6). |
| 37666 | * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3). |
| 37667 | * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5). |
| 37668 | */ |
| 37669 | space = now * 6; |
| 37670 | q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); |
| 37671 | |
| 37672 | p_now = p + now; |
| 37673 | |
| 37674 | while (p < p_now) { |
| 37675 | #if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH) |
| 37676 | duk_uint8_t b; |
| 37677 | |
| 37678 | b = duk__json_quotestr_lookup[*p++]; |
| 37679 | if (DUK_LIKELY(b < 0x80)) { |
| 37680 | /* Most input bytes go through here. */ |
| 37681 | *q++ = b; |
| 37682 | } else if (b >= 0xa0) { |
| 37683 | *q++ = DUK_ASC_BACKSLASH; |
| 37684 | *q++ = (duk_uint8_t) (b - 0x80); |
| 37685 | } else if (b == 0x80) { |
| 37686 | cp = (duk_ucodepoint_t) (*(p - 1)); |
| 37687 | q = duk__emit_esc_auto_fast(js_ctx, cp, q); |
| 37688 | } else if (b == 0x7f && js_ctx->flag_ascii_only) { |
| 37689 | /* 0x7F is special */ |
| 37690 | DUK_ASSERT(b == 0x81); |
| 37691 | cp = (duk_ucodepoint_t) 0x7f; |
| 37692 | q = duk__emit_esc_auto_fast(js_ctx, cp, q); |
| 37693 | } else { |
| 37694 | DUK_ASSERT(b == 0x81); |
| 37695 | p--; |
| 37696 | |
| 37697 | /* slow path is shared */ |
| 37698 | #else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ |
| 37699 | cp = *p; |
| 37700 | |
| 37701 | if (DUK_LIKELY(cp <= 0x7f)) { |
| 37702 | /* ascii fast path: avoid decoding utf-8 */ |
| 37703 | p++; |
| 37704 | if (cp == 0x22 || cp == 0x5c) { |
| 37705 | /* double quote or backslash */ |
| 37706 | *q++ = DUK_ASC_BACKSLASH; |
| 37707 | *q++ = (duk_uint8_t) cp; |
| 37708 | } else if (cp < 0x20) { |
| 37709 | duk_uint_fast8_t esc_char; |
| 37710 | |
| 37711 | /* This approach is a bit shorter than a straight |
| 37712 | * if-else-ladder and also a bit faster. |
| 37713 | */ |
| 37714 | if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) && |
| 37715 | (esc_char = duk__json_quotestr_esc[cp]) != 0) { |
| 37716 | *q++ = DUK_ASC_BACKSLASH; |
| 37717 | *q++ = (duk_uint8_t) esc_char; |
| 37718 | } else { |
| 37719 | q = duk__emit_esc_auto_fast(js_ctx, cp, q); |
| 37720 | } |
| 37721 | } else if (cp == 0x7f && js_ctx->flag_ascii_only) { |
| 37722 | q = duk__emit_esc_auto_fast(js_ctx, cp, q); |
| 37723 | } else { |
| 37724 | /* any other printable -> as is */ |
| 37725 | *q++ = (duk_uint8_t) cp; |
| 37726 | } |
| 37727 | } else { |
| 37728 | /* slow path is shared */ |
| 37729 | #endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */ |
| 37730 | |
| 37731 | /* slow path decode */ |
| 37732 | |
| 37733 | /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly |
| 37734 | * and go forward one byte. This is of course very lossy, but allows some kind |
| 37735 | * of output to be produced even for internal strings which don't conform to |
| 37736 | * XUTF-8. All standard ECMAScript strings are always CESU-8, so this behavior |
| 37737 | * does not violate the ECMAScript specification. The behavior is applied to |
| 37738 | * all modes, including ECMAScript standard JSON. Because the current XUTF-8 |
| 37739 | * decoding is not very strict, this behavior only really affects initial bytes |
| 37740 | * and truncated codepoints. |
| 37741 | * |
| 37742 | * Another alternative would be to scan forwards to start of next codepoint |
| 37743 | * (or end of input) and emit just one replacement codepoint. |
| 37744 | */ |
| 37745 | |
| 37746 | p_tmp = p; |
| 37747 | if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) { |
| 37748 | /* Decode failed. */ |
| 37749 | cp = *p_tmp; |
| 37750 | p = p_tmp + 1; |
| 37751 | } |
| 37752 | |
| 37753 | #if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029) |
| 37754 | if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) { |
| 37755 | #else |
| 37756 | if (js_ctx->flag_ascii_only) { |
| 37757 | #endif |
| 37758 | q = duk__emit_esc_auto_fast(js_ctx, cp, q); |
| 37759 | } else { |
| 37760 | /* as is */ |
| 37761 | DUK_RAW_WRITEINC_XUTF8(q, cp); |
| 37762 | } |
| 37763 | } |
| 37764 | } |
| 37765 | |
| 37766 | DUK_BW_SET_PTR(thr, &js_ctx->bw, q); |
| 37767 | } |
| 37768 | |
| 37769 | DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE); |
| 37770 | } |
| 37771 | |
| 37772 | /* Encode a double (checked by caller) from stack top. Stack top may be |
| 37773 | * replaced by serialized string but is not popped (caller does that). |
| 37774 | */ |
| 37775 | DUK_LOCAL void duk__json_enc_double(duk_json_enc_ctx *js_ctx) { |
| 37776 | duk_hthread *thr; |
| 37777 | duk_tval *tv; |
| 37778 | duk_double_t d; |
| 37779 | duk_small_int_t c; |
| 37780 | duk_small_int_t s; |
| 37781 | duk_small_uint_t stridx; |
| 37782 | duk_small_uint_t n2s_flags; |
| 37783 | duk_hstring *h_str; |
| 37784 | |
| 37785 | DUK_ASSERT(js_ctx != NULL); |
| 37786 | thr = js_ctx->thr; |
| 37787 | DUK_ASSERT(thr != NULL); |
| 37788 | |
| 37789 | /* Caller must ensure 'tv' is indeed a double and not a fastint! */ |
| 37790 | tv = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 37791 | DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); |
| 37792 | d = DUK_TVAL_GET_DOUBLE(tv); |
| 37793 | |
| 37794 | c = (duk_small_int_t) DUK_FPCLASSIFY(d); |
| 37795 | s = (duk_small_int_t) DUK_SIGNBIT(d); |
| 37796 | DUK_UNREF(s); |
| 37797 | |
| 37798 | if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) { |
| 37799 | DUK_ASSERT(DUK_ISFINITE(d)); |
| 37800 | |
| 37801 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 37802 | /* Negative zero needs special handling in JX/JC because |
| 37803 | * it would otherwise serialize to '0', not '-0'. |
| 37804 | */ |
| 37805 | if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 && |
| 37806 | (js_ctx->flag_ext_custom_or_compatible))) { |
| 37807 | duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_ZERO); /* '-0' */ |
| 37808 | } else |
| 37809 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 37810 | { |
| 37811 | n2s_flags = 0; |
| 37812 | /* [ ... number ] -> [ ... string ] */ |
| 37813 | duk_numconv_stringify(thr, 10 /*radix*/, 0 /*digits*/, n2s_flags); |
| 37814 | } |
| 37815 | h_str = duk_known_hstring(thr, -1); |
| 37816 | DUK__EMIT_HSTR(js_ctx, h_str); |
| 37817 | return; |
| 37818 | } |
| 37819 | |
| 37820 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 37821 | if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | |
| 37822 | DUK_JSON_FLAG_EXT_COMPATIBLE))) { |
| 37823 | stridx = DUK_STRIDX_LC_NULL; |
| 37824 | } else if (c == DUK_FP_NAN) { |
| 37825 | stridx = js_ctx->stridx_custom_nan; |
| 37826 | } else if (s == 0) { |
| 37827 | stridx = js_ctx->stridx_custom_posinf; |
| 37828 | } else { |
| 37829 | stridx = js_ctx->stridx_custom_neginf; |
| 37830 | } |
| 37831 | #else |
| 37832 | stridx = DUK_STRIDX_LC_NULL; |
| 37833 | #endif |
| 37834 | DUK__EMIT_STRIDX(js_ctx, stridx); |
| 37835 | } |
| 37836 | |
| 37837 | #if defined(DUK_USE_FASTINT) |
| 37838 | /* Encode a fastint from duk_tval ptr, no value stack effects. */ |
| 37839 | DUK_LOCAL void duk__json_enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) { |
| 37840 | duk_int64_t v; |
| 37841 | |
| 37842 | /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328 |
| 37843 | * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808 |
| 37844 | * (20 chars long). Alloc space for 64-bit range to be safe. |
| 37845 | */ |
| 37846 | duk_uint8_t buf[20 + 1]; |
| 37847 | |
| 37848 | /* Caller must ensure 'tv' is indeed a fastint! */ |
| 37849 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); |
| 37850 | v = DUK_TVAL_GET_FASTINT(tv); |
| 37851 | |
| 37852 | /* XXX: There are no format strings in duk_config.h yet, could add |
| 37853 | * one for formatting duk_int64_t. For now, assumes "%lld" and that |
| 37854 | * "long long" type exists. Could also rely on C99 directly but that |
| 37855 | * won't work for older MSVC. |
| 37856 | */ |
| 37857 | DUK_SPRINTF((char *) buf, "%lld" , (long long) v); |
| 37858 | DUK__EMIT_CSTR(js_ctx, (const char *) buf); |
| 37859 | } |
| 37860 | #endif |
| 37861 | |
| 37862 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 37863 | #if defined(DUK_USE_HEX_FASTPATH) |
| 37864 | DUK_LOCAL duk_uint8_t *duk__json_enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { |
| 37865 | duk_uint8_t *q; |
| 37866 | duk_uint16_t *q16; |
| 37867 | duk_small_uint_t x; |
| 37868 | duk_size_t i, len_safe; |
| 37869 | #if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) |
| 37870 | duk_bool_t shift_dst; |
| 37871 | #endif |
| 37872 | |
| 37873 | /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2. |
| 37874 | * For platforms where unaligned accesses are not allowed, shift 'dst' |
| 37875 | * ahead by 1 byte to get alignment and then duk_memmove() the result |
| 37876 | * in place. The faster encoding loop makes up the difference. |
| 37877 | * There's always space for one extra byte because a terminator always |
| 37878 | * follows the hex data and that's been accounted for by the caller. |
| 37879 | */ |
| 37880 | |
| 37881 | #if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) |
| 37882 | q16 = (duk_uint16_t *) (void *) dst; |
| 37883 | #else |
| 37884 | shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U); |
| 37885 | if (shift_dst) { |
| 37886 | DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1" )); |
| 37887 | q16 = (duk_uint16_t *) (void *) (dst + 1); |
| 37888 | } else { |
| 37889 | DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned" )); |
| 37890 | q16 = (duk_uint16_t *) (void *) dst; |
| 37891 | } |
| 37892 | DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0); |
| 37893 | #endif |
| 37894 | |
| 37895 | len_safe = src_len & ~0x03U; |
| 37896 | for (i = 0; i < len_safe; i += 4) { |
| 37897 | q16[0] = duk_hex_enctab[src[i]]; |
| 37898 | q16[1] = duk_hex_enctab[src[i + 1]]; |
| 37899 | q16[2] = duk_hex_enctab[src[i + 2]]; |
| 37900 | q16[3] = duk_hex_enctab[src[i + 3]]; |
| 37901 | q16 += 4; |
| 37902 | } |
| 37903 | q = (duk_uint8_t *) q16; |
| 37904 | |
| 37905 | #if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE) |
| 37906 | if (shift_dst) { |
| 37907 | q--; |
| 37908 | duk_memmove((void *) dst, (const void *) (dst + 1), 2 * len_safe); |
| 37909 | DUK_ASSERT(dst + 2 * len_safe == q); |
| 37910 | } |
| 37911 | #endif |
| 37912 | |
| 37913 | for (; i < src_len; i++) { |
| 37914 | x = src[i]; |
| 37915 | *q++ = duk_lc_digits[x >> 4]; |
| 37916 | *q++ = duk_lc_digits[x & 0x0f]; |
| 37917 | } |
| 37918 | |
| 37919 | return q; |
| 37920 | } |
| 37921 | #else /* DUK_USE_HEX_FASTPATH */ |
| 37922 | DUK_LOCAL duk_uint8_t *duk__json_enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) { |
| 37923 | const duk_uint8_t *p; |
| 37924 | const duk_uint8_t *p_end; |
| 37925 | duk_uint8_t *q; |
| 37926 | duk_small_uint_t x; |
| 37927 | |
| 37928 | p = src; |
| 37929 | p_end = src + src_len; |
| 37930 | q = dst; |
| 37931 | while (p != p_end) { |
| 37932 | x = *p++; |
| 37933 | *q++ = duk_lc_digits[x >> 4]; |
| 37934 | *q++ = duk_lc_digits[x & 0x0f]; |
| 37935 | } |
| 37936 | |
| 37937 | return q; |
| 37938 | } |
| 37939 | #endif /* DUK_USE_HEX_FASTPATH */ |
| 37940 | |
| 37941 | DUK_LOCAL void duk__json_enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) { |
| 37942 | duk_hthread *thr; |
| 37943 | duk_uint8_t *q; |
| 37944 | duk_size_t space; |
| 37945 | |
| 37946 | thr = js_ctx->thr; |
| 37947 | |
| 37948 | DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ |
| 37949 | DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); |
| 37950 | |
| 37951 | /* Buffer values are encoded in (lowercase) hex to make the |
| 37952 | * binary data readable. Base64 or similar would be more |
| 37953 | * compact but less readable, and the point of JX/JC |
| 37954 | * variants is to be as useful to a programmer as possible. |
| 37955 | */ |
| 37956 | |
| 37957 | /* The #if defined() clutter here needs to handle the three |
| 37958 | * cases: (1) JX+JC, (2) JX only, (3) JC only. |
| 37959 | */ |
| 37960 | |
| 37961 | /* Note: space must cater for both JX and JC. */ |
| 37962 | space = 9 + buf_len * 2 + 2; |
| 37963 | DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL); |
| 37964 | DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */ |
| 37965 | q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space); |
| 37966 | |
| 37967 | #if defined(DUK_USE_JX) && defined(DUK_USE_JC) |
| 37968 | if (js_ctx->flag_ext_custom) |
| 37969 | #endif |
| 37970 | #if defined(DUK_USE_JX) |
| 37971 | { |
| 37972 | *q++ = DUK_ASC_PIPE; |
| 37973 | q = duk__json_enc_buffer_data_hex(buf_data, buf_len, q); |
| 37974 | *q++ = DUK_ASC_PIPE; |
| 37975 | |
| 37976 | } |
| 37977 | #endif |
| 37978 | #if defined(DUK_USE_JX) && defined(DUK_USE_JC) |
| 37979 | else |
| 37980 | #endif |
| 37981 | #if defined(DUK_USE_JC) |
| 37982 | { |
| 37983 | DUK_ASSERT(js_ctx->flag_ext_compatible); |
| 37984 | duk_memcpy((void *) q, (const void *) "{\"_buf\":\"" , 9); /* len: 9 */ |
| 37985 | q += 9; |
| 37986 | q = duk__json_enc_buffer_data_hex(buf_data, buf_len, q); |
| 37987 | *q++ = DUK_ASC_DOUBLEQUOTE; |
| 37988 | *q++ = DUK_ASC_RCURLY; |
| 37989 | } |
| 37990 | #endif |
| 37991 | |
| 37992 | DUK_BW_SET_PTR(thr, &js_ctx->bw, q); |
| 37993 | } |
| 37994 | |
| 37995 | DUK_LOCAL void duk__json_enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { |
| 37996 | duk__json_enc_buffer_data(js_ctx, |
| 37997 | (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h), |
| 37998 | (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); |
| 37999 | } |
| 38000 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 38001 | |
| 38002 | #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) |
| 38003 | DUK_LOCAL void duk__json_enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) { |
| 38004 | duk_size_t i, n; |
| 38005 | const duk_uint8_t *buf; |
| 38006 | duk_uint8_t *q; |
| 38007 | |
| 38008 | n = DUK_HBUFFER_GET_SIZE(h); |
| 38009 | if (n == 0) { |
| 38010 | DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY); |
| 38011 | return; |
| 38012 | } |
| 38013 | |
| 38014 | DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); |
| 38015 | |
| 38016 | /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18, |
| 38017 | * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28. 32 has some slack. |
| 38018 | * |
| 38019 | * Note that because the output buffer is reallocated from time to time, |
| 38020 | * side effects (such as finalizers) affecting the buffer 'h' must be |
| 38021 | * disabled. This is the case in the JSON.stringify() fast path. |
| 38022 | */ |
| 38023 | |
| 38024 | buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h); |
| 38025 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38026 | for (i = 0; i < n; i++) { |
| 38027 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1); |
| 38028 | q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32); |
| 38029 | q += DUK_SPRINTF((char *) q, "\"%lu\": %u," , (unsigned long) i, (unsigned int) buf[i]); |
| 38030 | DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); |
| 38031 | } |
| 38032 | } else { |
| 38033 | q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw); |
| 38034 | for (i = 0; i < n; i++) { |
| 38035 | q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q); |
| 38036 | q += DUK_SPRINTF((char *) q, "\"%lu\":%u," , (unsigned long) i, (unsigned int) buf[i]); |
| 38037 | } |
| 38038 | DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q); |
| 38039 | } |
| 38040 | DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ |
| 38041 | |
| 38042 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38043 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth); |
| 38044 | } |
| 38045 | DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); |
| 38046 | } |
| 38047 | #endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ |
| 38048 | |
| 38049 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38050 | DUK_LOCAL void duk__json_enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) { |
| 38051 | char buf[64]; /* XXX: how to figure correct size? */ |
| 38052 | const char *fmt; |
| 38053 | |
| 38054 | DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */ |
| 38055 | DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible); |
| 38056 | |
| 38057 | duk_memzero(buf, sizeof(buf)); |
| 38058 | |
| 38059 | /* The #if defined() clutter here needs to handle the three |
| 38060 | * cases: (1) JX+JC, (2) JX only, (3) JC only. |
| 38061 | */ |
| 38062 | #if defined(DUK_USE_JX) && defined(DUK_USE_JC) |
| 38063 | if (js_ctx->flag_ext_custom) |
| 38064 | #endif |
| 38065 | #if defined(DUK_USE_JX) |
| 38066 | { |
| 38067 | fmt = ptr ? "(%p)" : "(null)" ; |
| 38068 | } |
| 38069 | #endif |
| 38070 | #if defined(DUK_USE_JX) && defined(DUK_USE_JC) |
| 38071 | else |
| 38072 | #endif |
| 38073 | #if defined(DUK_USE_JC) |
| 38074 | { |
| 38075 | DUK_ASSERT(js_ctx->flag_ext_compatible); |
| 38076 | fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}" ; |
| 38077 | } |
| 38078 | #endif |
| 38079 | |
| 38080 | /* When ptr == NULL, the format argument is unused. */ |
| 38081 | DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */ |
| 38082 | DUK__EMIT_CSTR(js_ctx, buf); |
| 38083 | } |
| 38084 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 38085 | |
| 38086 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 38087 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38088 | DUK_LOCAL void duk__json_enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) { |
| 38089 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 38090 | |
| 38091 | if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) { |
| 38092 | DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); |
| 38093 | } else { |
| 38094 | /* Handle both full and partial slice (as long as covered). */ |
| 38095 | duk__json_enc_buffer_data(js_ctx, |
| 38096 | (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj), |
| 38097 | (duk_size_t) h_bufobj->length); |
| 38098 | } |
| 38099 | } |
| 38100 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 38101 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 38102 | |
| 38103 | /* Indent helper. Calling code relies on js_ctx->recursion_depth also being |
| 38104 | * directly related to indent depth. |
| 38105 | */ |
| 38106 | #if defined(DUK_USE_PREFER_SIZE) |
| 38107 | DUK_LOCAL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) { |
| 38108 | DUK_ASSERT(js_ctx->h_gap != NULL); |
| 38109 | DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ |
| 38110 | |
| 38111 | DUK__EMIT_1(js_ctx, 0x0a); |
| 38112 | while (depth-- > 0) { |
| 38113 | DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap); |
| 38114 | } |
| 38115 | } |
| 38116 | #else /* DUK_USE_PREFER_SIZE */ |
| 38117 | DUK_LOCAL void duk__json_enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) { |
| 38118 | const duk_uint8_t *gap_data; |
| 38119 | duk_size_t gap_len; |
| 38120 | duk_size_t avail_bytes; /* bytes of indent available for copying */ |
| 38121 | duk_size_t need_bytes; /* bytes of indent still needed */ |
| 38122 | duk_uint8_t *p_start; |
| 38123 | duk_uint8_t *p; |
| 38124 | |
| 38125 | DUK_ASSERT(js_ctx->h_gap != NULL); |
| 38126 | DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */ |
| 38127 | |
| 38128 | DUK__EMIT_1(js_ctx, 0x0a); |
| 38129 | if (DUK_UNLIKELY(depth == 0)) { |
| 38130 | return; |
| 38131 | } |
| 38132 | |
| 38133 | /* To handle deeper indents efficiently, make use of copies we've |
| 38134 | * already emitted. In effect we can emit a sequence of 1, 2, 4, |
| 38135 | * 8, etc copies, and then finish the last run. Byte counters |
| 38136 | * avoid multiply with gap_len on every loop. |
| 38137 | */ |
| 38138 | |
| 38139 | gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap); |
| 38140 | gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap); |
| 38141 | DUK_ASSERT(gap_len > 0); |
| 38142 | |
| 38143 | need_bytes = gap_len * depth; |
| 38144 | p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes); |
| 38145 | p_start = p; |
| 38146 | |
| 38147 | duk_memcpy((void *) p, (const void *) gap_data, (size_t) gap_len); |
| 38148 | p += gap_len; |
| 38149 | avail_bytes = gap_len; |
| 38150 | DUK_ASSERT(need_bytes >= gap_len); |
| 38151 | need_bytes -= gap_len; |
| 38152 | |
| 38153 | while (need_bytes >= avail_bytes) { |
| 38154 | duk_memcpy((void *) p, (const void *) p_start, (size_t) avail_bytes); |
| 38155 | p += avail_bytes; |
| 38156 | need_bytes -= avail_bytes; |
| 38157 | avail_bytes <<= 1; |
| 38158 | } |
| 38159 | |
| 38160 | DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */ |
| 38161 | duk_memcpy((void *) p, (const void *) p_start, (size_t) need_bytes); |
| 38162 | p += need_bytes; |
| 38163 | /*avail_bytes += need_bytes*/ |
| 38164 | |
| 38165 | DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p); |
| 38166 | } |
| 38167 | #endif /* DUK_USE_PREFER_SIZE */ |
| 38168 | |
| 38169 | /* Shared entry handling for object/array serialization. */ |
| 38170 | DUK_LOCAL void duk__json_enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { |
| 38171 | duk_hthread *thr = js_ctx->thr; |
| 38172 | duk_hobject *h_target; |
| 38173 | duk_uint_fast32_t i, n; |
| 38174 | |
| 38175 | *entry_top = duk_get_top(thr); |
| 38176 | |
| 38177 | duk_native_stack_check(thr); |
| 38178 | duk_require_stack(thr, DUK_JSON_ENC_REQSTACK); |
| 38179 | |
| 38180 | /* Loop check using a hybrid approach: a fixed-size visited[] array |
| 38181 | * with overflow in a loop check object. |
| 38182 | */ |
| 38183 | |
| 38184 | h_target = duk_known_hobject(thr, -1); /* object or array */ |
| 38185 | |
| 38186 | n = js_ctx->recursion_depth; |
| 38187 | if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) { |
| 38188 | n = DUK_JSON_ENC_LOOPARRAY; |
| 38189 | } |
| 38190 | for (i = 0; i < n; i++) { |
| 38191 | if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) { |
| 38192 | DUK_DD(DUK_DDPRINT("slow path loop detect" )); |
| 38193 | DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT); |
| 38194 | DUK_WO_NORETURN(return;); |
| 38195 | } |
| 38196 | } |
| 38197 | if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { |
| 38198 | js_ctx->visiting[js_ctx->recursion_depth] = h_target; |
| 38199 | } else { |
| 38200 | duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target); |
| 38201 | duk_dup_top(thr); /* -> [ ... voidp voidp ] */ |
| 38202 | if (duk_has_prop(thr, js_ctx->idx_loop)) { |
| 38203 | DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT); |
| 38204 | DUK_WO_NORETURN(return;); |
| 38205 | } |
| 38206 | duk_push_true(thr); /* -> [ ... voidp true ] */ |
| 38207 | duk_put_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */ |
| 38208 | } |
| 38209 | |
| 38210 | /* C recursion check. */ |
| 38211 | |
| 38212 | DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */ |
| 38213 | DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); |
| 38214 | if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { |
| 38215 | DUK_ERROR_RANGE(thr, DUK_STR_ENC_RECLIMIT); |
| 38216 | DUK_WO_NORETURN(return;); |
| 38217 | } |
| 38218 | js_ctx->recursion_depth++; |
| 38219 | |
| 38220 | DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T" , |
| 38221 | (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop))); |
| 38222 | } |
| 38223 | |
| 38224 | /* Shared exit handling for object/array serialization. */ |
| 38225 | DUK_LOCAL void duk__json_enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) { |
| 38226 | duk_hthread *thr = js_ctx->thr; |
| 38227 | duk_hobject *h_target; |
| 38228 | |
| 38229 | /* C recursion check. */ |
| 38230 | |
| 38231 | DUK_ASSERT(js_ctx->recursion_depth > 0); |
| 38232 | DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); |
| 38233 | js_ctx->recursion_depth--; |
| 38234 | |
| 38235 | /* Loop check. */ |
| 38236 | |
| 38237 | h_target = duk_known_hobject(thr, *entry_top - 1); /* original target at entry_top - 1 */ |
| 38238 | |
| 38239 | if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) { |
| 38240 | /* Previous entry was inside visited[], nothing to do. */ |
| 38241 | } else { |
| 38242 | duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target); |
| 38243 | duk_del_prop(thr, js_ctx->idx_loop); /* -> [ ... ] */ |
| 38244 | } |
| 38245 | |
| 38246 | /* Restore stack top after unbalanced code paths. */ |
| 38247 | duk_set_top(thr, *entry_top); |
| 38248 | |
| 38249 | DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T" , |
| 38250 | (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop))); |
| 38251 | } |
| 38252 | |
| 38253 | /* The JO(value) operation: encode object. |
| 38254 | * |
| 38255 | * Stack policy: [ object ] -> [ object ]. |
| 38256 | */ |
| 38257 | DUK_LOCAL void duk__json_enc_object(duk_json_enc_ctx *js_ctx) { |
| 38258 | duk_hthread *thr = js_ctx->thr; |
| 38259 | duk_hstring *h_key; |
| 38260 | duk_idx_t entry_top; |
| 38261 | duk_idx_t idx_obj; |
| 38262 | duk_idx_t idx_keys; |
| 38263 | duk_bool_t emitted; |
| 38264 | duk_uarridx_t arr_len, i; |
| 38265 | duk_size_t prev_size; |
| 38266 | |
| 38267 | DUK_DDD(DUK_DDDPRINT("duk__json_enc_object: obj=%!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 38268 | |
| 38269 | duk__json_enc_objarr_entry(js_ctx, &entry_top); |
| 38270 | |
| 38271 | idx_obj = entry_top - 1; |
| 38272 | |
| 38273 | if (js_ctx->idx_proplist >= 0) { |
| 38274 | idx_keys = js_ctx->idx_proplist; |
| 38275 | } else { |
| 38276 | /* XXX: would be nice to enumerate an object at specified index */ |
| 38277 | duk_dup(thr, idx_obj); |
| 38278 | (void) duk_hobject_get_enumerated_keys(thr, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */ |
| 38279 | idx_keys = duk_require_normalize_index(thr, -1); |
| 38280 | /* leave stack unbalanced on purpose */ |
| 38281 | } |
| 38282 | |
| 38283 | DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T" , |
| 38284 | (long) idx_keys, (duk_tval *) duk_get_tval(thr, idx_keys))); |
| 38285 | |
| 38286 | /* Steps 8-10 have been merged to avoid a "partial" variable. */ |
| 38287 | |
| 38288 | DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); |
| 38289 | |
| 38290 | /* XXX: keys is an internal object with all keys to be processed |
| 38291 | * in its (gapless) array part. Because nobody can touch the keys |
| 38292 | * object, we could iterate its array part directly (keeping in mind |
| 38293 | * that it can be reallocated). |
| 38294 | */ |
| 38295 | |
| 38296 | arr_len = (duk_uarridx_t) duk_get_length(thr, idx_keys); |
| 38297 | emitted = 0; |
| 38298 | for (i = 0; i < arr_len; i++) { |
| 38299 | duk_get_prop_index(thr, idx_keys, i); /* -> [ ... key ] */ |
| 38300 | |
| 38301 | DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T" , |
| 38302 | (duk_tval *) duk_get_tval(thr, idx_obj), |
| 38303 | (duk_tval *) duk_get_tval(thr, -1))); |
| 38304 | |
| 38305 | h_key = duk_known_hstring(thr, -1); |
| 38306 | DUK_ASSERT(h_key != NULL); |
| 38307 | DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */ |
| 38308 | |
| 38309 | prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); |
| 38310 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38311 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth); |
| 38312 | duk__json_enc_key_autoquote(js_ctx, h_key); |
| 38313 | DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); |
| 38314 | } else { |
| 38315 | duk__json_enc_key_autoquote(js_ctx, h_key); |
| 38316 | DUK__EMIT_1(js_ctx, DUK_ASC_COLON); |
| 38317 | } |
| 38318 | |
| 38319 | /* [ ... key ] */ |
| 38320 | |
| 38321 | if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_obj) == 0)) { |
| 38322 | /* Value would yield 'undefined', so skip key altogether. |
| 38323 | * Side effects have already happened. |
| 38324 | */ |
| 38325 | DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size); |
| 38326 | } else { |
| 38327 | DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); |
| 38328 | emitted = 1; |
| 38329 | } |
| 38330 | |
| 38331 | /* [ ... ] */ |
| 38332 | } |
| 38333 | |
| 38334 | if (emitted) { |
| 38335 | DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); |
| 38336 | DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ |
| 38337 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38338 | DUK_ASSERT(js_ctx->recursion_depth >= 1); |
| 38339 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); |
| 38340 | } |
| 38341 | } |
| 38342 | DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); |
| 38343 | |
| 38344 | duk__json_enc_objarr_exit(js_ctx, &entry_top); |
| 38345 | |
| 38346 | DUK_ASSERT_TOP(thr, entry_top); |
| 38347 | } |
| 38348 | |
| 38349 | /* The JA(value) operation: encode array. |
| 38350 | * |
| 38351 | * Stack policy: [ array ] -> [ array ]. |
| 38352 | */ |
| 38353 | DUK_LOCAL void duk__json_enc_array(duk_json_enc_ctx *js_ctx) { |
| 38354 | duk_hthread *thr = js_ctx->thr; |
| 38355 | duk_idx_t entry_top; |
| 38356 | duk_idx_t idx_arr; |
| 38357 | duk_bool_t emitted; |
| 38358 | duk_uarridx_t i, arr_len; |
| 38359 | |
| 38360 | DUK_DDD(DUK_DDDPRINT("duk__json_enc_array: array=%!T" , |
| 38361 | (duk_tval *) duk_get_tval(thr, -1))); |
| 38362 | |
| 38363 | duk__json_enc_objarr_entry(js_ctx, &entry_top); |
| 38364 | |
| 38365 | idx_arr = entry_top - 1; |
| 38366 | |
| 38367 | /* Steps 8-10 have been merged to avoid a "partial" variable. */ |
| 38368 | |
| 38369 | DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET); |
| 38370 | |
| 38371 | arr_len = (duk_uarridx_t) duk_get_length(thr, idx_arr); |
| 38372 | emitted = 0; |
| 38373 | for (i = 0; i < arr_len; i++) { |
| 38374 | DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld" , |
| 38375 | (duk_tval *) duk_get_tval(thr, idx_arr), |
| 38376 | (long) i, (long) arr_len)); |
| 38377 | |
| 38378 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38379 | DUK_ASSERT(js_ctx->recursion_depth >= 1); |
| 38380 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth); |
| 38381 | } |
| 38382 | |
| 38383 | (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i); /* -> [ ... key ] */ |
| 38384 | |
| 38385 | /* [ ... key ] */ |
| 38386 | |
| 38387 | if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_arr) == 0)) { |
| 38388 | /* Value would normally be omitted, replace with 'null'. */ |
| 38389 | DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); |
| 38390 | } else { |
| 38391 | ; |
| 38392 | } |
| 38393 | |
| 38394 | /* [ ... ] */ |
| 38395 | |
| 38396 | DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); |
| 38397 | emitted = 1; |
| 38398 | } |
| 38399 | |
| 38400 | if (emitted) { |
| 38401 | DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); |
| 38402 | DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ |
| 38403 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38404 | DUK_ASSERT(js_ctx->recursion_depth >= 1); |
| 38405 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); |
| 38406 | } |
| 38407 | } |
| 38408 | DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); |
| 38409 | |
| 38410 | duk__json_enc_objarr_exit(js_ctx, &entry_top); |
| 38411 | |
| 38412 | DUK_ASSERT_TOP(thr, entry_top); |
| 38413 | } |
| 38414 | |
| 38415 | /* The Str(key, holder) operation. |
| 38416 | * |
| 38417 | * Stack policy: [ ... key ] -> [ ... ] |
| 38418 | */ |
| 38419 | DUK_LOCAL duk_bool_t duk__json_enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) { |
| 38420 | duk_hthread *thr = js_ctx->thr; |
| 38421 | duk_tval *tv; |
| 38422 | duk_tval *tv_holder; |
| 38423 | duk_tval *tv_key; |
| 38424 | duk_small_int_t c; |
| 38425 | |
| 38426 | DUK_DDD(DUK_DDDPRINT("duk__json_enc_value: idx_holder=%ld, holder=%!T, key=%!T" , |
| 38427 | (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder), |
| 38428 | (duk_tval *) duk_get_tval(thr, -1))); |
| 38429 | |
| 38430 | tv_holder = DUK_GET_TVAL_POSIDX(thr, idx_holder); |
| 38431 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder)); |
| 38432 | tv_key = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 38433 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key)); |
| 38434 | DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */ |
| 38435 | (void) duk_hobject_getprop(thr, tv_holder, tv_key); |
| 38436 | |
| 38437 | /* -> [ ... key val ] */ |
| 38438 | |
| 38439 | DUK_DDD(DUK_DDDPRINT("value=%!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 38440 | |
| 38441 | /* Standard JSON checks for .toJSON() only for actual objects; for |
| 38442 | * example, setting Number.prototype.toJSON and then serializing a |
| 38443 | * number won't invoke the .toJSON() method. However, lightfuncs and |
| 38444 | * plain buffers mimic objects so we check for their .toJSON() method. |
| 38445 | */ |
| 38446 | if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | |
| 38447 | DUK_TYPE_MASK_LIGHTFUNC | |
| 38448 | DUK_TYPE_MASK_BUFFER)) { |
| 38449 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_JSON); |
| 38450 | if (duk_is_callable(thr, -1)) { /* toJSON() can also be a lightfunc */ |
| 38451 | DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it" )); |
| 38452 | /* XXX: duk_dup_unvalidated(thr, -2) etc. */ |
| 38453 | duk_dup_m2(thr); /* -> [ ... key val toJSON val ] */ |
| 38454 | duk_dup_m4(thr); /* -> [ ... key val toJSON val key ] */ |
| 38455 | duk_call_method(thr, 1); /* -> [ ... key val val' ] */ |
| 38456 | duk_remove_m2(thr); /* -> [ ... key val' ] */ |
| 38457 | } else { |
| 38458 | duk_pop(thr); /* -> [ ... key val ] */ |
| 38459 | } |
| 38460 | } |
| 38461 | |
| 38462 | /* [ ... key val ] */ |
| 38463 | |
| 38464 | DUK_DDD(DUK_DDDPRINT("value=%!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 38465 | |
| 38466 | if (js_ctx->h_replacer) { |
| 38467 | /* XXX: Here a "slice copy" would be useful. */ |
| 38468 | DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer" )); |
| 38469 | duk_push_hobject(thr, js_ctx->h_replacer); /* -> [ ... key val replacer ] */ |
| 38470 | duk_dup(thr, idx_holder); /* -> [ ... key val replacer holder ] */ |
| 38471 | duk_dup_m4(thr); /* -> [ ... key val replacer holder key ] */ |
| 38472 | duk_dup_m4(thr); /* -> [ ... key val replacer holder key val ] */ |
| 38473 | duk_call_method(thr, 2); /* -> [ ... key val val' ] */ |
| 38474 | duk_remove_m2(thr); /* -> [ ... key val' ] */ |
| 38475 | } |
| 38476 | |
| 38477 | /* [ ... key val ] */ |
| 38478 | |
| 38479 | DUK_DDD(DUK_DDDPRINT("value=%!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 38480 | |
| 38481 | tv = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 38482 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 38483 | duk_hobject *h; |
| 38484 | |
| 38485 | h = DUK_TVAL_GET_OBJECT(tv); |
| 38486 | DUK_ASSERT(h != NULL); |
| 38487 | |
| 38488 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 38489 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38490 | if (DUK_HOBJECT_IS_BUFOBJ(h) && |
| 38491 | js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) { |
| 38492 | /* With JX/JC a bufferobject gets serialized specially. */ |
| 38493 | duk_hbufobj *h_bufobj; |
| 38494 | h_bufobj = (duk_hbufobj *) h; |
| 38495 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 38496 | duk__json_enc_bufobj(js_ctx, h_bufobj); |
| 38497 | goto pop2_emitted; |
| 38498 | } |
| 38499 | /* Otherwise bufferobjects get serialized as normal objects. */ |
| 38500 | #endif /* JX || JC */ |
| 38501 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 38502 | c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); |
| 38503 | switch (c) { |
| 38504 | case DUK_HOBJECT_CLASS_NUMBER: { |
| 38505 | DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()" )); |
| 38506 | duk_to_number_m1(thr); |
| 38507 | /* The coercion potentially invokes user .valueOf() and .toString() |
| 38508 | * but can't result in a function value because ToPrimitive() would |
| 38509 | * reject such a result: test-dev-json-stringify-coercion-1.js. |
| 38510 | */ |
| 38511 | DUK_ASSERT(!duk_is_callable(thr, -1)); |
| 38512 | break; |
| 38513 | } |
| 38514 | case DUK_HOBJECT_CLASS_STRING: { |
| 38515 | DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()" )); |
| 38516 | duk_to_string(thr, -1); |
| 38517 | /* Same coercion behavior as for Number. */ |
| 38518 | DUK_ASSERT(!duk_is_callable(thr, -1)); |
| 38519 | break; |
| 38520 | } |
| 38521 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38522 | case DUK_HOBJECT_CLASS_POINTER: |
| 38523 | #endif |
| 38524 | case DUK_HOBJECT_CLASS_BOOLEAN: { |
| 38525 | DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value" )); |
| 38526 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); |
| 38527 | duk_remove_m2(thr); |
| 38528 | break; |
| 38529 | } |
| 38530 | default: { |
| 38531 | /* Normal object which doesn't get automatically coerced to a |
| 38532 | * primitive value. Functions are checked for specially. The |
| 38533 | * primitive value coercions for Number, String, Pointer, and |
| 38534 | * Boolean can't result in functions so suffices to check here. |
| 38535 | * Symbol objects are handled like plain objects (their primitive |
| 38536 | * value is NOT looked up like for e.g. String objects). |
| 38537 | */ |
| 38538 | DUK_ASSERT(h != NULL); |
| 38539 | if (DUK_HOBJECT_IS_CALLABLE(h)) { |
| 38540 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38541 | if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | |
| 38542 | DUK_JSON_FLAG_EXT_COMPATIBLE)) { |
| 38543 | /* We only get here when doing non-standard JSON encoding */ |
| 38544 | DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format" )); |
| 38545 | DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); |
| 38546 | DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); |
| 38547 | goto pop2_emitted; |
| 38548 | } else { |
| 38549 | DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)" )); |
| 38550 | goto pop2_undef; |
| 38551 | } |
| 38552 | #else /* DUK_USE_JX || DUK_USE_JC */ |
| 38553 | DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)" )); |
| 38554 | goto pop2_undef; |
| 38555 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 38556 | } |
| 38557 | } |
| 38558 | } /* end switch */ |
| 38559 | } |
| 38560 | |
| 38561 | /* [ ... key val ] */ |
| 38562 | |
| 38563 | DUK_DDD(DUK_DDDPRINT("value=%!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 38564 | |
| 38565 | if (duk_check_type_mask(thr, -1, js_ctx->mask_for_undefined)) { |
| 38566 | /* will result in undefined */ |
| 38567 | DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)" )); |
| 38568 | goto pop2_undef; |
| 38569 | } |
| 38570 | tv = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 38571 | |
| 38572 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 38573 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38574 | /* When JX/JC not in use, the type mask above will avoid this case if needed. */ |
| 38575 | case DUK_TAG_UNDEFINED: { |
| 38576 | DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); |
| 38577 | break; |
| 38578 | } |
| 38579 | #endif |
| 38580 | case DUK_TAG_NULL: { |
| 38581 | DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); |
| 38582 | break; |
| 38583 | } |
| 38584 | case DUK_TAG_BOOLEAN: { |
| 38585 | DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ? |
| 38586 | DUK_STRIDX_TRUE : DUK_STRIDX_FALSE); |
| 38587 | break; |
| 38588 | } |
| 38589 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38590 | /* When JX/JC not in use, the type mask above will avoid this case if needed. */ |
| 38591 | case DUK_TAG_POINTER: { |
| 38592 | duk__json_enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); |
| 38593 | break; |
| 38594 | } |
| 38595 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 38596 | case DUK_TAG_STRING: { |
| 38597 | duk_hstring *h = DUK_TVAL_GET_STRING(tv); |
| 38598 | DUK_ASSERT(h != NULL); |
| 38599 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 38600 | goto pop2_undef; |
| 38601 | } |
| 38602 | duk__json_enc_quote_string(js_ctx, h); |
| 38603 | break; |
| 38604 | } |
| 38605 | case DUK_TAG_OBJECT: { |
| 38606 | duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); |
| 38607 | DUK_ASSERT(h != NULL); |
| 38608 | |
| 38609 | /* Function values are handled completely above (including |
| 38610 | * coercion results): |
| 38611 | */ |
| 38612 | DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h)); |
| 38613 | |
| 38614 | if (duk_js_isarray_hobject(h)) { |
| 38615 | duk__json_enc_array(js_ctx); |
| 38616 | } else { |
| 38617 | duk__json_enc_object(js_ctx); |
| 38618 | } |
| 38619 | break; |
| 38620 | } |
| 38621 | /* Because plain buffers mimics Uint8Array, they have enumerable |
| 38622 | * index properties [0,byteLength[. Because JSON only serializes |
| 38623 | * enumerable own properties, no properties can be serialized for |
| 38624 | * plain buffers (all virtual properties are non-enumerable). However, |
| 38625 | * there may be a .toJSON() method which was already handled above. |
| 38626 | */ |
| 38627 | case DUK_TAG_BUFFER: { |
| 38628 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38629 | if (js_ctx->flag_ext_custom_or_compatible) { |
| 38630 | duk__json_enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); |
| 38631 | break; |
| 38632 | } |
| 38633 | #endif |
| 38634 | |
| 38635 | /* Could implement a fastpath, but the fast path would need |
| 38636 | * to handle realloc side effects correctly. |
| 38637 | */ |
| 38638 | duk_to_object(thr, -1); |
| 38639 | duk__json_enc_object(js_ctx); |
| 38640 | break; |
| 38641 | } |
| 38642 | case DUK_TAG_LIGHTFUNC: { |
| 38643 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38644 | /* We only get here when doing non-standard JSON encoding */ |
| 38645 | DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); |
| 38646 | DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); |
| 38647 | #else |
| 38648 | /* Standard JSON omits functions */ |
| 38649 | DUK_UNREACHABLE(); |
| 38650 | #endif |
| 38651 | break; |
| 38652 | } |
| 38653 | #if defined(DUK_USE_FASTINT) |
| 38654 | case DUK_TAG_FASTINT: |
| 38655 | /* Number serialization has a significant impact relative to |
| 38656 | * other fast path code, so careful fast path for fastints. |
| 38657 | */ |
| 38658 | duk__json_enc_fastint_tval(js_ctx, tv); |
| 38659 | break; |
| 38660 | #endif |
| 38661 | default: { |
| 38662 | /* number */ |
| 38663 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 38664 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 38665 | /* XXX: A fast path for usual integers would be useful when |
| 38666 | * fastint support is not enabled. |
| 38667 | */ |
| 38668 | duk__json_enc_double(js_ctx); |
| 38669 | break; |
| 38670 | } |
| 38671 | } |
| 38672 | |
| 38673 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38674 | pop2_emitted: |
| 38675 | #endif |
| 38676 | duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */ |
| 38677 | return 1; /* emitted */ |
| 38678 | |
| 38679 | pop2_undef: |
| 38680 | duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */ |
| 38681 | return 0; /* not emitted */ |
| 38682 | } |
| 38683 | |
| 38684 | /* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */ |
| 38685 | DUK_LOCAL duk_bool_t duk__json_enc_allow_into_proplist(duk_tval *tv) { |
| 38686 | duk_small_int_t c; |
| 38687 | |
| 38688 | /* XXX: some kind of external internal type checker? |
| 38689 | * - type mask; symbol flag; class mask |
| 38690 | */ |
| 38691 | DUK_ASSERT(tv != NULL); |
| 38692 | if (DUK_TVAL_IS_STRING(tv)) { |
| 38693 | duk_hstring *h; |
| 38694 | h = DUK_TVAL_GET_STRING(tv); |
| 38695 | DUK_ASSERT(h != NULL); |
| 38696 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 38697 | return 0; |
| 38698 | } |
| 38699 | return 1; |
| 38700 | } else if (DUK_TVAL_IS_NUMBER(tv)) { |
| 38701 | return 1; |
| 38702 | } else if (DUK_TVAL_IS_OBJECT(tv)) { |
| 38703 | duk_hobject *h; |
| 38704 | h = DUK_TVAL_GET_OBJECT(tv); |
| 38705 | DUK_ASSERT(h != NULL); |
| 38706 | c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h); |
| 38707 | if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) { |
| 38708 | return 1; |
| 38709 | } |
| 38710 | } |
| 38711 | |
| 38712 | return 0; |
| 38713 | } |
| 38714 | |
| 38715 | /* |
| 38716 | * JSON.stringify() fast path |
| 38717 | * |
| 38718 | * Otherwise supports full JSON, JX, and JC features, but bails out on any |
| 38719 | * possible side effect which might change the value being serialized. The |
| 38720 | * fast path can take advantage of the fact that the value being serialized |
| 38721 | * is unchanged so that we can walk directly through property tables etc. |
| 38722 | */ |
| 38723 | |
| 38724 | #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) |
| 38725 | DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) { |
| 38726 | duk_uint_fast32_t i, n; |
| 38727 | |
| 38728 | DUK_DDD(DUK_DDDPRINT("stringify fast: %!T" , tv)); |
| 38729 | |
| 38730 | DUK_ASSERT(js_ctx != NULL); |
| 38731 | DUK_ASSERT(js_ctx->thr != NULL); |
| 38732 | |
| 38733 | #if 0 /* disabled for now */ |
| 38734 | restart_match: |
| 38735 | #endif |
| 38736 | |
| 38737 | DUK_ASSERT(tv != NULL); |
| 38738 | |
| 38739 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 38740 | case DUK_TAG_UNDEFINED: { |
| 38741 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38742 | if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) { |
| 38743 | DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); |
| 38744 | break; |
| 38745 | } else { |
| 38746 | goto emit_undefined; |
| 38747 | } |
| 38748 | #else |
| 38749 | goto emit_undefined; |
| 38750 | #endif |
| 38751 | } |
| 38752 | case DUK_TAG_NULL: { |
| 38753 | DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); |
| 38754 | break; |
| 38755 | } |
| 38756 | case DUK_TAG_BOOLEAN: { |
| 38757 | DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ? |
| 38758 | DUK_STRIDX_TRUE : DUK_STRIDX_FALSE); |
| 38759 | break; |
| 38760 | } |
| 38761 | case DUK_TAG_STRING: { |
| 38762 | duk_hstring *h; |
| 38763 | h = DUK_TVAL_GET_STRING(tv); |
| 38764 | DUK_ASSERT(h != NULL); |
| 38765 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 38766 | goto emit_undefined; |
| 38767 | } |
| 38768 | duk__json_enc_quote_string(js_ctx, h); |
| 38769 | break; |
| 38770 | } |
| 38771 | case DUK_TAG_OBJECT: { |
| 38772 | duk_hobject *obj; |
| 38773 | duk_tval *tv_val; |
| 38774 | duk_bool_t emitted = 0; |
| 38775 | duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef, |
| 38776 | c_func, c_bufobj, c_object, c_abort; |
| 38777 | |
| 38778 | /* For objects JSON.stringify() only looks for own, enumerable |
| 38779 | * properties which is nice for the fast path here. |
| 38780 | * |
| 38781 | * For arrays JSON.stringify() uses [[Get]] so it will actually |
| 38782 | * inherit properties during serialization! This fast path |
| 38783 | * supports gappy arrays as long as there's no actual inherited |
| 38784 | * property (which might be a getter etc). |
| 38785 | * |
| 38786 | * Since recursion only happens for objects, we can have both |
| 38787 | * recursion and loop checks here. We use a simple, depth-limited |
| 38788 | * loop check in the fast path because the object-based tracking |
| 38789 | * is very slow (when tested, it accounted for 50% of fast path |
| 38790 | * execution time for input data with a lot of small objects!). |
| 38791 | */ |
| 38792 | |
| 38793 | /* XXX: for real world code, could just ignore array inheritance |
| 38794 | * and only look at array own properties. |
| 38795 | */ |
| 38796 | |
| 38797 | /* We rely on a few object flag / class number relationships here, |
| 38798 | * assert for them. |
| 38799 | */ |
| 38800 | |
| 38801 | obj = DUK_TVAL_GET_OBJECT(tv); |
| 38802 | DUK_ASSERT(obj != NULL); |
| 38803 | DUK_HOBJECT_ASSERT_VALID(obj); |
| 38804 | |
| 38805 | /* Once recursion depth is increased, exit path must decrease |
| 38806 | * it (though it's OK to abort the fast path). |
| 38807 | */ |
| 38808 | |
| 38809 | DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0); /* unsigned */ |
| 38810 | DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); |
| 38811 | if (js_ctx->recursion_depth >= js_ctx->recursion_limit) { |
| 38812 | DUK_DD(DUK_DDPRINT("fast path recursion limit" )); |
| 38813 | DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_DEC_RECLIMIT); |
| 38814 | DUK_WO_NORETURN(return 0;); |
| 38815 | } |
| 38816 | |
| 38817 | for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) { |
| 38818 | if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) { |
| 38819 | DUK_DD(DUK_DDPRINT("fast path loop detect" )); |
| 38820 | DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT); |
| 38821 | DUK_WO_NORETURN(return 0;); |
| 38822 | } |
| 38823 | } |
| 38824 | |
| 38825 | /* Guaranteed by recursion_limit setup so we don't have to |
| 38826 | * check twice. |
| 38827 | */ |
| 38828 | DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY); |
| 38829 | js_ctx->visiting[js_ctx->recursion_depth] = obj; |
| 38830 | js_ctx->recursion_depth++; |
| 38831 | |
| 38832 | /* If object has a .toJSON() property, we can't be certain |
| 38833 | * that it wouldn't mutate any value arbitrarily, so bail |
| 38834 | * out of the fast path. |
| 38835 | * |
| 38836 | * If an object is a Proxy we also can't avoid side effects |
| 38837 | * so abandon. |
| 38838 | */ |
| 38839 | /* XXX: non-callable .toJSON() doesn't need to cause an abort |
| 38840 | * but does at the moment, probably not worth fixing. |
| 38841 | */ |
| 38842 | if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) || |
| 38843 | DUK_HOBJECT_IS_PROXY(obj)) { |
| 38844 | DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path" )); |
| 38845 | goto abort_fastpath; |
| 38846 | } |
| 38847 | |
| 38848 | /* We could use a switch-case for the class number but it turns out |
| 38849 | * a small if-else ladder on class masks is better. The if-ladder |
| 38850 | * should be in order of relevancy. |
| 38851 | */ |
| 38852 | |
| 38853 | /* XXX: move masks to js_ctx? they don't change during one |
| 38854 | * fast path invocation. |
| 38855 | */ |
| 38856 | DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31); |
| 38857 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 38858 | if (js_ctx->flag_ext_custom_or_compatible) { |
| 38859 | c_all = DUK_HOBJECT_CMASK_ALL; |
| 38860 | c_array = DUK_HOBJECT_CMASK_ARRAY; |
| 38861 | c_unbox = DUK_HOBJECT_CMASK_NUMBER | |
| 38862 | DUK_HOBJECT_CMASK_STRING | |
| 38863 | DUK_HOBJECT_CMASK_BOOLEAN | |
| 38864 | DUK_HOBJECT_CMASK_POINTER; /* Symbols are not unboxed. */ |
| 38865 | c_func = DUK_HOBJECT_CMASK_FUNCTION; |
| 38866 | c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS; |
| 38867 | c_undef = 0; |
| 38868 | c_abort = 0; |
| 38869 | c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort); |
| 38870 | } |
| 38871 | else |
| 38872 | #endif |
| 38873 | { |
| 38874 | c_all = DUK_HOBJECT_CMASK_ALL; |
| 38875 | c_array = DUK_HOBJECT_CMASK_ARRAY; |
| 38876 | c_unbox = DUK_HOBJECT_CMASK_NUMBER | |
| 38877 | DUK_HOBJECT_CMASK_STRING | |
| 38878 | DUK_HOBJECT_CMASK_BOOLEAN; /* Symbols are not unboxed. */ |
| 38879 | c_func = 0; |
| 38880 | c_bufobj = 0; |
| 38881 | c_undef = DUK_HOBJECT_CMASK_FUNCTION | |
| 38882 | DUK_HOBJECT_CMASK_POINTER; |
| 38883 | /* As the fast path doesn't currently properly support |
| 38884 | * duk_hbufobj virtual properties, abort fast path if |
| 38885 | * we encounter them in plain JSON mode. |
| 38886 | */ |
| 38887 | c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS; |
| 38888 | c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort); |
| 38889 | } |
| 38890 | |
| 38891 | c_bit = (duk_uint32_t) DUK_HOBJECT_GET_CLASS_MASK(obj); |
| 38892 | if (c_bit & c_object) { |
| 38893 | /* All other object types. */ |
| 38894 | DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY); |
| 38895 | |
| 38896 | /* A non-Array object should not have an array part in practice. |
| 38897 | * But since it is supported internally (and perhaps used at some |
| 38898 | * point), check and abandon if that's the case. |
| 38899 | */ |
| 38900 | if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) { |
| 38901 | DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path" )); |
| 38902 | goto abort_fastpath; |
| 38903 | } |
| 38904 | |
| 38905 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 38906 | duk_hstring *k; |
| 38907 | duk_size_t prev_size; |
| 38908 | |
| 38909 | k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i); |
| 38910 | if (!k) { |
| 38911 | continue; |
| 38912 | } |
| 38913 | if (DUK_HSTRING_HAS_ARRIDX(k)) { |
| 38914 | /* If an object has array index keys we would need |
| 38915 | * to sort them into the ES2015 enumeration order to |
| 38916 | * be consistent with the slow path. Abort the fast |
| 38917 | * path and handle in the slow path for now. |
| 38918 | */ |
| 38919 | DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path" )); |
| 38920 | goto abort_fastpath; |
| 38921 | } |
| 38922 | if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) { |
| 38923 | continue; |
| 38924 | } |
| 38925 | if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) { |
| 38926 | /* Getter might have arbitrary side effects, |
| 38927 | * so bail out. |
| 38928 | */ |
| 38929 | DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path" )); |
| 38930 | goto abort_fastpath; |
| 38931 | } |
| 38932 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { |
| 38933 | continue; |
| 38934 | } |
| 38935 | |
| 38936 | tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i); |
| 38937 | |
| 38938 | prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw); |
| 38939 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38940 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth); |
| 38941 | duk__json_enc_key_autoquote(js_ctx, k); |
| 38942 | DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE); |
| 38943 | } else { |
| 38944 | duk__json_enc_key_autoquote(js_ctx, k); |
| 38945 | DUK__EMIT_1(js_ctx, DUK_ASC_COLON); |
| 38946 | } |
| 38947 | |
| 38948 | if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) { |
| 38949 | DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon" )); |
| 38950 | DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size); |
| 38951 | } else { |
| 38952 | DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); |
| 38953 | emitted = 1; |
| 38954 | } |
| 38955 | } |
| 38956 | |
| 38957 | /* If any non-Array value had enumerable virtual own |
| 38958 | * properties, they should be serialized here (actually, |
| 38959 | * before the explicit properties). Standard types don't. |
| 38960 | */ |
| 38961 | |
| 38962 | if (emitted) { |
| 38963 | DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); |
| 38964 | DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ |
| 38965 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38966 | DUK_ASSERT(js_ctx->recursion_depth >= 1); |
| 38967 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); |
| 38968 | } |
| 38969 | } |
| 38970 | DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY); |
| 38971 | } else if (c_bit & c_array) { |
| 38972 | duk_uint_fast32_t arr_len; |
| 38973 | duk_uint_fast32_t asize; |
| 38974 | |
| 38975 | DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET); |
| 38976 | |
| 38977 | /* Assume arrays are dense in the fast path. */ |
| 38978 | if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) { |
| 38979 | DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path" )); |
| 38980 | goto abort_fastpath; |
| 38981 | } |
| 38982 | |
| 38983 | arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length; |
| 38984 | asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj); |
| 38985 | /* Array part may be larger than 'length'; if so, iterate |
| 38986 | * only up to array 'length'. Array part may also be smaller |
| 38987 | * than 'length' in some cases. |
| 38988 | */ |
| 38989 | for (i = 0; i < arr_len; i++) { |
| 38990 | duk_tval *tv_arrval; |
| 38991 | duk_hstring *h_tmp; |
| 38992 | duk_bool_t has_inherited; |
| 38993 | |
| 38994 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 38995 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth); |
| 38996 | } |
| 38997 | |
| 38998 | if (DUK_LIKELY(i < asize)) { |
| 38999 | tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i); |
| 39000 | if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) { |
| 39001 | /* Expected case: element is present. */ |
| 39002 | if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) { |
| 39003 | DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); |
| 39004 | } |
| 39005 | goto elem_done; |
| 39006 | } |
| 39007 | } |
| 39008 | |
| 39009 | /* Gap in array; check for inherited property, |
| 39010 | * bail out if one exists. This should be enough |
| 39011 | * to support gappy arrays for all practical code. |
| 39012 | */ |
| 39013 | |
| 39014 | h_tmp = duk_push_uint_to_hstring(js_ctx->thr, (duk_uint_t) i); |
| 39015 | has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp); |
| 39016 | duk_pop(js_ctx->thr); |
| 39017 | if (has_inherited) { |
| 39018 | DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path" )); |
| 39019 | goto abort_fastpath; |
| 39020 | } |
| 39021 | |
| 39022 | /* Ordinary gap, undefined encodes to 'null' in |
| 39023 | * standard JSON, but JX/JC use their form for |
| 39024 | * undefined to better preserve the typing. |
| 39025 | */ |
| 39026 | DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path" )); |
| 39027 | #if defined(DUK_USE_JX) |
| 39028 | DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined); |
| 39029 | #else |
| 39030 | DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL); |
| 39031 | #endif |
| 39032 | /* fall through */ |
| 39033 | |
| 39034 | elem_done: |
| 39035 | DUK__EMIT_1(js_ctx, DUK_ASC_COMMA); |
| 39036 | emitted = 1; |
| 39037 | } |
| 39038 | |
| 39039 | if (emitted) { |
| 39040 | DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA); |
| 39041 | DUK__UNEMIT_1(js_ctx); /* eat trailing comma */ |
| 39042 | if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) { |
| 39043 | DUK_ASSERT(js_ctx->recursion_depth >= 1); |
| 39044 | duk__json_enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U); |
| 39045 | } |
| 39046 | } |
| 39047 | DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET); |
| 39048 | } else if (c_bit & c_unbox) { |
| 39049 | /* Certain boxed types are required to go through |
| 39050 | * automatic unboxing. Rely on internal value being |
| 39051 | * sane (to avoid infinite recursion). |
| 39052 | */ |
| 39053 | DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0); /* Symbols are not unboxed. */ |
| 39054 | |
| 39055 | #if 1 |
| 39056 | /* The code below is incorrect if .toString() or .valueOf() have |
| 39057 | * have been overridden. The correct approach would be to look up |
| 39058 | * the method(s) and if they resolve to the built-in function we |
| 39059 | * can safely bypass it and look up the internal value directly. |
| 39060 | * Unimplemented for now, abort fast path for boxed values. |
| 39061 | */ |
| 39062 | goto abort_fastpath; |
| 39063 | #else /* disabled */ |
| 39064 | /* Disabled until fixed, see above. */ |
| 39065 | duk_tval *tv_internal; |
| 39066 | |
| 39067 | DUK_DD(DUK_DDPRINT("auto unboxing in fast path" )); |
| 39068 | |
| 39069 | tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj); |
| 39070 | DUK_ASSERT(tv_internal != NULL); |
| 39071 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) || |
| 39072 | DUK_TVAL_IS_NUMBER(tv_internal) || |
| 39073 | DUK_TVAL_IS_BOOLEAN(tv_internal) || |
| 39074 | DUK_TVAL_IS_POINTER(tv_internal)); |
| 39075 | |
| 39076 | tv = tv_internal; |
| 39077 | DUK_ASSERT(js_ctx->recursion_depth > 0); |
| 39078 | js_ctx->recursion_depth--; /* required to keep recursion depth correct */ |
| 39079 | goto restart_match; |
| 39080 | #endif /* disabled */ |
| 39081 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 39082 | } else if (c_bit & c_func) { |
| 39083 | DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function); |
| 39084 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 39085 | } else if (c_bit & c_bufobj) { |
| 39086 | duk__json_enc_bufobj(js_ctx, (duk_hbufobj *) obj); |
| 39087 | #endif |
| 39088 | #endif |
| 39089 | } else if (c_bit & c_abort) { |
| 39090 | DUK_DD(DUK_DDPRINT("abort fast path for unsupported type" )); |
| 39091 | goto abort_fastpath; |
| 39092 | } else { |
| 39093 | DUK_ASSERT((c_bit & c_undef) != 0); |
| 39094 | |
| 39095 | /* Must decrease recursion depth before returning. */ |
| 39096 | DUK_ASSERT(js_ctx->recursion_depth > 0); |
| 39097 | DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); |
| 39098 | js_ctx->recursion_depth--; |
| 39099 | goto emit_undefined; |
| 39100 | } |
| 39101 | |
| 39102 | DUK_ASSERT(js_ctx->recursion_depth > 0); |
| 39103 | DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit); |
| 39104 | js_ctx->recursion_depth--; |
| 39105 | break; |
| 39106 | } |
| 39107 | case DUK_TAG_BUFFER: { |
| 39108 | /* Plain buffers are treated like Uint8Arrays: they have |
| 39109 | * enumerable indices. Other virtual properties are not |
| 39110 | * enumerable, and inherited properties are not serialized. |
| 39111 | * However, there can be a replacer (not relevant here) or |
| 39112 | * a .toJSON() method (which we need to check for explicitly). |
| 39113 | */ |
| 39114 | |
| 39115 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 39116 | if (duk_hobject_hasprop_raw(js_ctx->thr, |
| 39117 | js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE], |
| 39118 | DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) { |
| 39119 | DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path" )); |
| 39120 | goto abort_fastpath; |
| 39121 | } |
| 39122 | #endif |
| 39123 | |
| 39124 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 39125 | if (js_ctx->flag_ext_custom_or_compatible) { |
| 39126 | duk__json_enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv)); |
| 39127 | break; |
| 39128 | } |
| 39129 | #endif |
| 39130 | |
| 39131 | /* Plain buffers mimic Uint8Arrays, and have enumerable index |
| 39132 | * properties. |
| 39133 | */ |
| 39134 | duk__json_enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv)); |
| 39135 | break; |
| 39136 | } |
| 39137 | case DUK_TAG_POINTER: { |
| 39138 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 39139 | if (js_ctx->flag_ext_custom_or_compatible) { |
| 39140 | duk__json_enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv)); |
| 39141 | break; |
| 39142 | } else { |
| 39143 | goto emit_undefined; |
| 39144 | } |
| 39145 | #else |
| 39146 | goto emit_undefined; |
| 39147 | #endif |
| 39148 | } |
| 39149 | case DUK_TAG_LIGHTFUNC: { |
| 39150 | /* A lightfunc might also inherit a .toJSON() so just bail out. */ |
| 39151 | /* XXX: Could just lookup .toJSON() and continue in fast path, |
| 39152 | * as it would almost never be defined. |
| 39153 | */ |
| 39154 | DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path" )); |
| 39155 | goto abort_fastpath; |
| 39156 | } |
| 39157 | #if defined(DUK_USE_FASTINT) |
| 39158 | case DUK_TAG_FASTINT: { |
| 39159 | /* Number serialization has a significant impact relative to |
| 39160 | * other fast path code, so careful fast path for fastints. |
| 39161 | */ |
| 39162 | duk__json_enc_fastint_tval(js_ctx, tv); |
| 39163 | break; |
| 39164 | } |
| 39165 | #endif |
| 39166 | default: { |
| 39167 | /* XXX: A fast path for usual integers would be useful when |
| 39168 | * fastint support is not enabled. |
| 39169 | */ |
| 39170 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 39171 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 39172 | |
| 39173 | /* XXX: Stack discipline is annoying, could be changed in numconv. */ |
| 39174 | duk_push_tval(js_ctx->thr, tv); |
| 39175 | duk__json_enc_double(js_ctx); |
| 39176 | duk_pop(js_ctx->thr); |
| 39177 | |
| 39178 | #if 0 |
| 39179 | /* Could also rely on native sprintf(), but it will handle |
| 39180 | * values like NaN, Infinity, -0, exponent notation etc in |
| 39181 | * a JSON-incompatible way. |
| 39182 | */ |
| 39183 | duk_double_t d; |
| 39184 | char buf[64]; |
| 39185 | |
| 39186 | DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); |
| 39187 | d = DUK_TVAL_GET_DOUBLE(tv); |
| 39188 | DUK_SPRINTF(buf, "%lg" , d); |
| 39189 | DUK__EMIT_CSTR(js_ctx, buf); |
| 39190 | #endif |
| 39191 | } |
| 39192 | } |
| 39193 | return 1; /* not undefined */ |
| 39194 | |
| 39195 | emit_undefined: |
| 39196 | return 0; /* value was undefined/unsupported */ |
| 39197 | |
| 39198 | abort_fastpath: |
| 39199 | /* Error message doesn't matter: the error is ignored anyway. */ |
| 39200 | DUK_DD(DUK_DDPRINT("aborting fast path" )); |
| 39201 | DUK_ERROR_INTERNAL(js_ctx->thr); |
| 39202 | DUK_WO_NORETURN(return 0;); |
| 39203 | } |
| 39204 | |
| 39205 | DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) { |
| 39206 | duk_json_enc_ctx *js_ctx; |
| 39207 | duk_tval *tv; |
| 39208 | |
| 39209 | DUK_ASSERT(thr != NULL); |
| 39210 | DUK_ASSERT(udata != NULL); |
| 39211 | |
| 39212 | js_ctx = (duk_json_enc_ctx *) udata; |
| 39213 | DUK_ASSERT(js_ctx != NULL); |
| 39214 | |
| 39215 | tv = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 39216 | if (duk__json_stringify_fast_value(js_ctx, tv) == 0) { |
| 39217 | DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path" )); |
| 39218 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* Error message is ignored, so doesn't matter. */ |
| 39219 | } |
| 39220 | |
| 39221 | return 0; |
| 39222 | } |
| 39223 | #endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */ |
| 39224 | |
| 39225 | /* |
| 39226 | * Top level wrappers |
| 39227 | */ |
| 39228 | |
| 39229 | DUK_INTERNAL |
| 39230 | void duk_bi_json_parse_helper(duk_hthread *thr, |
| 39231 | duk_idx_t idx_value, |
| 39232 | duk_idx_t idx_reviver, |
| 39233 | duk_small_uint_t flags) { |
| 39234 | duk_json_dec_ctx js_ctx_alloc; |
| 39235 | duk_json_dec_ctx *js_ctx = &js_ctx_alloc; |
| 39236 | duk_hstring *h_text; |
| 39237 | #if defined(DUK_USE_ASSERTIONS) |
| 39238 | duk_idx_t entry_top = duk_get_top(thr); |
| 39239 | #endif |
| 39240 | |
| 39241 | /* negative top-relative indices not allowed now */ |
| 39242 | DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0); |
| 39243 | DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0); |
| 39244 | |
| 39245 | DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld" , |
| 39246 | (duk_tval *) duk_get_tval(thr, idx_value), |
| 39247 | (duk_tval *) duk_get_tval(thr, idx_reviver), |
| 39248 | (unsigned long) flags, |
| 39249 | (long) duk_get_top(thr))); |
| 39250 | |
| 39251 | duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc)); |
| 39252 | js_ctx->thr = thr; |
| 39253 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 39254 | /* nothing now */ |
| 39255 | #endif |
| 39256 | js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT; |
| 39257 | DUK_ASSERT(js_ctx->recursion_depth == 0); |
| 39258 | |
| 39259 | /* Flag handling currently assumes that flags are consistent. This is OK |
| 39260 | * because the call sites are now strictly controlled. |
| 39261 | */ |
| 39262 | |
| 39263 | js_ctx->flags = flags; |
| 39264 | #if defined(DUK_USE_JX) |
| 39265 | js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM; |
| 39266 | #endif |
| 39267 | #if defined(DUK_USE_JC) |
| 39268 | js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; |
| 39269 | #endif |
| 39270 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 39271 | js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); |
| 39272 | #endif |
| 39273 | |
| 39274 | h_text = duk_to_hstring(thr, idx_value); /* coerce in-place; rejects Symbols */ |
| 39275 | DUK_ASSERT(h_text != NULL); |
| 39276 | |
| 39277 | /* JSON parsing code is allowed to read [p_start,p_end]: p_end is |
| 39278 | * valid and points to the string NUL terminator (which is always |
| 39279 | * guaranteed for duk_hstrings. |
| 39280 | */ |
| 39281 | js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text); |
| 39282 | js_ctx->p = js_ctx->p_start; |
| 39283 | js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) + |
| 39284 | DUK_HSTRING_GET_BYTELEN(h_text); |
| 39285 | DUK_ASSERT(*(js_ctx->p_end) == 0x00); |
| 39286 | |
| 39287 | duk__json_dec_value(js_ctx); /* -> [ ... value ] */ |
| 39288 | DUK_ASSERT(js_ctx->recursion_depth == 0); |
| 39289 | |
| 39290 | /* Trailing whitespace has been eaten by duk__json_dec_value(), so if |
| 39291 | * we're not at end of input here, it's a SyntaxError. |
| 39292 | */ |
| 39293 | |
| 39294 | if (js_ctx->p != js_ctx->p_end) { |
| 39295 | duk__json_dec_syntax_error(js_ctx); |
| 39296 | } |
| 39297 | |
| 39298 | if (duk_is_callable(thr, idx_reviver)) { |
| 39299 | DUK_DDD(DUK_DDDPRINT("applying reviver: %!T" , |
| 39300 | (duk_tval *) duk_get_tval(thr, idx_reviver))); |
| 39301 | |
| 39302 | js_ctx->idx_reviver = idx_reviver; |
| 39303 | |
| 39304 | duk_push_object(thr); |
| 39305 | duk_dup_m2(thr); /* -> [ ... val root val ] */ |
| 39306 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */ |
| 39307 | duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */ |
| 39308 | |
| 39309 | DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T" , |
| 39310 | (duk_tval *) duk_get_tval(thr, -2), |
| 39311 | (duk_tval *) duk_get_tval(thr, -1))); |
| 39312 | |
| 39313 | DUK_ASSERT(js_ctx->recursion_depth == 0); |
| 39314 | duk__json_dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */ |
| 39315 | DUK_ASSERT(js_ctx->recursion_depth == 0); |
| 39316 | duk_remove_m2(thr); /* -> [ ... val' ] */ |
| 39317 | } else { |
| 39318 | DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T" , |
| 39319 | (duk_tval *) duk_get_tval(thr, idx_reviver))); |
| 39320 | } |
| 39321 | |
| 39322 | /* Final result is at stack top. */ |
| 39323 | |
| 39324 | DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld" , |
| 39325 | (duk_tval *) duk_get_tval(thr, idx_value), |
| 39326 | (duk_tval *) duk_get_tval(thr, idx_reviver), |
| 39327 | (unsigned long) flags, |
| 39328 | (duk_tval *) duk_get_tval(thr, -1), |
| 39329 | (long) duk_get_top(thr))); |
| 39330 | |
| 39331 | DUK_ASSERT(duk_get_top(thr) == entry_top + 1); |
| 39332 | } |
| 39333 | |
| 39334 | DUK_INTERNAL |
| 39335 | void duk_bi_json_stringify_helper(duk_hthread *thr, |
| 39336 | duk_idx_t idx_value, |
| 39337 | duk_idx_t idx_replacer, |
| 39338 | duk_idx_t idx_space, |
| 39339 | duk_small_uint_t flags) { |
| 39340 | duk_json_enc_ctx js_ctx_alloc; |
| 39341 | duk_json_enc_ctx *js_ctx = &js_ctx_alloc; |
| 39342 | duk_hobject *h; |
| 39343 | duk_idx_t idx_holder; |
| 39344 | duk_idx_t entry_top; |
| 39345 | |
| 39346 | /* negative top-relative indices not allowed now */ |
| 39347 | DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0); |
| 39348 | DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0); |
| 39349 | DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0); |
| 39350 | |
| 39351 | DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld" , |
| 39352 | (duk_tval *) duk_get_tval(thr, idx_value), |
| 39353 | (duk_tval *) duk_get_tval(thr, idx_replacer), |
| 39354 | (duk_tval *) duk_get_tval(thr, idx_space), |
| 39355 | (unsigned long) flags, |
| 39356 | (long) duk_get_top(thr))); |
| 39357 | |
| 39358 | entry_top = duk_get_top(thr); |
| 39359 | |
| 39360 | /* |
| 39361 | * Context init |
| 39362 | */ |
| 39363 | |
| 39364 | duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc)); |
| 39365 | js_ctx->thr = thr; |
| 39366 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 39367 | js_ctx->h_replacer = NULL; |
| 39368 | js_ctx->h_gap = NULL; |
| 39369 | #endif |
| 39370 | js_ctx->idx_proplist = -1; |
| 39371 | |
| 39372 | /* Flag handling currently assumes that flags are consistent. This is OK |
| 39373 | * because the call sites are now strictly controlled. |
| 39374 | */ |
| 39375 | |
| 39376 | js_ctx->flags = flags; |
| 39377 | js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY; |
| 39378 | js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES; |
| 39379 | #if defined(DUK_USE_JX) |
| 39380 | js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM; |
| 39381 | #endif |
| 39382 | #if defined(DUK_USE_JC) |
| 39383 | js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE; |
| 39384 | #endif |
| 39385 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 39386 | js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE); |
| 39387 | #endif |
| 39388 | |
| 39389 | /* The #if defined() clutter here handles the JX/JC enable/disable |
| 39390 | * combinations properly. |
| 39391 | */ |
| 39392 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 39393 | js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */ |
| 39394 | #if defined(DUK_USE_JX) |
| 39395 | if (flags & DUK_JSON_FLAG_EXT_CUSTOM) { |
| 39396 | js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED; |
| 39397 | js_ctx->stridx_custom_nan = DUK_STRIDX_NAN; |
| 39398 | js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY; |
| 39399 | js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY; |
| 39400 | js_ctx->stridx_custom_function = |
| 39401 | (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ? |
| 39402 | DUK_STRIDX_JSON_EXT_FUNCTION2 : |
| 39403 | DUK_STRIDX_JSON_EXT_FUNCTION1; |
| 39404 | } |
| 39405 | #endif /* DUK_USE_JX */ |
| 39406 | #if defined(DUK_USE_JX) && defined(DUK_USE_JC) |
| 39407 | else |
| 39408 | #endif /* DUK_USE_JX && DUK_USE_JC */ |
| 39409 | #if defined(DUK_USE_JC) |
| 39410 | if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) { |
| 39411 | js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED; |
| 39412 | js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN; |
| 39413 | js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF; |
| 39414 | js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF; |
| 39415 | js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1; |
| 39416 | } |
| 39417 | #endif /* DUK_USE_JC */ |
| 39418 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 39419 | |
| 39420 | #if defined(DUK_USE_JX) || defined(DUK_USE_JC) |
| 39421 | if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | |
| 39422 | DUK_JSON_FLAG_EXT_COMPATIBLE)) { |
| 39423 | DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */ |
| 39424 | } |
| 39425 | else |
| 39426 | #endif /* DUK_USE_JX || DUK_USE_JC */ |
| 39427 | { |
| 39428 | /* Plain buffer is treated like ArrayBuffer and serialized. |
| 39429 | * Lightfuncs are treated like objects, but JSON explicitly |
| 39430 | * skips serializing Function objects so we can just reject |
| 39431 | * lightfuncs here. |
| 39432 | */ |
| 39433 | js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED | |
| 39434 | DUK_TYPE_MASK_POINTER | |
| 39435 | DUK_TYPE_MASK_LIGHTFUNC; |
| 39436 | } |
| 39437 | |
| 39438 | DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE); |
| 39439 | |
| 39440 | js_ctx->idx_loop = duk_push_bare_object(thr); |
| 39441 | DUK_ASSERT(js_ctx->idx_loop >= 0); |
| 39442 | |
| 39443 | /* [ ... buf loop ] */ |
| 39444 | |
| 39445 | /* |
| 39446 | * Process replacer/proplist (2nd argument to JSON.stringify) |
| 39447 | */ |
| 39448 | |
| 39449 | h = duk_get_hobject(thr, idx_replacer); |
| 39450 | if (h != NULL) { |
| 39451 | if (DUK_HOBJECT_IS_CALLABLE(h)) { |
| 39452 | js_ctx->h_replacer = h; |
| 39453 | } else if (duk_js_isarray_hobject(h)) { |
| 39454 | /* Here the specification requires correct array index enumeration |
| 39455 | * which is a bit tricky for sparse arrays (it is handled by the |
| 39456 | * enum setup code). We now enumerate ancestors too, although the |
| 39457 | * specification is not very clear on whether that is required. |
| 39458 | */ |
| 39459 | |
| 39460 | duk_uarridx_t plist_idx = 0; |
| 39461 | duk_small_uint_t enum_flags; |
| 39462 | |
| 39463 | js_ctx->idx_proplist = duk_push_bare_array(thr); |
| 39464 | |
| 39465 | enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY | |
| 39466 | DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */ |
| 39467 | duk_enum(thr, idx_replacer, enum_flags); |
| 39468 | while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) { |
| 39469 | /* [ ... proplist enum_obj key val ] */ |
| 39470 | if (duk__json_enc_allow_into_proplist(duk_get_tval(thr, -1))) { |
| 39471 | /* XXX: duplicates should be eliminated here */ |
| 39472 | DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept" , |
| 39473 | (duk_tval *) duk_get_tval(thr, -2), |
| 39474 | (duk_tval *) duk_get_tval(thr, -1))); |
| 39475 | duk_to_string(thr, -1); /* extra coercion of strings is OK */ |
| 39476 | duk_put_prop_index(thr, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */ |
| 39477 | plist_idx++; |
| 39478 | duk_pop(thr); |
| 39479 | } else { |
| 39480 | DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject" , |
| 39481 | (duk_tval *) duk_get_tval(thr, -2), |
| 39482 | (duk_tval *) duk_get_tval(thr, -1))); |
| 39483 | duk_pop_2(thr); |
| 39484 | } |
| 39485 | } |
| 39486 | duk_pop(thr); /* pop enum */ |
| 39487 | |
| 39488 | /* [ ... proplist ] */ |
| 39489 | } |
| 39490 | } |
| 39491 | |
| 39492 | /* [ ... buf loop (proplist) ] */ |
| 39493 | |
| 39494 | /* |
| 39495 | * Process space (3rd argument to JSON.stringify) |
| 39496 | */ |
| 39497 | |
| 39498 | h = duk_get_hobject(thr, idx_space); |
| 39499 | if (h != NULL) { |
| 39500 | duk_small_uint_t c = DUK_HOBJECT_GET_CLASS_NUMBER(h); |
| 39501 | if (c == DUK_HOBJECT_CLASS_NUMBER) { |
| 39502 | duk_to_number(thr, idx_space); |
| 39503 | } else if (c == DUK_HOBJECT_CLASS_STRING) { |
| 39504 | duk_to_string(thr, idx_space); |
| 39505 | } |
| 39506 | } |
| 39507 | |
| 39508 | if (duk_is_number(thr, idx_space)) { |
| 39509 | duk_small_int_t nspace; |
| 39510 | /* spaces[] must be static to allow initializer with old compilers like BCC */ |
| 39511 | static const char spaces[10] = { |
| 39512 | DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, |
| 39513 | DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, |
| 39514 | DUK_ASC_SPACE, DUK_ASC_SPACE |
| 39515 | }; /* XXX: helper */ |
| 39516 | |
| 39517 | /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */ |
| 39518 | nspace = (duk_small_int_t) duk_to_int_clamped(thr, idx_space, 0 /*minval*/, 10 /*maxval*/); |
| 39519 | DUK_ASSERT(nspace >= 0 && nspace <= 10); |
| 39520 | |
| 39521 | duk_push_lstring(thr, spaces, (duk_size_t) nspace); |
| 39522 | js_ctx->h_gap = duk_known_hstring(thr, -1); |
| 39523 | DUK_ASSERT(js_ctx->h_gap != NULL); |
| 39524 | } else if (duk_is_string_notsymbol(thr, idx_space)) { |
| 39525 | duk_dup(thr, idx_space); |
| 39526 | duk_substring(thr, -1, 0, 10); /* clamp to 10 chars */ |
| 39527 | js_ctx->h_gap = duk_known_hstring(thr, -1); |
| 39528 | } else { |
| 39529 | /* nop */ |
| 39530 | } |
| 39531 | |
| 39532 | if (js_ctx->h_gap != NULL) { |
| 39533 | /* If gap is empty, behave as if not given at all. Check |
| 39534 | * against byte length because character length is more |
| 39535 | * expensive. |
| 39536 | */ |
| 39537 | if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) { |
| 39538 | js_ctx->h_gap = NULL; |
| 39539 | } |
| 39540 | } |
| 39541 | |
| 39542 | /* [ ... buf loop (proplist) (gap) ] */ |
| 39543 | |
| 39544 | /* |
| 39545 | * Fast path: assume no mutation, iterate object property tables |
| 39546 | * directly; bail out if that assumption doesn't hold. |
| 39547 | */ |
| 39548 | |
| 39549 | #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) |
| 39550 | if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */ |
| 39551 | js_ctx->idx_proplist == -1) { /* proplist is very rare */ |
| 39552 | duk_int_t pcall_rc; |
| 39553 | duk_small_uint_t prev_ms_base_flags; |
| 39554 | |
| 39555 | DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path" )); |
| 39556 | |
| 39557 | /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[] |
| 39558 | * array so we don't need two counter checks in the fast path. The |
| 39559 | * slow path has a much larger recursion limit which we'll use if |
| 39560 | * necessary. |
| 39561 | */ |
| 39562 | DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY); |
| 39563 | js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY; |
| 39564 | DUK_ASSERT(js_ctx->recursion_depth == 0); |
| 39565 | |
| 39566 | /* Execute the fast path in a protected call. If any error is thrown, |
| 39567 | * fall back to the slow path. This includes e.g. recursion limit |
| 39568 | * because the fast path has a smaller recursion limit (and simpler, |
| 39569 | * limited loop detection). |
| 39570 | */ |
| 39571 | |
| 39572 | duk_dup(thr, idx_value); |
| 39573 | |
| 39574 | /* Must prevent finalizers which may have arbitrary side effects. */ |
| 39575 | prev_ms_base_flags = thr->heap->ms_base_flags; |
| 39576 | thr->heap->ms_base_flags |= |
| 39577 | DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact any objects. */ |
| 39578 | thr->heap->pf_prevent_count++; /* Prevent finalizers. */ |
| 39579 | DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ |
| 39580 | |
| 39581 | pcall_rc = duk_safe_call(thr, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/); |
| 39582 | |
| 39583 | DUK_ASSERT(thr->heap->pf_prevent_count > 0); |
| 39584 | thr->heap->pf_prevent_count--; |
| 39585 | thr->heap->ms_base_flags = prev_ms_base_flags; |
| 39586 | |
| 39587 | if (pcall_rc == DUK_EXEC_SUCCESS) { |
| 39588 | DUK_DD(DUK_DDPRINT("fast path successful" )); |
| 39589 | DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); |
| 39590 | goto replace_finished; |
| 39591 | } |
| 39592 | |
| 39593 | /* We come here for actual aborts (like encountering .toJSON()) |
| 39594 | * but also for recursion/loop errors. Bufwriter size can be |
| 39595 | * kept because we'll probably need at least as much as we've |
| 39596 | * allocated so far. |
| 39597 | */ |
| 39598 | DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead" )); |
| 39599 | DUK_BW_RESET_SIZE(thr, &js_ctx->bw); |
| 39600 | js_ctx->recursion_depth = 0; |
| 39601 | } |
| 39602 | #endif |
| 39603 | |
| 39604 | /* |
| 39605 | * Create wrapper object and serialize |
| 39606 | */ |
| 39607 | |
| 39608 | idx_holder = duk_push_object(thr); |
| 39609 | duk_dup(thr, idx_value); |
| 39610 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING); |
| 39611 | |
| 39612 | DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, " |
| 39613 | "proplist=%!T, gap=%!O, holder=%!T" , |
| 39614 | (unsigned long) js_ctx->flags, |
| 39615 | (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop), |
| 39616 | (duk_heaphdr *) js_ctx->h_replacer, |
| 39617 | (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL), |
| 39618 | (duk_heaphdr *) js_ctx->h_gap, |
| 39619 | (duk_tval *) duk_get_tval(thr, -1))); |
| 39620 | |
| 39621 | /* serialize the wrapper with empty string key */ |
| 39622 | |
| 39623 | duk_push_hstring_empty(thr); |
| 39624 | |
| 39625 | /* [ ... buf loop (proplist) (gap) holder "" ] */ |
| 39626 | |
| 39627 | js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT; |
| 39628 | DUK_ASSERT(js_ctx->recursion_depth == 0); |
| 39629 | |
| 39630 | if (DUK_UNLIKELY(duk__json_enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */ |
| 39631 | /* Result is undefined. */ |
| 39632 | duk_push_undefined(thr); |
| 39633 | } else { |
| 39634 | /* Convert buffer to result string. */ |
| 39635 | DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw); |
| 39636 | } |
| 39637 | |
| 39638 | DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, " |
| 39639 | "proplist=%!T, gap=%!O, holder=%!T" , |
| 39640 | (unsigned long) js_ctx->flags, |
| 39641 | (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop), |
| 39642 | (duk_heaphdr *) js_ctx->h_replacer, |
| 39643 | (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL), |
| 39644 | (duk_heaphdr *) js_ctx->h_gap, |
| 39645 | (duk_tval *) duk_get_tval(thr, idx_holder))); |
| 39646 | |
| 39647 | /* The stack has a variable shape here, so force it to the |
| 39648 | * desired one explicitly. |
| 39649 | */ |
| 39650 | |
| 39651 | #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH) |
| 39652 | replace_finished: |
| 39653 | #endif |
| 39654 | duk_replace(thr, entry_top); |
| 39655 | duk_set_top(thr, entry_top + 1); |
| 39656 | |
| 39657 | DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, " |
| 39658 | "flags=0x%08lx, result=%!T, stack_top=%ld" , |
| 39659 | (duk_tval *) duk_get_tval(thr, idx_value), |
| 39660 | (duk_tval *) duk_get_tval(thr, idx_replacer), |
| 39661 | (duk_tval *) duk_get_tval(thr, idx_space), |
| 39662 | (unsigned long) flags, |
| 39663 | (duk_tval *) duk_get_tval(thr, -1), |
| 39664 | (long) duk_get_top(thr))); |
| 39665 | |
| 39666 | DUK_ASSERT(duk_get_top(thr) == entry_top + 1); |
| 39667 | } |
| 39668 | |
| 39669 | #if defined(DUK_USE_JSON_BUILTIN) |
| 39670 | |
| 39671 | /* |
| 39672 | * Entry points |
| 39673 | */ |
| 39674 | |
| 39675 | DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_hthread *thr) { |
| 39676 | duk_bi_json_parse_helper(thr, |
| 39677 | 0 /*idx_value*/, |
| 39678 | 1 /*idx_replacer*/, |
| 39679 | 0 /*flags*/); |
| 39680 | return 1; |
| 39681 | } |
| 39682 | |
| 39683 | DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_hthread *thr) { |
| 39684 | duk_bi_json_stringify_helper(thr, |
| 39685 | 0 /*idx_value*/, |
| 39686 | 1 /*idx_replacer*/, |
| 39687 | 2 /*idx_space*/, |
| 39688 | 0 /*flags*/); |
| 39689 | return 1; |
| 39690 | } |
| 39691 | |
| 39692 | #endif /* DUK_USE_JSON_BUILTIN */ |
| 39693 | |
| 39694 | #endif /* DUK_USE_JSON_SUPPORT */ |
| 39695 | |
| 39696 | /* automatic undefs */ |
| 39697 | #undef DUK__EMIT_1 |
| 39698 | #undef DUK__EMIT_2 |
| 39699 | #undef DUK__EMIT_CSTR |
| 39700 | #undef DUK__EMIT_HSTR |
| 39701 | #undef DUK__EMIT_STRIDX |
| 39702 | #undef DUK__JSON_DECSTR_BUFSIZE |
| 39703 | #undef DUK__JSON_DECSTR_CHUNKSIZE |
| 39704 | #undef DUK__JSON_ENCSTR_CHUNKSIZE |
| 39705 | #undef DUK__JSON_MAX_ESC_LEN |
| 39706 | #undef DUK__JSON_STRINGIFY_BUFSIZE |
| 39707 | #undef DUK__MKESC |
| 39708 | #undef DUK__UNEMIT_1 |
| 39709 | #line 1 "duk_bi_math.c" |
| 39710 | /* |
| 39711 | * Math built-ins |
| 39712 | */ |
| 39713 | |
| 39714 | /* #include duk_internal.h -> already included */ |
| 39715 | |
| 39716 | #if defined(DUK_USE_MATH_BUILTIN) |
| 39717 | |
| 39718 | /* |
| 39719 | * Use static helpers which can work with math.h functions matching |
| 39720 | * the following signatures. This is not portable if any of these math |
| 39721 | * functions is actually a macro. |
| 39722 | * |
| 39723 | * Typing here is intentionally 'double' wherever values interact with |
| 39724 | * the standard library APIs. |
| 39725 | */ |
| 39726 | |
| 39727 | typedef double (*duk__one_arg_func)(double); |
| 39728 | typedef double (*duk__two_arg_func)(double, double); |
| 39729 | |
| 39730 | DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk__two_arg_func min_max) { |
| 39731 | duk_idx_t n = duk_get_top(thr); |
| 39732 | duk_idx_t i; |
| 39733 | duk_double_t res = initial; |
| 39734 | duk_double_t t; |
| 39735 | |
| 39736 | /* |
| 39737 | * Note: fmax() does not match the E5 semantics. E5 requires |
| 39738 | * that if -any- input to Math.max() is a NaN, the result is a |
| 39739 | * NaN. fmax() will return a NaN only if -both- inputs are NaN. |
| 39740 | * Same applies to fmin(). |
| 39741 | * |
| 39742 | * Note: every input value must be coerced with ToNumber(), even |
| 39743 | * if we know the result will be a NaN anyway: ToNumber() may have |
| 39744 | * side effects for which even order of evaluation matters. |
| 39745 | */ |
| 39746 | |
| 39747 | for (i = 0; i < n; i++) { |
| 39748 | t = duk_to_number(thr, i); |
| 39749 | if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) { |
| 39750 | /* Note: not normalized, but duk_push_number() will normalize */ |
| 39751 | res = (duk_double_t) DUK_DOUBLE_NAN; |
| 39752 | } else { |
| 39753 | res = (duk_double_t) min_max(res, (double) t); |
| 39754 | } |
| 39755 | } |
| 39756 | |
| 39757 | duk_push_number(thr, res); |
| 39758 | return 1; |
| 39759 | } |
| 39760 | |
| 39761 | DUK_LOCAL double duk__fmin_fixed(double x, double y) { |
| 39762 | /* fmin() with args -0 and +0 is not guaranteed to return |
| 39763 | * -0 as ECMAScript requires. |
| 39764 | */ |
| 39765 | if (duk_double_equals(x, 0.0) && duk_double_equals(y, 0.0)) { |
| 39766 | duk_double_union du1, du2; |
| 39767 | du1.d = x; |
| 39768 | du2.d = y; |
| 39769 | |
| 39770 | /* Already checked to be zero so these must hold, and allow us |
| 39771 | * to check for "x is -0 or y is -0" by ORing the high parts |
| 39772 | * for comparison. |
| 39773 | */ |
| 39774 | DUK_ASSERT(du1.ui[DUK_DBL_IDX_UI0] == 0 || du1.ui[DUK_DBL_IDX_UI0] == 0x80000000UL); |
| 39775 | DUK_ASSERT(du2.ui[DUK_DBL_IDX_UI0] == 0 || du2.ui[DUK_DBL_IDX_UI0] == 0x80000000UL); |
| 39776 | |
| 39777 | /* XXX: what's the safest way of creating a negative zero? */ |
| 39778 | if ((du1.ui[DUK_DBL_IDX_UI0] | du2.ui[DUK_DBL_IDX_UI0]) != 0) { |
| 39779 | /* Enter here if either x or y (or both) is -0. */ |
| 39780 | return -0.0; |
| 39781 | } else { |
| 39782 | return +0.0; |
| 39783 | } |
| 39784 | } |
| 39785 | return duk_double_fmin(x, y); |
| 39786 | } |
| 39787 | |
| 39788 | DUK_LOCAL double duk__fmax_fixed(double x, double y) { |
| 39789 | /* fmax() with args -0 and +0 is not guaranteed to return |
| 39790 | * +0 as ECMAScript requires. |
| 39791 | */ |
| 39792 | if (duk_double_equals(x, 0.0) && duk_double_equals(y, 0.0)) { |
| 39793 | if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) { |
| 39794 | return +0.0; |
| 39795 | } else { |
| 39796 | return -0.0; |
| 39797 | } |
| 39798 | } |
| 39799 | return duk_double_fmax(x, y); |
| 39800 | } |
| 39801 | |
| 39802 | #if defined(DUK_USE_ES6) |
| 39803 | DUK_LOCAL double duk__cbrt(double x) { |
| 39804 | /* cbrt() is C99. To avoid hassling embedders with the need to provide a |
| 39805 | * cube root function, we can get by with pow(). The result is not |
| 39806 | * identical, but that's OK: ES2015 says it's implementation-dependent. |
| 39807 | */ |
| 39808 | |
| 39809 | #if defined(DUK_CBRT) |
| 39810 | /* cbrt() matches ES2015 requirements. */ |
| 39811 | return DUK_CBRT(x); |
| 39812 | #else |
| 39813 | duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 39814 | |
| 39815 | /* pow() does not, however. */ |
| 39816 | if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) { |
| 39817 | return x; |
| 39818 | } |
| 39819 | if (DUK_SIGNBIT(x)) { |
| 39820 | return -DUK_POW(-x, 1.0 / 3.0); |
| 39821 | } else { |
| 39822 | return DUK_POW(x, 1.0 / 3.0); |
| 39823 | } |
| 39824 | #endif |
| 39825 | } |
| 39826 | |
| 39827 | DUK_LOCAL double duk__log2(double x) { |
| 39828 | #if defined(DUK_LOG2) |
| 39829 | return DUK_LOG2(x); |
| 39830 | #else |
| 39831 | return DUK_LOG(x) * DUK_DOUBLE_LOG2E; |
| 39832 | #endif |
| 39833 | } |
| 39834 | |
| 39835 | DUK_LOCAL double duk__log10(double x) { |
| 39836 | #if defined(DUK_LOG10) |
| 39837 | return DUK_LOG10(x); |
| 39838 | #else |
| 39839 | return DUK_LOG(x) * DUK_DOUBLE_LOG10E; |
| 39840 | #endif |
| 39841 | } |
| 39842 | |
| 39843 | DUK_LOCAL double duk__trunc(double x) { |
| 39844 | #if defined(DUK_TRUNC) |
| 39845 | return DUK_TRUNC(x); |
| 39846 | #else |
| 39847 | /* Handles -0 correctly: -0.0 matches 'x >= 0.0' but floor() |
| 39848 | * is required to return -0 when the argument is -0. |
| 39849 | */ |
| 39850 | return x >= 0.0 ? DUK_FLOOR(x) : DUK_CEIL(x); |
| 39851 | #endif |
| 39852 | } |
| 39853 | #endif /* DUK_USE_ES6 */ |
| 39854 | |
| 39855 | DUK_LOCAL double duk__round_fixed(double x) { |
| 39856 | /* Numbers half-way between integers must be rounded towards +Infinity, |
| 39857 | * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero |
| 39858 | * sign must be set appropriately. E5.1 Section 15.8.2.15. |
| 39859 | * |
| 39860 | * Note that ANSI C round() is "round to nearest integer, away from zero", |
| 39861 | * which is incorrect for negative values. Here we make do with floor(). |
| 39862 | */ |
| 39863 | |
| 39864 | duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 39865 | if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) { |
| 39866 | return x; |
| 39867 | } |
| 39868 | |
| 39869 | /* |
| 39870 | * x is finite and non-zero |
| 39871 | * |
| 39872 | * -1.6 -> floor(-1.1) -> -2 |
| 39873 | * -1.5 -> floor(-1.0) -> -1 (towards +Inf) |
| 39874 | * -1.4 -> floor(-0.9) -> -1 |
| 39875 | * -0.5 -> -0.0 (special case) |
| 39876 | * -0.1 -> -0.0 (special case) |
| 39877 | * +0.1 -> +0.0 (special case) |
| 39878 | * +0.5 -> floor(+1.0) -> 1 (towards +Inf) |
| 39879 | * +1.4 -> floor(+1.9) -> 1 |
| 39880 | * +1.5 -> floor(+2.0) -> 2 (towards +Inf) |
| 39881 | * +1.6 -> floor(+2.1) -> 2 |
| 39882 | */ |
| 39883 | |
| 39884 | if (x >= -0.5 && x < 0.5) { |
| 39885 | /* +0.5 is handled by floor, this is on purpose */ |
| 39886 | if (x < 0.0) { |
| 39887 | return -0.0; |
| 39888 | } else { |
| 39889 | return +0.0; |
| 39890 | } |
| 39891 | } |
| 39892 | |
| 39893 | return DUK_FLOOR(x + 0.5); |
| 39894 | } |
| 39895 | |
| 39896 | /* Wrappers for calling standard math library methods. These may be required |
| 39897 | * on platforms where one or more of the math built-ins are defined as macros |
| 39898 | * or inline functions and are thus not suitable to be used as function pointers. |
| 39899 | */ |
| 39900 | #if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) |
| 39901 | DUK_LOCAL double duk__fabs(double x) { |
| 39902 | return DUK_FABS(x); |
| 39903 | } |
| 39904 | DUK_LOCAL double duk__acos(double x) { |
| 39905 | return DUK_ACOS(x); |
| 39906 | } |
| 39907 | DUK_LOCAL double duk__asin(double x) { |
| 39908 | return DUK_ASIN(x); |
| 39909 | } |
| 39910 | DUK_LOCAL double duk__atan(double x) { |
| 39911 | return DUK_ATAN(x); |
| 39912 | } |
| 39913 | DUK_LOCAL double duk__ceil(double x) { |
| 39914 | return DUK_CEIL(x); |
| 39915 | } |
| 39916 | DUK_LOCAL double duk__cos(double x) { |
| 39917 | return DUK_COS(x); |
| 39918 | } |
| 39919 | DUK_LOCAL double duk__exp(double x) { |
| 39920 | return DUK_EXP(x); |
| 39921 | } |
| 39922 | DUK_LOCAL double duk__floor(double x) { |
| 39923 | return DUK_FLOOR(x); |
| 39924 | } |
| 39925 | DUK_LOCAL double duk__log(double x) { |
| 39926 | return DUK_LOG(x); |
| 39927 | } |
| 39928 | DUK_LOCAL double duk__sin(double x) { |
| 39929 | return DUK_SIN(x); |
| 39930 | } |
| 39931 | DUK_LOCAL double duk__sqrt(double x) { |
| 39932 | return DUK_SQRT(x); |
| 39933 | } |
| 39934 | DUK_LOCAL double duk__tan(double x) { |
| 39935 | return DUK_TAN(x); |
| 39936 | } |
| 39937 | DUK_LOCAL double duk__atan2_fixed(double x, double y) { |
| 39938 | #if defined(DUK_USE_ATAN2_WORKAROUNDS) |
| 39939 | /* Specific fixes to common atan2() implementation issues: |
| 39940 | * - test-bug-mingw-math-issues.js |
| 39941 | */ |
| 39942 | if (DUK_ISINF(x) && DUK_ISINF(y)) { |
| 39943 | if (DUK_SIGNBIT(x)) { |
| 39944 | if (DUK_SIGNBIT(y)) { |
| 39945 | return -2.356194490192345; |
| 39946 | } else { |
| 39947 | return -0.7853981633974483; |
| 39948 | } |
| 39949 | } else { |
| 39950 | if (DUK_SIGNBIT(y)) { |
| 39951 | return 2.356194490192345; |
| 39952 | } else { |
| 39953 | return 0.7853981633974483; |
| 39954 | } |
| 39955 | } |
| 39956 | } |
| 39957 | #else |
| 39958 | /* Some ISO C assumptions. */ |
| 39959 | |
| 39960 | DUK_ASSERT(duk_double_equals(DUK_ATAN2(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY), 0.7853981633974483)); |
| 39961 | DUK_ASSERT(duk_double_equals(DUK_ATAN2(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY), -0.7853981633974483)); |
| 39962 | DUK_ASSERT(duk_double_equals(DUK_ATAN2(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY), 2.356194490192345)); |
| 39963 | DUK_ASSERT(duk_double_equals(DUK_ATAN2(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY), -2.356194490192345)); |
| 39964 | #endif |
| 39965 | |
| 39966 | return DUK_ATAN2(x, y); |
| 39967 | } |
| 39968 | #endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */ |
| 39969 | |
| 39970 | /* order must match constants in genbuiltins.py */ |
| 39971 | DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = { |
| 39972 | #if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) |
| 39973 | duk__fabs, |
| 39974 | duk__acos, |
| 39975 | duk__asin, |
| 39976 | duk__atan, |
| 39977 | duk__ceil, |
| 39978 | duk__cos, |
| 39979 | duk__exp, |
| 39980 | duk__floor, |
| 39981 | duk__log, |
| 39982 | duk__round_fixed, |
| 39983 | duk__sin, |
| 39984 | duk__sqrt, |
| 39985 | duk__tan, |
| 39986 | #if defined(DUK_USE_ES6) |
| 39987 | duk__cbrt, |
| 39988 | duk__log2, |
| 39989 | duk__log10, |
| 39990 | duk__trunc |
| 39991 | #endif |
| 39992 | #else /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */ |
| 39993 | DUK_FABS, |
| 39994 | DUK_ACOS, |
| 39995 | DUK_ASIN, |
| 39996 | DUK_ATAN, |
| 39997 | DUK_CEIL, |
| 39998 | DUK_COS, |
| 39999 | DUK_EXP, |
| 40000 | DUK_FLOOR, |
| 40001 | DUK_LOG, |
| 40002 | duk__round_fixed, |
| 40003 | DUK_SIN, |
| 40004 | DUK_SQRT, |
| 40005 | DUK_TAN, |
| 40006 | #if defined(DUK_USE_ES6) |
| 40007 | duk__cbrt, |
| 40008 | duk__log2, |
| 40009 | duk__log10, |
| 40010 | duk__trunc |
| 40011 | #endif |
| 40012 | #endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */ |
| 40013 | }; |
| 40014 | |
| 40015 | /* order must match constants in genbuiltins.py */ |
| 40016 | DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = { |
| 40017 | #if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS) |
| 40018 | duk__atan2_fixed, |
| 40019 | duk_js_arith_pow |
| 40020 | #else |
| 40021 | duk__atan2_fixed, |
| 40022 | duk_js_arith_pow |
| 40023 | #endif |
| 40024 | }; |
| 40025 | |
| 40026 | DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_hthread *thr) { |
| 40027 | duk_small_int_t fun_idx = duk_get_current_magic(thr); |
| 40028 | duk__one_arg_func fun; |
| 40029 | duk_double_t arg1; |
| 40030 | |
| 40031 | DUK_ASSERT(fun_idx >= 0); |
| 40032 | DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func))); |
| 40033 | arg1 = duk_to_number(thr, 0); |
| 40034 | fun = duk__one_arg_funcs[fun_idx]; |
| 40035 | duk_push_number(thr, (duk_double_t) fun((double) arg1)); |
| 40036 | return 1; |
| 40037 | } |
| 40038 | |
| 40039 | DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_hthread *thr) { |
| 40040 | duk_small_int_t fun_idx = duk_get_current_magic(thr); |
| 40041 | duk__two_arg_func fun; |
| 40042 | duk_double_t arg1; |
| 40043 | duk_double_t arg2; |
| 40044 | |
| 40045 | DUK_ASSERT(fun_idx >= 0); |
| 40046 | DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func))); |
| 40047 | arg1 = duk_to_number(thr, 0); /* explicit ordered evaluation to match coercion semantics */ |
| 40048 | arg2 = duk_to_number(thr, 1); |
| 40049 | fun = duk__two_arg_funcs[fun_idx]; |
| 40050 | duk_push_number(thr, (duk_double_t) fun((double) arg1, (double) arg2)); |
| 40051 | return 1; |
| 40052 | } |
| 40053 | |
| 40054 | DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_hthread *thr) { |
| 40055 | return duk__math_minmax(thr, -DUK_DOUBLE_INFINITY, duk__fmax_fixed); |
| 40056 | } |
| 40057 | |
| 40058 | DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_hthread *thr) { |
| 40059 | return duk__math_minmax(thr, DUK_DOUBLE_INFINITY, duk__fmin_fixed); |
| 40060 | } |
| 40061 | |
| 40062 | DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_hthread *thr) { |
| 40063 | duk_push_number(thr, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr)); |
| 40064 | return 1; |
| 40065 | } |
| 40066 | |
| 40067 | #if defined(DUK_USE_ES6) |
| 40068 | DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_hthread *thr) { |
| 40069 | /* |
| 40070 | * E6 Section 20.2.2.18: Math.hypot |
| 40071 | * |
| 40072 | * - If no arguments are passed, the result is +0. |
| 40073 | * - If any argument is +inf, the result is +inf. |
| 40074 | * - If any argument is -inf, the result is +inf. |
| 40075 | * - If no argument is +inf or -inf, and any argument is NaN, the result is |
| 40076 | * NaN. |
| 40077 | * - If all arguments are either +0 or -0, the result is +0. |
| 40078 | */ |
| 40079 | |
| 40080 | duk_idx_t nargs; |
| 40081 | duk_idx_t i; |
| 40082 | duk_bool_t found_nan; |
| 40083 | duk_double_t max; |
| 40084 | duk_double_t sum, summand; |
| 40085 | duk_double_t comp, prelim; |
| 40086 | duk_double_t t; |
| 40087 | |
| 40088 | nargs = duk_get_top(thr); |
| 40089 | |
| 40090 | /* Find the highest value. Also ToNumber() coerces. */ |
| 40091 | max = 0.0; |
| 40092 | found_nan = 0; |
| 40093 | for (i = 0; i < nargs; i++) { |
| 40094 | t = DUK_FABS(duk_to_number(thr, i)); |
| 40095 | if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) { |
| 40096 | found_nan = 1; |
| 40097 | } else { |
| 40098 | max = duk_double_fmax(max, t); |
| 40099 | } |
| 40100 | } |
| 40101 | |
| 40102 | /* Early return cases. */ |
| 40103 | if (duk_double_equals(max, DUK_DOUBLE_INFINITY)) { |
| 40104 | duk_push_number(thr, DUK_DOUBLE_INFINITY); |
| 40105 | return 1; |
| 40106 | } else if (found_nan) { |
| 40107 | duk_push_number(thr, DUK_DOUBLE_NAN); |
| 40108 | return 1; |
| 40109 | } else if (duk_double_equals(max, 0.0)) { |
| 40110 | duk_push_number(thr, 0.0); |
| 40111 | /* Otherwise we'd divide by zero. */ |
| 40112 | return 1; |
| 40113 | } |
| 40114 | |
| 40115 | /* Use Kahan summation and normalize to the highest value to minimize |
| 40116 | * floating point rounding error and avoid overflow. |
| 40117 | * |
| 40118 | * https://en.wikipedia.org/wiki/Kahan_summation_algorithm |
| 40119 | */ |
| 40120 | sum = 0.0; |
| 40121 | comp = 0.0; |
| 40122 | for (i = 0; i < nargs; i++) { |
| 40123 | t = DUK_FABS(duk_get_number(thr, i)) / max; |
| 40124 | summand = (t * t) - comp; |
| 40125 | prelim = sum + summand; |
| 40126 | comp = (prelim - sum) - summand; |
| 40127 | sum = prelim; |
| 40128 | } |
| 40129 | |
| 40130 | duk_push_number(thr, (duk_double_t) DUK_SQRT(sum) * max); |
| 40131 | return 1; |
| 40132 | } |
| 40133 | #endif /* DUK_USE_ES6 */ |
| 40134 | |
| 40135 | #if defined(DUK_USE_ES6) |
| 40136 | DUK_INTERNAL duk_ret_t duk_bi_math_object_sign(duk_hthread *thr) { |
| 40137 | duk_double_t d; |
| 40138 | |
| 40139 | d = duk_to_number(thr, 0); |
| 40140 | if (duk_double_is_nan(d)) { |
| 40141 | DUK_ASSERT(duk_is_nan(thr, -1)); |
| 40142 | return 1; /* NaN input -> return NaN */ |
| 40143 | } |
| 40144 | if (duk_double_equals(d, 0.0)) { |
| 40145 | /* Zero sign kept, i.e. -0 -> -0, +0 -> +0. */ |
| 40146 | return 1; |
| 40147 | } |
| 40148 | duk_push_int(thr, (d > 0.0 ? 1 : -1)); |
| 40149 | return 1; |
| 40150 | } |
| 40151 | #endif /* DUK_USE_ES6 */ |
| 40152 | |
| 40153 | #if defined(DUK_USE_ES6) |
| 40154 | DUK_INTERNAL duk_ret_t duk_bi_math_object_clz32(duk_hthread *thr) { |
| 40155 | duk_uint32_t x; |
| 40156 | duk_small_uint_t i; |
| 40157 | |
| 40158 | #if defined(DUK_USE_PREFER_SIZE) |
| 40159 | duk_uint32_t mask; |
| 40160 | |
| 40161 | x = duk_to_uint32(thr, 0); |
| 40162 | for (i = 0, mask = 0x80000000UL; mask != 0; mask >>= 1) { |
| 40163 | if (x & mask) { |
| 40164 | break; |
| 40165 | } |
| 40166 | i++; |
| 40167 | } |
| 40168 | DUK_ASSERT(i <= 32); |
| 40169 | duk_push_uint(thr, i); |
| 40170 | return 1; |
| 40171 | #else /* DUK_USE_PREFER_SIZE */ |
| 40172 | i = 0; |
| 40173 | x = duk_to_uint32(thr, 0); |
| 40174 | if (x & 0xffff0000UL) { |
| 40175 | x >>= 16; |
| 40176 | } else { |
| 40177 | i += 16; |
| 40178 | } |
| 40179 | if (x & 0x0000ff00UL) { |
| 40180 | x >>= 8; |
| 40181 | } else { |
| 40182 | i += 8; |
| 40183 | } |
| 40184 | if (x & 0x000000f0UL) { |
| 40185 | x >>= 4; |
| 40186 | } else { |
| 40187 | i += 4; |
| 40188 | } |
| 40189 | if (x & 0x0000000cUL) { |
| 40190 | x >>= 2; |
| 40191 | } else { |
| 40192 | i += 2; |
| 40193 | } |
| 40194 | if (x & 0x00000002UL) { |
| 40195 | x >>= 1; |
| 40196 | } else { |
| 40197 | i += 1; |
| 40198 | } |
| 40199 | if (x & 0x00000001UL) { |
| 40200 | ; |
| 40201 | } else { |
| 40202 | i += 1; |
| 40203 | } |
| 40204 | DUK_ASSERT(i <= 32); |
| 40205 | duk_push_uint(thr, i); |
| 40206 | return 1; |
| 40207 | #endif /* DUK_USE_PREFER_SIZE */ |
| 40208 | } |
| 40209 | #endif /* DUK_USE_ES6 */ |
| 40210 | |
| 40211 | #if defined(DUK_USE_ES6) |
| 40212 | DUK_INTERNAL duk_ret_t duk_bi_math_object_imul(duk_hthread *thr) { |
| 40213 | duk_uint32_t x, y, z; |
| 40214 | |
| 40215 | x = duk_to_uint32(thr, 0); |
| 40216 | y = duk_to_uint32(thr, 1); |
| 40217 | z = x * y; |
| 40218 | |
| 40219 | /* While arguments are ToUint32() coerced and the multiplication |
| 40220 | * is unsigned as such, the final result is curiously interpreted |
| 40221 | * as a signed 32-bit value. |
| 40222 | */ |
| 40223 | duk_push_i32(thr, (duk_int32_t) z); |
| 40224 | return 1; |
| 40225 | } |
| 40226 | #endif /* DUK_USE_ES6 */ |
| 40227 | |
| 40228 | #endif /* DUK_USE_MATH_BUILTIN */ |
| 40229 | #line 1 "duk_bi_number.c" |
| 40230 | /* |
| 40231 | * Number built-ins |
| 40232 | */ |
| 40233 | |
| 40234 | /* #include duk_internal.h -> already included */ |
| 40235 | |
| 40236 | #if defined(DUK_USE_NUMBER_BUILTIN) |
| 40237 | |
| 40238 | DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) { |
| 40239 | duk_hobject *h; |
| 40240 | |
| 40241 | /* Number built-in accepts a plain number or a Number object (whose |
| 40242 | * internal value is operated on). Other types cause TypeError. |
| 40243 | */ |
| 40244 | |
| 40245 | duk_push_this(thr); |
| 40246 | if (duk_is_number(thr, -1)) { |
| 40247 | DUK_DDD(DUK_DDDPRINT("plain number value: %!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 40248 | goto done; |
| 40249 | } |
| 40250 | h = duk_get_hobject(thr, -1); |
| 40251 | if (!h || |
| 40252 | (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) { |
| 40253 | DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 40254 | DUK_ERROR_TYPE(thr, "number expected" ); |
| 40255 | DUK_WO_NORETURN(return 0.0;); |
| 40256 | } |
| 40257 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); |
| 40258 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 40259 | DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T" , |
| 40260 | (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); |
| 40261 | duk_remove_m2(thr); |
| 40262 | |
| 40263 | done: |
| 40264 | return duk_get_number(thr, -1); |
| 40265 | } |
| 40266 | |
| 40267 | DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_hthread *thr) { |
| 40268 | duk_idx_t nargs; |
| 40269 | duk_hobject *h_this; |
| 40270 | |
| 40271 | /* |
| 40272 | * The Number constructor uses ToNumber(arg) for number coercion |
| 40273 | * (coercing an undefined argument to NaN). However, if the |
| 40274 | * argument is not given at all, +0 must be used instead. To do |
| 40275 | * this, a vararg function is used. |
| 40276 | */ |
| 40277 | |
| 40278 | nargs = duk_get_top(thr); |
| 40279 | if (nargs == 0) { |
| 40280 | duk_push_int(thr, 0); |
| 40281 | } |
| 40282 | duk_to_number(thr, 0); |
| 40283 | duk_set_top(thr, 1); |
| 40284 | DUK_ASSERT_TOP(thr, 1); |
| 40285 | |
| 40286 | if (!duk_is_constructor_call(thr)) { |
| 40287 | return 1; |
| 40288 | } |
| 40289 | |
| 40290 | /* |
| 40291 | * E5 Section 15.7.2.1 requires that the constructed object |
| 40292 | * must have the original Number.prototype as its internal |
| 40293 | * prototype. However, since Number.prototype is non-writable |
| 40294 | * and non-configurable, this doesn't have to be enforced here: |
| 40295 | * The default object (bound to 'this') is OK, though we have |
| 40296 | * to change its class. |
| 40297 | * |
| 40298 | * Internal value set to ToNumber(arg) or +0; if no arg given, |
| 40299 | * ToNumber(undefined) = NaN, so special treatment is needed |
| 40300 | * (above). String internal value is immutable. |
| 40301 | */ |
| 40302 | |
| 40303 | /* XXX: helper */ |
| 40304 | duk_push_this(thr); |
| 40305 | h_this = duk_known_hobject(thr, -1); |
| 40306 | DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER); |
| 40307 | |
| 40308 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]); |
| 40309 | DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER); |
| 40310 | DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this)); |
| 40311 | |
| 40312 | duk_dup_0(thr); /* -> [ val obj val ] */ |
| 40313 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); |
| 40314 | return 0; /* no return value -> don't replace created value */ |
| 40315 | } |
| 40316 | |
| 40317 | DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_hthread *thr) { |
| 40318 | (void) duk__push_this_number_plain(thr); |
| 40319 | return 1; |
| 40320 | } |
| 40321 | |
| 40322 | DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_hthread *thr) { |
| 40323 | duk_small_int_t radix; |
| 40324 | duk_small_uint_t n2s_flags; |
| 40325 | |
| 40326 | (void) duk__push_this_number_plain(thr); |
| 40327 | if (duk_is_undefined(thr, 0)) { |
| 40328 | radix = 10; |
| 40329 | } else { |
| 40330 | radix = (duk_small_int_t) duk_to_int_check_range(thr, 0, 2, 36); |
| 40331 | } |
| 40332 | DUK_DDD(DUK_DDDPRINT("radix=%ld" , (long) radix)); |
| 40333 | |
| 40334 | n2s_flags = 0; |
| 40335 | |
| 40336 | duk_numconv_stringify(thr, |
| 40337 | radix /*radix*/, |
| 40338 | 0 /*digits*/, |
| 40339 | n2s_flags /*flags*/); |
| 40340 | return 1; |
| 40341 | } |
| 40342 | |
| 40343 | DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_hthread *thr) { |
| 40344 | /* XXX: just use toString() for now; permitted although not recommended. |
| 40345 | * nargs==1, so radix is passed to toString(). |
| 40346 | */ |
| 40347 | return duk_bi_number_prototype_to_string(thr); |
| 40348 | } |
| 40349 | |
| 40350 | /* |
| 40351 | * toFixed(), toExponential(), toPrecision() |
| 40352 | */ |
| 40353 | |
| 40354 | /* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */ |
| 40355 | |
| 40356 | DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) { |
| 40357 | duk_small_int_t frac_digits; |
| 40358 | duk_double_t d; |
| 40359 | duk_small_int_t c; |
| 40360 | duk_small_uint_t n2s_flags; |
| 40361 | |
| 40362 | /* In ES5.1 frac_digits is coerced first; in ES2015 the 'this number |
| 40363 | * value' check is done first. |
| 40364 | */ |
| 40365 | d = duk__push_this_number_plain(thr); |
| 40366 | frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20); |
| 40367 | |
| 40368 | c = (duk_small_int_t) DUK_FPCLASSIFY(d); |
| 40369 | if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { |
| 40370 | goto use_to_string; |
| 40371 | } |
| 40372 | |
| 40373 | if (d >= 1.0e21 || d <= -1.0e21) { |
| 40374 | goto use_to_string; |
| 40375 | } |
| 40376 | |
| 40377 | n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | |
| 40378 | DUK_N2S_FLAG_FRACTION_DIGITS; |
| 40379 | |
| 40380 | duk_numconv_stringify(thr, |
| 40381 | 10 /*radix*/, |
| 40382 | frac_digits /*digits*/, |
| 40383 | n2s_flags /*flags*/); |
| 40384 | return 1; |
| 40385 | |
| 40386 | use_to_string: |
| 40387 | DUK_ASSERT_TOP(thr, 2); |
| 40388 | duk_to_string(thr, -1); |
| 40389 | return 1; |
| 40390 | } |
| 40391 | |
| 40392 | DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_hthread *thr) { |
| 40393 | duk_bool_t frac_undefined; |
| 40394 | duk_small_int_t frac_digits; |
| 40395 | duk_double_t d; |
| 40396 | duk_small_int_t c; |
| 40397 | duk_small_uint_t n2s_flags; |
| 40398 | |
| 40399 | d = duk__push_this_number_plain(thr); |
| 40400 | |
| 40401 | frac_undefined = duk_is_undefined(thr, 0); |
| 40402 | duk_to_int(thr, 0); /* for side effects */ |
| 40403 | |
| 40404 | c = (duk_small_int_t) DUK_FPCLASSIFY(d); |
| 40405 | if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { |
| 40406 | goto use_to_string; |
| 40407 | } |
| 40408 | |
| 40409 | frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20); |
| 40410 | |
| 40411 | n2s_flags = DUK_N2S_FLAG_FORCE_EXP | |
| 40412 | (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT); |
| 40413 | |
| 40414 | duk_numconv_stringify(thr, |
| 40415 | 10 /*radix*/, |
| 40416 | frac_digits + 1 /*leading digit + fractions*/, |
| 40417 | n2s_flags /*flags*/); |
| 40418 | return 1; |
| 40419 | |
| 40420 | use_to_string: |
| 40421 | DUK_ASSERT_TOP(thr, 2); |
| 40422 | duk_to_string(thr, -1); |
| 40423 | return 1; |
| 40424 | } |
| 40425 | |
| 40426 | DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) { |
| 40427 | /* The specification has quite awkward order of coercion and |
| 40428 | * checks for toPrecision(). The operations below are a bit |
| 40429 | * reordered, within constraints of observable side effects. |
| 40430 | */ |
| 40431 | |
| 40432 | duk_double_t d; |
| 40433 | duk_small_int_t prec; |
| 40434 | duk_small_int_t c; |
| 40435 | duk_small_uint_t n2s_flags; |
| 40436 | |
| 40437 | DUK_ASSERT_TOP(thr, 1); |
| 40438 | |
| 40439 | d = duk__push_this_number_plain(thr); |
| 40440 | if (duk_is_undefined(thr, 0)) { |
| 40441 | goto use_to_string; |
| 40442 | } |
| 40443 | DUK_ASSERT_TOP(thr, 2); |
| 40444 | |
| 40445 | duk_to_int(thr, 0); /* for side effects */ |
| 40446 | |
| 40447 | c = (duk_small_int_t) DUK_FPCLASSIFY(d); |
| 40448 | if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { |
| 40449 | goto use_to_string; |
| 40450 | } |
| 40451 | |
| 40452 | prec = (duk_small_int_t) duk_to_int_check_range(thr, 0, 1, 21); |
| 40453 | |
| 40454 | n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | |
| 40455 | DUK_N2S_FLAG_NO_ZERO_PAD; |
| 40456 | |
| 40457 | duk_numconv_stringify(thr, |
| 40458 | 10 /*radix*/, |
| 40459 | prec /*digits*/, |
| 40460 | n2s_flags /*flags*/); |
| 40461 | return 1; |
| 40462 | |
| 40463 | use_to_string: |
| 40464 | /* Used when precision is undefined; also used for NaN (-> "NaN"), |
| 40465 | * and +/- infinity (-> "Infinity", "-Infinity"). |
| 40466 | */ |
| 40467 | |
| 40468 | DUK_ASSERT_TOP(thr, 2); |
| 40469 | duk_to_string(thr, -1); |
| 40470 | return 1; |
| 40471 | } |
| 40472 | |
| 40473 | /* |
| 40474 | * ES2015 isFinite() etc |
| 40475 | */ |
| 40476 | |
| 40477 | #if defined(DUK_USE_ES6) |
| 40478 | DUK_INTERNAL duk_ret_t duk_bi_number_check_shared(duk_hthread *thr) { |
| 40479 | duk_int_t magic; |
| 40480 | duk_bool_t ret = 0; |
| 40481 | |
| 40482 | if (duk_is_number(thr, 0)) { |
| 40483 | duk_double_t d; |
| 40484 | |
| 40485 | magic = duk_get_current_magic(thr); |
| 40486 | d = duk_get_number(thr, 0); |
| 40487 | |
| 40488 | switch (magic) { |
| 40489 | case 0: /* isFinite() */ |
| 40490 | ret = duk_double_is_finite(d); |
| 40491 | break; |
| 40492 | case 1: /* isInteger() */ |
| 40493 | ret = duk_double_is_integer(d); |
| 40494 | break; |
| 40495 | case 2: /* isNaN() */ |
| 40496 | ret = duk_double_is_nan(d); |
| 40497 | break; |
| 40498 | default: /* isSafeInteger() */ |
| 40499 | DUK_ASSERT(magic == 3); |
| 40500 | ret = duk_double_is_safe_integer(d); |
| 40501 | } |
| 40502 | } |
| 40503 | |
| 40504 | duk_push_boolean(thr, ret); |
| 40505 | return 1; |
| 40506 | } |
| 40507 | #endif /* DUK_USE_ES6 */ |
| 40508 | |
| 40509 | #endif /* DUK_USE_NUMBER_BUILTIN */ |
| 40510 | #line 1 "duk_bi_object.c" |
| 40511 | /* |
| 40512 | * Object built-ins |
| 40513 | */ |
| 40514 | |
| 40515 | /* #include duk_internal.h -> already included */ |
| 40516 | |
| 40517 | /* Needed even when Object built-in disabled. */ |
| 40518 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) { |
| 40519 | duk_tval *tv; |
| 40520 | |
| 40521 | tv = DUK_HTHREAD_THIS_PTR(thr); |
| 40522 | duk_push_class_string_tval(thr, tv, 0 /*avoid_side_effects*/); |
| 40523 | return 1; |
| 40524 | } |
| 40525 | |
| 40526 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40527 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_hthread *thr) { |
| 40528 | duk_uint_t arg_mask; |
| 40529 | |
| 40530 | arg_mask = duk_get_type_mask(thr, 0); |
| 40531 | |
| 40532 | if (!duk_is_constructor_call(thr) && /* not a constructor call */ |
| 40533 | ((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) { /* and argument not null or undefined */ |
| 40534 | duk_to_object(thr, 0); |
| 40535 | return 1; |
| 40536 | } |
| 40537 | |
| 40538 | /* Pointer and buffer primitive values are treated like other |
| 40539 | * primitives values which have a fully fledged object counterpart: |
| 40540 | * promote to an object value. Lightfuncs and plain buffers are |
| 40541 | * coerced with ToObject() even they could also be returned as is. |
| 40542 | */ |
| 40543 | if (arg_mask & (DUK_TYPE_MASK_OBJECT | |
| 40544 | DUK_TYPE_MASK_STRING | |
| 40545 | DUK_TYPE_MASK_BOOLEAN | |
| 40546 | DUK_TYPE_MASK_NUMBER | |
| 40547 | DUK_TYPE_MASK_POINTER | |
| 40548 | DUK_TYPE_MASK_BUFFER | |
| 40549 | DUK_TYPE_MASK_LIGHTFUNC)) { |
| 40550 | /* For DUK_TYPE_OBJECT the coercion is a no-op and could |
| 40551 | * be checked for explicitly, but Object(obj) calls are |
| 40552 | * not very common so opt for minimal footprint. |
| 40553 | */ |
| 40554 | duk_to_object(thr, 0); |
| 40555 | return 1; |
| 40556 | } |
| 40557 | |
| 40558 | (void) duk_push_object_helper(thr, |
| 40559 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 40560 | DUK_HOBJECT_FLAG_FASTREFS | |
| 40561 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), |
| 40562 | DUK_BIDX_OBJECT_PROTOTYPE); |
| 40563 | return 1; |
| 40564 | } |
| 40565 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40566 | |
| 40567 | #if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6) |
| 40568 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_hthread *thr) { |
| 40569 | duk_idx_t nargs; |
| 40570 | duk_int_t idx; |
| 40571 | |
| 40572 | nargs = duk_get_top_require_min(thr, 1 /*min_top*/); |
| 40573 | |
| 40574 | duk_to_object(thr, 0); |
| 40575 | for (idx = 1; idx < nargs; idx++) { |
| 40576 | /* E7 19.1.2.1 (step 4a) */ |
| 40577 | if (duk_is_null_or_undefined(thr, idx)) { |
| 40578 | continue; |
| 40579 | } |
| 40580 | |
| 40581 | /* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is |
| 40582 | * convenient here. |
| 40583 | */ |
| 40584 | duk_to_object(thr, idx); |
| 40585 | duk_enum(thr, idx, DUK_ENUM_OWN_PROPERTIES_ONLY); |
| 40586 | while (duk_next(thr, -1, 1 /*get_value*/)) { |
| 40587 | /* [ target ... enum key value ] */ |
| 40588 | duk_put_prop(thr, 0); |
| 40589 | /* [ target ... enum ] */ |
| 40590 | } |
| 40591 | /* Could pop enumerator, but unnecessary because of duk_set_top() |
| 40592 | * below. |
| 40593 | */ |
| 40594 | } |
| 40595 | |
| 40596 | duk_set_top(thr, 1); |
| 40597 | return 1; |
| 40598 | } |
| 40599 | #endif |
| 40600 | |
| 40601 | #if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6) |
| 40602 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_hthread *thr) { |
| 40603 | DUK_ASSERT_TOP(thr, 2); |
| 40604 | duk_push_boolean(thr, duk_samevalue(thr, 0, 1)); |
| 40605 | return 1; |
| 40606 | } |
| 40607 | #endif |
| 40608 | |
| 40609 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40610 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) { |
| 40611 | duk_hobject *proto; |
| 40612 | |
| 40613 | DUK_ASSERT_TOP(thr, 2); |
| 40614 | |
| 40615 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 40616 | duk_hbufobj_promote_plain(thr, 0); |
| 40617 | #endif |
| 40618 | proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL); |
| 40619 | DUK_ASSERT(proto != NULL || duk_is_null(thr, 0)); |
| 40620 | |
| 40621 | (void) duk_push_object_helper_proto(thr, |
| 40622 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 40623 | DUK_HOBJECT_FLAG_FASTREFS | |
| 40624 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), |
| 40625 | proto); |
| 40626 | |
| 40627 | if (!duk_is_undefined(thr, 1)) { |
| 40628 | /* [ O Properties obj ] */ |
| 40629 | |
| 40630 | duk_replace(thr, 0); |
| 40631 | |
| 40632 | /* [ obj Properties ] */ |
| 40633 | |
| 40634 | /* Just call the "original" Object.defineProperties() to |
| 40635 | * finish up. |
| 40636 | */ |
| 40637 | |
| 40638 | return duk_bi_object_constructor_define_properties(thr); |
| 40639 | } |
| 40640 | |
| 40641 | /* [ O Properties obj ] */ |
| 40642 | |
| 40643 | return 1; |
| 40644 | } |
| 40645 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40646 | |
| 40647 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40648 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_hthread *thr) { |
| 40649 | duk_small_uint_t pass; |
| 40650 | duk_uint_t defprop_flags; |
| 40651 | duk_hobject *obj; |
| 40652 | duk_idx_t idx_value; |
| 40653 | duk_hobject *get; |
| 40654 | duk_hobject *set; |
| 40655 | |
| 40656 | /* Lightfunc and plain buffer handling by ToObject() coercion. */ |
| 40657 | obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 40658 | DUK_ASSERT(obj != NULL); |
| 40659 | |
| 40660 | duk_to_object(thr, 1); /* properties object */ |
| 40661 | |
| 40662 | DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT" , |
| 40663 | (duk_tval *) duk_get_tval(thr, 0), |
| 40664 | (duk_tval *) duk_get_tval(thr, 1))); |
| 40665 | |
| 40666 | /* |
| 40667 | * Two pass approach to processing the property descriptors. |
| 40668 | * On first pass validate and normalize all descriptors before |
| 40669 | * any changes are made to the target object. On second pass |
| 40670 | * make the actual modifications to the target object. |
| 40671 | * |
| 40672 | * Right now we'll just use the same normalize/validate helper |
| 40673 | * on both passes, ignoring its outputs on the first pass. |
| 40674 | */ |
| 40675 | |
| 40676 | for (pass = 0; pass < 2; pass++) { |
| 40677 | duk_set_top(thr, 2); /* -> [ hobject props ] */ |
| 40678 | duk_enum(thr, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/); |
| 40679 | |
| 40680 | for (;;) { |
| 40681 | duk_hstring *key; |
| 40682 | |
| 40683 | /* [ hobject props enum(props) ] */ |
| 40684 | |
| 40685 | duk_set_top(thr, 3); |
| 40686 | |
| 40687 | if (!duk_next(thr, 2, 1 /*get_value*/)) { |
| 40688 | break; |
| 40689 | } |
| 40690 | |
| 40691 | DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT" , |
| 40692 | (duk_tval *) duk_get_tval(thr, -2), |
| 40693 | (duk_tval *) duk_get_tval(thr, -1))); |
| 40694 | |
| 40695 | /* [ hobject props enum(props) key desc ] */ |
| 40696 | |
| 40697 | duk_hobject_prepare_property_descriptor(thr, |
| 40698 | 4 /*idx_desc*/, |
| 40699 | &defprop_flags, |
| 40700 | &idx_value, |
| 40701 | &get, |
| 40702 | &set); |
| 40703 | |
| 40704 | /* [ hobject props enum(props) key desc [multiple values] ] */ |
| 40705 | |
| 40706 | if (pass == 0) { |
| 40707 | continue; |
| 40708 | } |
| 40709 | |
| 40710 | /* This allows symbols on purpose. */ |
| 40711 | key = duk_known_hstring(thr, 3); |
| 40712 | DUK_ASSERT(key != NULL); |
| 40713 | |
| 40714 | duk_hobject_define_property_helper(thr, |
| 40715 | defprop_flags, |
| 40716 | obj, |
| 40717 | key, |
| 40718 | idx_value, |
| 40719 | get, |
| 40720 | set, |
| 40721 | 1 /*throw_flag*/); |
| 40722 | } |
| 40723 | } |
| 40724 | |
| 40725 | /* |
| 40726 | * Return target object |
| 40727 | */ |
| 40728 | |
| 40729 | duk_dup_0(thr); |
| 40730 | return 1; |
| 40731 | } |
| 40732 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40733 | |
| 40734 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40735 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_hthread *thr) { |
| 40736 | DUK_ASSERT_TOP(thr, 1); |
| 40737 | |
| 40738 | duk_seal_freeze_raw(thr, 0, (duk_bool_t) duk_get_current_magic(thr) /*is_freeze*/); |
| 40739 | return 1; |
| 40740 | } |
| 40741 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40742 | |
| 40743 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40744 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_hthread *thr) { |
| 40745 | duk_hobject *h; |
| 40746 | duk_bool_t is_frozen; |
| 40747 | duk_uint_t mask; |
| 40748 | |
| 40749 | is_frozen = (duk_bool_t) duk_get_current_magic(thr); |
| 40750 | mask = duk_get_type_mask(thr, 0); |
| 40751 | if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) { |
| 40752 | DUK_ASSERT(is_frozen == 0 || is_frozen == 1); |
| 40753 | duk_push_boolean(thr, (mask & DUK_TYPE_MASK_LIGHTFUNC) ? |
| 40754 | 1 : /* lightfunc always frozen and sealed */ |
| 40755 | (is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */ |
| 40756 | } else { |
| 40757 | /* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object |
| 40758 | * is considered to be already sealed and frozen. |
| 40759 | */ |
| 40760 | h = duk_get_hobject(thr, 0); |
| 40761 | duk_push_boolean(thr, (h == NULL) || |
| 40762 | duk_hobject_object_is_sealed_frozen_helper(thr, h, is_frozen /*is_frozen*/)); |
| 40763 | } |
| 40764 | return 1; |
| 40765 | } |
| 40766 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40767 | |
| 40768 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40769 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) { |
| 40770 | DUK_ASSERT_TOP(thr, 0); |
| 40771 | (void) duk_push_this_coercible_to_object(thr); |
| 40772 | duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING); |
| 40773 | #if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */ |
| 40774 | duk_require_callable(thr, 1); |
| 40775 | #endif |
| 40776 | duk_dup_0(thr); /* -> [ O toString O ] */ |
| 40777 | duk_call_method(thr, 0); /* XXX: call method tail call? */ |
| 40778 | return 1; |
| 40779 | } |
| 40780 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40781 | |
| 40782 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40783 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_hthread *thr) { |
| 40784 | /* For lightfuncs and plain buffers, returns Object() coerced. */ |
| 40785 | (void) duk_push_this_coercible_to_object(thr); |
| 40786 | return 1; |
| 40787 | } |
| 40788 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40789 | |
| 40790 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40791 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) { |
| 40792 | duk_hobject *h_v; |
| 40793 | duk_hobject *h_obj; |
| 40794 | |
| 40795 | DUK_ASSERT_TOP(thr, 1); |
| 40796 | |
| 40797 | h_v = duk_get_hobject(thr, 0); |
| 40798 | if (!h_v) { |
| 40799 | duk_push_false(thr); /* XXX: tail call: return duk_push_false(thr) */ |
| 40800 | return 1; |
| 40801 | } |
| 40802 | |
| 40803 | h_obj = duk_push_this_coercible_to_object(thr); |
| 40804 | DUK_ASSERT(h_obj != NULL); |
| 40805 | |
| 40806 | /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare. |
| 40807 | * Prototype loops should cause an error to be thrown. |
| 40808 | */ |
| 40809 | duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/)); |
| 40810 | return 1; |
| 40811 | } |
| 40812 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40813 | |
| 40814 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40815 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_hthread *thr) { |
| 40816 | return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, 0 /*required_desc_flags*/); |
| 40817 | } |
| 40818 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40819 | |
| 40820 | #if defined(DUK_USE_OBJECT_BUILTIN) |
| 40821 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_hthread *thr) { |
| 40822 | return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/); |
| 40823 | } |
| 40824 | #endif /* DUK_USE_OBJECT_BUILTIN */ |
| 40825 | |
| 40826 | #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) |
| 40827 | /* Shared helper to implement Object.getPrototypeOf, |
| 40828 | * Object.prototype.__proto__ getter, and Reflect.getPrototypeOf. |
| 40829 | * |
| 40830 | * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__ |
| 40831 | */ |
| 40832 | DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_hthread *thr) { |
| 40833 | /* |
| 40834 | * magic = 0: __proto__ getter |
| 40835 | * magic = 1: Object.getPrototypeOf() |
| 40836 | * magic = 2: Reflect.getPrototypeOf() |
| 40837 | */ |
| 40838 | |
| 40839 | duk_hobject *h; |
| 40840 | duk_hobject *proto; |
| 40841 | duk_tval *tv; |
| 40842 | duk_int_t magic; |
| 40843 | |
| 40844 | magic = duk_get_current_magic(thr); |
| 40845 | |
| 40846 | if (magic == 0) { |
| 40847 | DUK_ASSERT_TOP(thr, 0); |
| 40848 | duk_push_this_coercible_to_object(thr); |
| 40849 | } |
| 40850 | DUK_ASSERT(duk_get_top(thr) >= 1); |
| 40851 | if (magic < 2) { |
| 40852 | /* ES2015 Section 19.1.2.9, step 1 */ |
| 40853 | duk_to_object(thr, 0); |
| 40854 | } |
| 40855 | tv = DUK_GET_TVAL_POSIDX(thr, 0); |
| 40856 | |
| 40857 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 40858 | case DUK_TAG_BUFFER: |
| 40859 | proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; |
| 40860 | break; |
| 40861 | case DUK_TAG_LIGHTFUNC: |
| 40862 | proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]; |
| 40863 | break; |
| 40864 | case DUK_TAG_OBJECT: |
| 40865 | h = DUK_TVAL_GET_OBJECT(tv); |
| 40866 | proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); |
| 40867 | break; |
| 40868 | default: |
| 40869 | /* This implicitly handles CheckObjectCoercible() caused |
| 40870 | * TypeError. |
| 40871 | */ |
| 40872 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 40873 | } |
| 40874 | if (proto != NULL) { |
| 40875 | duk_push_hobject(thr, proto); |
| 40876 | } else { |
| 40877 | duk_push_null(thr); |
| 40878 | } |
| 40879 | return 1; |
| 40880 | } |
| 40881 | #endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ |
| 40882 | |
| 40883 | #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) |
| 40884 | /* Shared helper to implement ES2015 Object.setPrototypeOf, |
| 40885 | * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf. |
| 40886 | * |
| 40887 | * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__ |
| 40888 | * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof |
| 40889 | */ |
| 40890 | DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) { |
| 40891 | /* |
| 40892 | * magic = 0: __proto__ setter |
| 40893 | * magic = 1: Object.setPrototypeOf() |
| 40894 | * magic = 2: Reflect.setPrototypeOf() |
| 40895 | */ |
| 40896 | |
| 40897 | duk_hobject *h_obj; |
| 40898 | duk_hobject *h_new_proto; |
| 40899 | duk_hobject *h_curr; |
| 40900 | duk_ret_t ret_success = 1; /* retval for success path */ |
| 40901 | duk_uint_t mask; |
| 40902 | duk_int_t magic; |
| 40903 | |
| 40904 | /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */ |
| 40905 | magic = duk_get_current_magic(thr); |
| 40906 | if (magic == 0) { |
| 40907 | duk_push_this_check_object_coercible(thr); |
| 40908 | duk_insert(thr, 0); |
| 40909 | if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) { |
| 40910 | return 0; |
| 40911 | } |
| 40912 | |
| 40913 | /* __proto__ setter returns 'undefined' on success unlike the |
| 40914 | * setPrototypeOf() call which returns the target object. |
| 40915 | */ |
| 40916 | ret_success = 0; |
| 40917 | } else { |
| 40918 | if (magic == 1) { |
| 40919 | duk_require_object_coercible(thr, 0); |
| 40920 | } else { |
| 40921 | duk_require_hobject_accept_mask(thr, 0, |
| 40922 | DUK_TYPE_MASK_LIGHTFUNC | |
| 40923 | DUK_TYPE_MASK_BUFFER); |
| 40924 | } |
| 40925 | duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT); |
| 40926 | } |
| 40927 | |
| 40928 | h_new_proto = duk_get_hobject(thr, 1); |
| 40929 | /* h_new_proto may be NULL */ |
| 40930 | |
| 40931 | mask = duk_get_type_mask(thr, 0); |
| 40932 | if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) { |
| 40933 | duk_hobject *curr_proto; |
| 40934 | curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ? |
| 40935 | DUK_BIDX_FUNCTION_PROTOTYPE : |
| 40936 | DUK_BIDX_UINT8ARRAY_PROTOTYPE]; |
| 40937 | if (h_new_proto == curr_proto) { |
| 40938 | goto skip; |
| 40939 | } |
| 40940 | goto fail_nonextensible; |
| 40941 | } |
| 40942 | h_obj = duk_get_hobject(thr, 0); |
| 40943 | if (h_obj == NULL) { |
| 40944 | goto skip; |
| 40945 | } |
| 40946 | DUK_ASSERT(h_obj != NULL); |
| 40947 | |
| 40948 | /* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */ |
| 40949 | /* TODO: implement Proxy object support here */ |
| 40950 | |
| 40951 | if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) { |
| 40952 | goto skip; |
| 40953 | } |
| 40954 | if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) { |
| 40955 | goto fail_nonextensible; |
| 40956 | } |
| 40957 | for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) { |
| 40958 | /* Loop prevention. */ |
| 40959 | if (h_curr == h_obj) { |
| 40960 | goto fail_loop; |
| 40961 | } |
| 40962 | } |
| 40963 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto); |
| 40964 | /* fall thru */ |
| 40965 | |
| 40966 | skip: |
| 40967 | duk_set_top(thr, 1); |
| 40968 | if (magic == 2) { |
| 40969 | duk_push_true(thr); |
| 40970 | } |
| 40971 | return ret_success; |
| 40972 | |
| 40973 | fail_nonextensible: |
| 40974 | fail_loop: |
| 40975 | if (magic != 2) { |
| 40976 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 40977 | } else { |
| 40978 | duk_push_false(thr); |
| 40979 | return 1; |
| 40980 | } |
| 40981 | } |
| 40982 | #endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ |
| 40983 | |
| 40984 | #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) |
| 40985 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *thr) { |
| 40986 | /* |
| 40987 | * magic = 0: Object.defineProperty() |
| 40988 | * magic = 1: Reflect.defineProperty() |
| 40989 | */ |
| 40990 | |
| 40991 | duk_hobject *obj; |
| 40992 | duk_hstring *key; |
| 40993 | duk_hobject *get; |
| 40994 | duk_hobject *set; |
| 40995 | duk_idx_t idx_value; |
| 40996 | duk_uint_t defprop_flags; |
| 40997 | duk_small_uint_t magic; |
| 40998 | duk_bool_t throw_flag; |
| 40999 | duk_bool_t ret; |
| 41000 | |
| 41001 | DUK_ASSERT(thr != NULL); |
| 41002 | |
| 41003 | DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T" , |
| 41004 | (void *) thr, |
| 41005 | (duk_tval *) duk_get_tval(thr, 0), |
| 41006 | (duk_tval *) duk_get_tval(thr, 1), |
| 41007 | (duk_tval *) duk_get_tval(thr, 2))); |
| 41008 | |
| 41009 | /* [ obj key desc ] */ |
| 41010 | |
| 41011 | magic = (duk_small_uint_t) duk_get_current_magic(thr); |
| 41012 | |
| 41013 | /* Lightfuncs are currently supported by coercing to a temporary |
| 41014 | * Function object; changes will be allowed (the coerced value is |
| 41015 | * extensible) but will be lost. Same for plain buffers. |
| 41016 | */ |
| 41017 | obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 41018 | DUK_ASSERT(obj != NULL); |
| 41019 | key = duk_to_property_key_hstring(thr, 1); |
| 41020 | (void) duk_require_hobject(thr, 2); |
| 41021 | |
| 41022 | DUK_ASSERT(obj != NULL); |
| 41023 | DUK_ASSERT(key != NULL); |
| 41024 | DUK_ASSERT(duk_get_hobject(thr, 2) != NULL); |
| 41025 | |
| 41026 | /* |
| 41027 | * Validate and convert argument property descriptor (an ECMAScript |
| 41028 | * object) into a set of defprop_flags and possibly property value, |
| 41029 | * getter, and/or setter values on the value stack. |
| 41030 | * |
| 41031 | * Lightfunc set/get values are coerced to full Functions. |
| 41032 | */ |
| 41033 | |
| 41034 | duk_hobject_prepare_property_descriptor(thr, |
| 41035 | 2 /*idx_desc*/, |
| 41036 | &defprop_flags, |
| 41037 | &idx_value, |
| 41038 | &get, |
| 41039 | &set); |
| 41040 | |
| 41041 | /* |
| 41042 | * Use Object.defineProperty() helper for the actual operation. |
| 41043 | */ |
| 41044 | |
| 41045 | DUK_ASSERT(magic == 0U || magic == 1U); |
| 41046 | throw_flag = magic ^ 1U; |
| 41047 | ret = duk_hobject_define_property_helper(thr, |
| 41048 | defprop_flags, |
| 41049 | obj, |
| 41050 | key, |
| 41051 | idx_value, |
| 41052 | get, |
| 41053 | set, |
| 41054 | throw_flag); |
| 41055 | |
| 41056 | /* Ignore the normalize/validate helper outputs on the value stack, |
| 41057 | * they're popped automatically. |
| 41058 | */ |
| 41059 | |
| 41060 | if (magic == 0U) { |
| 41061 | /* Object.defineProperty(): return target object. */ |
| 41062 | duk_push_hobject(thr, obj); |
| 41063 | } else { |
| 41064 | /* Reflect.defineProperty(): return success/fail. */ |
| 41065 | duk_push_boolean(thr, ret); |
| 41066 | } |
| 41067 | return 1; |
| 41068 | } |
| 41069 | #endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ |
| 41070 | |
| 41071 | #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) |
| 41072 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) { |
| 41073 | DUK_ASSERT_TOP(thr, 2); |
| 41074 | |
| 41075 | /* ES2015 Section 19.1.2.6, step 1 */ |
| 41076 | if (duk_get_current_magic(thr) == 0) { |
| 41077 | duk_to_object(thr, 0); |
| 41078 | } |
| 41079 | |
| 41080 | /* [ obj key ] */ |
| 41081 | |
| 41082 | duk_hobject_object_get_own_property_descriptor(thr, -2); |
| 41083 | return 1; |
| 41084 | } |
| 41085 | #endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ |
| 41086 | |
| 41087 | #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) |
| 41088 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) { |
| 41089 | /* |
| 41090 | * magic = 0: Object.isExtensible() |
| 41091 | * magic = 1: Reflect.isExtensible() |
| 41092 | */ |
| 41093 | |
| 41094 | duk_hobject *h; |
| 41095 | |
| 41096 | if (duk_get_current_magic(thr) == 0) { |
| 41097 | h = duk_get_hobject(thr, 0); |
| 41098 | } else { |
| 41099 | /* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs |
| 41100 | * and plain buffers here because they pretend to be objects. |
| 41101 | */ |
| 41102 | h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 41103 | } |
| 41104 | |
| 41105 | duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h)); |
| 41106 | return 1; |
| 41107 | } |
| 41108 | #endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ |
| 41109 | |
| 41110 | #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) |
| 41111 | /* Shared helper for various key/symbol listings, magic: |
| 41112 | * 0=Object.keys() |
| 41113 | * 1=Object.getOwnPropertyNames(), |
| 41114 | * 2=Object.getOwnPropertySymbols(), |
| 41115 | * 3=Reflect.ownKeys() |
| 41116 | */ |
| 41117 | DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = { |
| 41118 | /* Object.keys() */ |
| 41119 | DUK_ENUM_OWN_PROPERTIES_ONLY | |
| 41120 | DUK_ENUM_NO_PROXY_BEHAVIOR, |
| 41121 | |
| 41122 | /* Object.getOwnPropertyNames() */ |
| 41123 | DUK_ENUM_INCLUDE_NONENUMERABLE | |
| 41124 | DUK_ENUM_OWN_PROPERTIES_ONLY | |
| 41125 | DUK_ENUM_NO_PROXY_BEHAVIOR, |
| 41126 | |
| 41127 | /* Object.getOwnPropertySymbols() */ |
| 41128 | DUK_ENUM_INCLUDE_SYMBOLS | |
| 41129 | DUK_ENUM_OWN_PROPERTIES_ONLY | |
| 41130 | DUK_ENUM_EXCLUDE_STRINGS | |
| 41131 | DUK_ENUM_INCLUDE_NONENUMERABLE | |
| 41132 | DUK_ENUM_NO_PROXY_BEHAVIOR, |
| 41133 | |
| 41134 | /* Reflect.ownKeys() */ |
| 41135 | DUK_ENUM_INCLUDE_SYMBOLS | |
| 41136 | DUK_ENUM_OWN_PROPERTIES_ONLY | |
| 41137 | DUK_ENUM_INCLUDE_NONENUMERABLE | |
| 41138 | DUK_ENUM_NO_PROXY_BEHAVIOR |
| 41139 | }; |
| 41140 | |
| 41141 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) { |
| 41142 | duk_hobject *obj; |
| 41143 | #if defined(DUK_USE_ES6_PROXY) |
| 41144 | duk_hobject *h_proxy_target; |
| 41145 | duk_hobject *h_proxy_handler; |
| 41146 | duk_hobject *h_trap_result; |
| 41147 | #endif |
| 41148 | duk_small_uint_t enum_flags; |
| 41149 | duk_int_t magic; |
| 41150 | |
| 41151 | DUK_ASSERT_TOP(thr, 1); |
| 41152 | |
| 41153 | magic = duk_get_current_magic(thr); |
| 41154 | if (magic == 3) { |
| 41155 | /* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs |
| 41156 | * and plain buffers pretend to be objects, so accept those too. |
| 41157 | */ |
| 41158 | obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 41159 | } else { |
| 41160 | /* ES2015: ToObject coerce. */ |
| 41161 | obj = duk_to_hobject(thr, 0); |
| 41162 | } |
| 41163 | DUK_ASSERT(obj != NULL); |
| 41164 | DUK_UNREF(obj); |
| 41165 | |
| 41166 | /* XXX: proxy chains */ |
| 41167 | |
| 41168 | #if defined(DUK_USE_ES6_PROXY) |
| 41169 | /* XXX: better sharing of code between proxy target call sites */ |
| 41170 | if (DUK_LIKELY(!duk_hobject_proxy_check(obj, |
| 41171 | &h_proxy_target, |
| 41172 | &h_proxy_handler))) { |
| 41173 | goto skip_proxy; |
| 41174 | } |
| 41175 | |
| 41176 | duk_push_hobject(thr, h_proxy_handler); |
| 41177 | if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) { |
| 41178 | /* Careful with reachability here: don't pop 'obj' before pushing |
| 41179 | * proxy target. |
| 41180 | */ |
| 41181 | DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead" )); |
| 41182 | duk_pop_2(thr); |
| 41183 | duk_push_hobject(thr, h_proxy_target); |
| 41184 | duk_replace(thr, 0); |
| 41185 | DUK_ASSERT_TOP(thr, 1); |
| 41186 | goto skip_proxy; |
| 41187 | } |
| 41188 | |
| 41189 | /* [ obj handler trap ] */ |
| 41190 | duk_insert(thr, -2); |
| 41191 | duk_push_hobject(thr, h_proxy_target); /* -> [ obj trap handler target ] */ |
| 41192 | duk_call_method(thr, 1 /*nargs*/); /* -> [ obj trap_result ] */ |
| 41193 | h_trap_result = duk_require_hobject(thr, -1); |
| 41194 | DUK_UNREF(h_trap_result); |
| 41195 | |
| 41196 | magic = duk_get_current_magic(thr); |
| 41197 | DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t))); |
| 41198 | enum_flags = duk__object_keys_enum_flags[magic]; |
| 41199 | |
| 41200 | duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags); |
| 41201 | return 1; |
| 41202 | |
| 41203 | skip_proxy: |
| 41204 | #endif /* DUK_USE_ES6_PROXY */ |
| 41205 | |
| 41206 | DUK_ASSERT_TOP(thr, 1); |
| 41207 | magic = duk_get_current_magic(thr); |
| 41208 | DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t))); |
| 41209 | enum_flags = duk__object_keys_enum_flags[magic]; |
| 41210 | return duk_hobject_get_enumerated_keys(thr, enum_flags); |
| 41211 | } |
| 41212 | #endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ |
| 41213 | |
| 41214 | #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN) |
| 41215 | DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_hthread *thr) { |
| 41216 | /* |
| 41217 | * magic = 0: Object.preventExtensions() |
| 41218 | * magic = 1: Reflect.preventExtensions() |
| 41219 | */ |
| 41220 | |
| 41221 | duk_hobject *h; |
| 41222 | duk_uint_t mask; |
| 41223 | duk_int_t magic; |
| 41224 | |
| 41225 | magic = duk_get_current_magic(thr); |
| 41226 | |
| 41227 | /* Silent success for lightfuncs and plain buffers always. */ |
| 41228 | mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER; |
| 41229 | |
| 41230 | /* Object.preventExtensions() silent success for non-object. */ |
| 41231 | if (magic == 0) { |
| 41232 | mask |= DUK_TYPE_MASK_UNDEFINED | |
| 41233 | DUK_TYPE_MASK_NULL | |
| 41234 | DUK_TYPE_MASK_BOOLEAN | |
| 41235 | DUK_TYPE_MASK_NUMBER | |
| 41236 | DUK_TYPE_MASK_STRING | |
| 41237 | DUK_TYPE_MASK_POINTER; |
| 41238 | } |
| 41239 | |
| 41240 | if (duk_check_type_mask(thr, 0, mask)) { |
| 41241 | /* Not an object, already non-extensible so always success. */ |
| 41242 | goto done; |
| 41243 | } |
| 41244 | h = duk_require_hobject(thr, 0); |
| 41245 | DUK_ASSERT(h != NULL); |
| 41246 | |
| 41247 | DUK_HOBJECT_CLEAR_EXTENSIBLE(h); |
| 41248 | |
| 41249 | /* A non-extensible object cannot gain any more properties, |
| 41250 | * so this is a good time to compact. |
| 41251 | */ |
| 41252 | duk_hobject_compact_props(thr, h); |
| 41253 | |
| 41254 | done: |
| 41255 | if (magic == 1) { |
| 41256 | duk_push_true(thr); |
| 41257 | } |
| 41258 | return 1; |
| 41259 | } |
| 41260 | #endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */ |
| 41261 | |
| 41262 | /* |
| 41263 | * __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__ |
| 41264 | */ |
| 41265 | |
| 41266 | #if defined(DUK_USE_ES8) |
| 41267 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) { |
| 41268 | duk_push_this(thr); |
| 41269 | duk_insert(thr, 0); |
| 41270 | duk_to_object(thr, 0); |
| 41271 | duk_require_callable(thr, 2); |
| 41272 | |
| 41273 | /* [ ToObject(this) key getter/setter ] */ |
| 41274 | |
| 41275 | /* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */ |
| 41276 | duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE | |
| 41277 | DUK_DEFPROP_SET_CONFIGURABLE | |
| 41278 | (duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER)); |
| 41279 | return 0; |
| 41280 | } |
| 41281 | DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) { |
| 41282 | duk_uint_t sanity; |
| 41283 | |
| 41284 | duk_push_this(thr); |
| 41285 | duk_to_object(thr, -1); |
| 41286 | |
| 41287 | /* XXX: Prototype walk (with sanity) should be a core property |
| 41288 | * operation, could add a flag to e.g. duk_get_prop_desc(). |
| 41289 | */ |
| 41290 | |
| 41291 | /* ToPropertyKey() coercion is not needed, duk_get_prop_desc() does it. */ |
| 41292 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 41293 | while (!duk_is_undefined(thr, -1)) { |
| 41294 | /* [ key obj ] */ |
| 41295 | duk_dup(thr, 0); |
| 41296 | duk_get_prop_desc(thr, 1, 0 /*flags*/); |
| 41297 | if (!duk_is_undefined(thr, -1)) { |
| 41298 | duk_get_prop_stridx(thr, -1, (duk_get_current_magic(thr) != 0 ? DUK_STRIDX_SET : DUK_STRIDX_GET)); |
| 41299 | return 1; |
| 41300 | } |
| 41301 | duk_pop(thr); |
| 41302 | |
| 41303 | if (DUK_UNLIKELY(sanity-- == 0)) { |
| 41304 | DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); |
| 41305 | DUK_WO_NORETURN(return 0;); |
| 41306 | } |
| 41307 | |
| 41308 | duk_get_prototype(thr, -1); |
| 41309 | duk_remove(thr, -2); |
| 41310 | } |
| 41311 | return 1; |
| 41312 | } |
| 41313 | #endif /* DUK_USE_ES8 */ |
| 41314 | #line 1 "duk_bi_performance.c" |
| 41315 | /* |
| 41316 | * High resolution time API (performance.now() et al) |
| 41317 | * |
| 41318 | * API specification: https://encoding.spec.whatwg.org/#ap://www.w3.org/TR/hr-time/ |
| 41319 | */ |
| 41320 | |
| 41321 | /* #include duk_internal.h -> already included */ |
| 41322 | |
| 41323 | #if defined(DUK_USE_PERFORMANCE_BUILTIN) |
| 41324 | DUK_INTERNAL duk_ret_t duk_bi_performance_now(duk_hthread *thr) { |
| 41325 | /* From API spec: |
| 41326 | * The DOMHighResTimeStamp type is used to store a time value in |
| 41327 | * milliseconds, measured relative from the time origin, global |
| 41328 | * monotonic clock, or a time value that represents a duration |
| 41329 | * between two DOMHighResTimeStamp's. |
| 41330 | */ |
| 41331 | duk_push_number(thr, duk_time_get_monotonic_time(thr)); |
| 41332 | return 1; |
| 41333 | } |
| 41334 | |
| 41335 | #if 0 /* Missing until semantics decided. */ |
| 41336 | DUK_INTERNAL duk_ret_t duk_bi_performance_timeorigin_getter(duk_hthread *thr) { |
| 41337 | /* No decision yet how to handle timeOrigins, e.g. should one be |
| 41338 | * initialized per heap, or per global object set. See |
| 41339 | * https://www.w3.org/TR/hr-time/#time-origin. |
| 41340 | */ |
| 41341 | duk_push_uint(thr, 0); |
| 41342 | return 1; |
| 41343 | } |
| 41344 | #endif /* 0 */ |
| 41345 | #endif /* DUK_USE_PERFORMANCE_BUILTIN */ |
| 41346 | #line 1 "duk_bi_pointer.c" |
| 41347 | /* |
| 41348 | * Pointer built-ins |
| 41349 | */ |
| 41350 | |
| 41351 | /* #include duk_internal.h -> already included */ |
| 41352 | |
| 41353 | /* |
| 41354 | * Constructor |
| 41355 | */ |
| 41356 | |
| 41357 | DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_hthread *thr) { |
| 41358 | /* XXX: this behavior is quite useless now; it would be nice to be able |
| 41359 | * to create pointer values from e.g. numbers or strings. Numbers are |
| 41360 | * problematic on 64-bit platforms though. Hex encoded strings? |
| 41361 | */ |
| 41362 | if (duk_get_top(thr) == 0) { |
| 41363 | duk_push_pointer(thr, NULL); |
| 41364 | } else { |
| 41365 | duk_to_pointer(thr, 0); |
| 41366 | } |
| 41367 | DUK_ASSERT(duk_is_pointer(thr, 0)); |
| 41368 | duk_set_top(thr, 1); |
| 41369 | |
| 41370 | if (duk_is_constructor_call(thr)) { |
| 41371 | (void) duk_push_object_helper(thr, |
| 41372 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 41373 | DUK_HOBJECT_FLAG_FASTREFS | |
| 41374 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER), |
| 41375 | DUK_BIDX_POINTER_PROTOTYPE); |
| 41376 | |
| 41377 | /* Pointer object internal value is immutable. */ |
| 41378 | duk_dup_0(thr); |
| 41379 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); |
| 41380 | } |
| 41381 | /* Note: unbalanced stack on purpose */ |
| 41382 | |
| 41383 | return 1; |
| 41384 | } |
| 41385 | |
| 41386 | /* |
| 41387 | * toString(), valueOf() |
| 41388 | */ |
| 41389 | |
| 41390 | DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr) { |
| 41391 | duk_tval *tv; |
| 41392 | duk_small_int_t to_string = duk_get_current_magic(thr); |
| 41393 | |
| 41394 | duk_push_this(thr); |
| 41395 | tv = duk_require_tval(thr, -1); |
| 41396 | DUK_ASSERT(tv != NULL); |
| 41397 | |
| 41398 | if (DUK_TVAL_IS_POINTER(tv)) { |
| 41399 | /* nop */ |
| 41400 | } else if (DUK_TVAL_IS_OBJECT(tv)) { |
| 41401 | duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); |
| 41402 | DUK_ASSERT(h != NULL); |
| 41403 | |
| 41404 | /* Must be a "pointer object", i.e. class "Pointer" */ |
| 41405 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) { |
| 41406 | goto type_error; |
| 41407 | } |
| 41408 | |
| 41409 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); |
| 41410 | } else { |
| 41411 | goto type_error; |
| 41412 | } |
| 41413 | |
| 41414 | if (to_string) { |
| 41415 | duk_to_string(thr, -1); |
| 41416 | } |
| 41417 | return 1; |
| 41418 | |
| 41419 | type_error: |
| 41420 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 41421 | } |
| 41422 | #line 1 "duk_bi_promise.c" |
| 41423 | /* |
| 41424 | * Promise built-in |
| 41425 | */ |
| 41426 | |
| 41427 | /* #include duk_internal.h -> already included */ |
| 41428 | |
| 41429 | #if defined(DUK_USE_PROMISE_BUILTIN) |
| 41430 | |
| 41431 | DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) { |
| 41432 | DUK_ERROR_TYPE(thr, "unimplemented" ); |
| 41433 | DUK_WO_NORETURN(return 0;); |
| 41434 | } |
| 41435 | |
| 41436 | DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) { |
| 41437 | DUK_ERROR_TYPE(thr, "unimplemented" ); |
| 41438 | DUK_WO_NORETURN(return 0;); |
| 41439 | } |
| 41440 | |
| 41441 | DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) { |
| 41442 | DUK_ERROR_TYPE(thr, "unimplemented" ); |
| 41443 | DUK_WO_NORETURN(return 0;); |
| 41444 | } |
| 41445 | |
| 41446 | DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) { |
| 41447 | DUK_ERROR_TYPE(thr, "unimplemented" ); |
| 41448 | DUK_WO_NORETURN(return 0;); |
| 41449 | } |
| 41450 | |
| 41451 | DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) { |
| 41452 | DUK_ERROR_TYPE(thr, "unimplemented" ); |
| 41453 | DUK_WO_NORETURN(return 0;); |
| 41454 | } |
| 41455 | |
| 41456 | DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) { |
| 41457 | DUK_ERROR_TYPE(thr, "unimplemented" ); |
| 41458 | DUK_WO_NORETURN(return 0;); |
| 41459 | } |
| 41460 | |
| 41461 | DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) { |
| 41462 | DUK_ERROR_TYPE(thr, "unimplemented" ); |
| 41463 | DUK_WO_NORETURN(return 0;); |
| 41464 | } |
| 41465 | |
| 41466 | #endif /* DUK_USE_PROMISE_BUILTIN */ |
| 41467 | #line 1 "duk_bi_proxy.c" |
| 41468 | /* |
| 41469 | * Proxy built-in (ES2015) |
| 41470 | */ |
| 41471 | |
| 41472 | /* #include duk_internal.h -> already included */ |
| 41473 | |
| 41474 | #if defined(DUK_USE_ES6_PROXY) |
| 41475 | /* Post-process a Proxy ownKeys() result at stack top. Push a cleaned up |
| 41476 | * array of valid result keys (strings or symbols). TypeError for invalid |
| 41477 | * values. Flags are shared with duk_enum(). |
| 41478 | */ |
| 41479 | DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) { |
| 41480 | duk_uarridx_t i, len, idx; |
| 41481 | duk_propdesc desc; |
| 41482 | |
| 41483 | DUK_CTX_ASSERT_VALID(thr); |
| 41484 | DUK_ASSERT(h_proxy_target != NULL); |
| 41485 | |
| 41486 | len = (duk_uarridx_t) duk_get_length(thr, -1); |
| 41487 | idx = 0; |
| 41488 | duk_push_array(thr); |
| 41489 | /* XXX: preallocated dense array, fill in directly */ |
| 41490 | for (i = 0; i < len; i++) { |
| 41491 | duk_hstring *h; |
| 41492 | |
| 41493 | /* [ obj trap_result res_arr ] */ |
| 41494 | (void) duk_get_prop_index(thr, -2, i); |
| 41495 | h = duk_get_hstring(thr, -1); |
| 41496 | if (h == NULL) { |
| 41497 | DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr); |
| 41498 | DUK_WO_NORETURN(return;); |
| 41499 | } |
| 41500 | |
| 41501 | if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) { |
| 41502 | /* No support for 'getOwnPropertyDescriptor' trap yet, |
| 41503 | * so check enumerability always from target object |
| 41504 | * descriptor. |
| 41505 | */ |
| 41506 | if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) { |
| 41507 | if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) { |
| 41508 | DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T" , duk_get_tval(thr, -1))); |
| 41509 | goto skip_key; |
| 41510 | } |
| 41511 | } else { |
| 41512 | DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T" , duk_get_tval(thr, -1))); |
| 41513 | goto skip_key; |
| 41514 | } |
| 41515 | } |
| 41516 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 41517 | if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) { |
| 41518 | DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T" , duk_get_tval(thr, -1))); |
| 41519 | goto skip_key; |
| 41520 | } |
| 41521 | if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) { |
| 41522 | DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T" , duk_get_tval(thr, -1))); |
| 41523 | goto skip_key; |
| 41524 | } |
| 41525 | } else { |
| 41526 | if (flags & DUK_ENUM_EXCLUDE_STRINGS) { |
| 41527 | DUK_DDD(DUK_DDDPRINT("ignore string property: %!T" , duk_get_tval(thr, -1))); |
| 41528 | goto skip_key; |
| 41529 | } |
| 41530 | } |
| 41531 | |
| 41532 | /* [ obj trap_result res_arr propname ] */ |
| 41533 | duk_push_uarridx(thr, idx++); |
| 41534 | duk_insert(thr, -2); |
| 41535 | duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WEC); |
| 41536 | continue; |
| 41537 | |
| 41538 | skip_key: |
| 41539 | duk_pop(thr); |
| 41540 | continue; |
| 41541 | } |
| 41542 | |
| 41543 | /* XXX: Missing trap result validation for non-configurable target keys |
| 41544 | * (must be present), for non-extensible target all target keys must be |
| 41545 | * present and no extra keys can be present. |
| 41546 | * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys |
| 41547 | */ |
| 41548 | |
| 41549 | /* XXX: The key enumerability check should trigger the "getOwnPropertyDescriptor" |
| 41550 | * trap which has not yet been implemented. In the absence of such a trap, |
| 41551 | * the enumerability should be checked from the target object; this is |
| 41552 | * handled above. |
| 41553 | */ |
| 41554 | } |
| 41555 | #endif /* DUK_USE_ES6_PROXY */ |
| 41556 | |
| 41557 | #if defined(DUK_USE_ES6_PROXY) |
| 41558 | DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_hthread *thr) { |
| 41559 | DUK_ASSERT_TOP(thr, 2); /* [ target handler ] */ |
| 41560 | |
| 41561 | duk_require_constructor_call(thr); |
| 41562 | duk_push_proxy(thr, 0 /*flags*/); /* [ target handler ] -> [ proxy ] */ |
| 41563 | return 1; /* replacement */ |
| 41564 | } |
| 41565 | #endif /* DUK_USE_ES6_PROXY */ |
| 41566 | #line 1 "duk_bi_reflect.c" |
| 41567 | /* |
| 41568 | * 'Reflect' built-in (ES2016 Section 26.1) |
| 41569 | * http://www.ecma-international.org/ecma-262/7.0/#sec-reflect-object |
| 41570 | * |
| 41571 | * Many Reflect built-in functions are provided by shared helpers in |
| 41572 | * duk_bi_object.c or duk_bi_function.c. |
| 41573 | */ |
| 41574 | |
| 41575 | /* #include duk_internal.h -> already included */ |
| 41576 | |
| 41577 | #if defined(DUK_USE_REFLECT_BUILTIN) |
| 41578 | DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_hthread *thr) { |
| 41579 | duk_tval *tv_obj; |
| 41580 | duk_tval *tv_key; |
| 41581 | duk_bool_t ret; |
| 41582 | |
| 41583 | DUK_ASSERT_TOP(thr, 2); |
| 41584 | (void) duk_require_hobject(thr, 0); |
| 41585 | (void) duk_to_string(thr, 1); |
| 41586 | |
| 41587 | /* [ target key ] */ |
| 41588 | |
| 41589 | DUK_ASSERT(thr != NULL); |
| 41590 | tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); |
| 41591 | tv_key = DUK_GET_TVAL_POSIDX(thr, 1); |
| 41592 | ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/); |
| 41593 | duk_push_boolean(thr, ret); |
| 41594 | return 1; |
| 41595 | } |
| 41596 | |
| 41597 | DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) { |
| 41598 | duk_tval *tv_obj; |
| 41599 | duk_tval *tv_key; |
| 41600 | duk_idx_t nargs; |
| 41601 | |
| 41602 | DUK_ASSERT(thr != NULL); |
| 41603 | nargs = duk_get_top_require_min(thr, 2 /*min_top*/); |
| 41604 | (void) duk_require_hobject(thr, 0); |
| 41605 | (void) duk_to_string(thr, 1); |
| 41606 | if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) { |
| 41607 | /* XXX: [[Get]] receiver currently unsupported */ |
| 41608 | DUK_ERROR_UNSUPPORTED(thr); |
| 41609 | DUK_WO_NORETURN(return 0;); |
| 41610 | } |
| 41611 | |
| 41612 | /* [ target key receiver? ...? ] */ |
| 41613 | |
| 41614 | tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); |
| 41615 | tv_key = DUK_GET_TVAL_POSIDX(thr, 1); |
| 41616 | (void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */ |
| 41617 | return 1; |
| 41618 | } |
| 41619 | |
| 41620 | DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_hthread *thr) { |
| 41621 | duk_tval *tv_obj; |
| 41622 | duk_tval *tv_key; |
| 41623 | duk_bool_t ret; |
| 41624 | |
| 41625 | DUK_ASSERT(thr != NULL); |
| 41626 | DUK_ASSERT_TOP(thr, 2); |
| 41627 | (void) duk_require_hobject(thr, 0); |
| 41628 | (void) duk_to_string(thr, 1); |
| 41629 | |
| 41630 | /* [ target key ] */ |
| 41631 | |
| 41632 | tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); |
| 41633 | tv_key = DUK_GET_TVAL_POSIDX(thr, 1); |
| 41634 | ret = duk_hobject_hasprop(thr, tv_obj, tv_key); |
| 41635 | duk_push_boolean(thr, ret); |
| 41636 | return 1; |
| 41637 | } |
| 41638 | |
| 41639 | DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) { |
| 41640 | duk_tval *tv_obj; |
| 41641 | duk_tval *tv_key; |
| 41642 | duk_tval *tv_val; |
| 41643 | duk_idx_t nargs; |
| 41644 | duk_bool_t ret; |
| 41645 | |
| 41646 | DUK_ASSERT(thr != NULL); |
| 41647 | nargs = duk_get_top_require_min(thr, 3 /*min_top*/); |
| 41648 | (void) duk_require_hobject(thr, 0); |
| 41649 | (void) duk_to_string(thr, 1); |
| 41650 | if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) { |
| 41651 | /* XXX: [[Set]] receiver currently unsupported */ |
| 41652 | DUK_ERROR_UNSUPPORTED(thr); |
| 41653 | DUK_WO_NORETURN(return 0;); |
| 41654 | } |
| 41655 | |
| 41656 | /* [ target key value receiver? ...? ] */ |
| 41657 | |
| 41658 | tv_obj = DUK_GET_TVAL_POSIDX(thr, 0); |
| 41659 | tv_key = DUK_GET_TVAL_POSIDX(thr, 1); |
| 41660 | tv_val = DUK_GET_TVAL_POSIDX(thr, 2); |
| 41661 | ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/); |
| 41662 | duk_push_boolean(thr, ret); |
| 41663 | return 1; |
| 41664 | } |
| 41665 | #endif /* DUK_USE_REFLECT_BUILTIN */ |
| 41666 | #line 1 "duk_bi_regexp.c" |
| 41667 | /* |
| 41668 | * RegExp built-ins |
| 41669 | */ |
| 41670 | |
| 41671 | /* #include duk_internal.h -> already included */ |
| 41672 | |
| 41673 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 41674 | |
| 41675 | DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) { |
| 41676 | duk_hobject *h; |
| 41677 | |
| 41678 | duk_push_this(thr); |
| 41679 | h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP); |
| 41680 | DUK_ASSERT(h != NULL); |
| 41681 | DUK_UNREF(h); |
| 41682 | duk_insert(thr, 0); /* prepend regexp to valstack 0 index */ |
| 41683 | } |
| 41684 | |
| 41685 | /* XXX: much to improve (code size) */ |
| 41686 | DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_hthread *thr) { |
| 41687 | duk_hobject *h_pattern; |
| 41688 | |
| 41689 | DUK_ASSERT_TOP(thr, 2); |
| 41690 | h_pattern = duk_get_hobject(thr, 0); |
| 41691 | |
| 41692 | if (!duk_is_constructor_call(thr) && |
| 41693 | h_pattern != NULL && |
| 41694 | DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP && |
| 41695 | duk_is_undefined(thr, 1)) { |
| 41696 | /* Called as a function, pattern has [[Class]] "RegExp" and |
| 41697 | * flags is undefined -> return object as is. |
| 41698 | */ |
| 41699 | /* XXX: ES2015 has a NewTarget SameValue() check which is not |
| 41700 | * yet implemented. |
| 41701 | */ |
| 41702 | duk_dup_0(thr); |
| 41703 | return 1; |
| 41704 | } |
| 41705 | |
| 41706 | /* Else functionality is identical for function call and constructor |
| 41707 | * call. |
| 41708 | */ |
| 41709 | |
| 41710 | if (h_pattern != NULL && |
| 41711 | DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) { |
| 41712 | duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_SOURCE); |
| 41713 | if (duk_is_undefined(thr, 1)) { |
| 41714 | /* In ES5 one would need to read the flags individually; |
| 41715 | * in ES2015 just read .flags. |
| 41716 | */ |
| 41717 | duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS); |
| 41718 | } else { |
| 41719 | /* In ES2015 allowed; overrides argument RegExp flags. */ |
| 41720 | duk_dup_1(thr); |
| 41721 | } |
| 41722 | } else { |
| 41723 | if (duk_is_undefined(thr, 0)) { |
| 41724 | duk_push_hstring_empty(thr); |
| 41725 | } else { |
| 41726 | duk_dup_0(thr); |
| 41727 | duk_to_string(thr, -1); /* Rejects Symbols. */ |
| 41728 | } |
| 41729 | if (duk_is_undefined(thr, 1)) { |
| 41730 | duk_push_hstring_empty(thr); |
| 41731 | } else { |
| 41732 | duk_dup_1(thr); |
| 41733 | duk_to_string(thr, -1); /* Rejects Symbols. */ |
| 41734 | } |
| 41735 | |
| 41736 | /* [ ... pattern flags ] */ |
| 41737 | } |
| 41738 | |
| 41739 | DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T" , |
| 41740 | (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1))); |
| 41741 | |
| 41742 | /* [ ... pattern flags ] (both uncoerced) */ |
| 41743 | |
| 41744 | duk_to_string(thr, -2); |
| 41745 | duk_to_string(thr, -1); |
| 41746 | duk_regexp_compile(thr); |
| 41747 | |
| 41748 | /* [ ... bytecode escaped_source ] */ |
| 41749 | |
| 41750 | duk_regexp_create_instance(thr); |
| 41751 | |
| 41752 | /* [ ... RegExp ] */ |
| 41753 | |
| 41754 | return 1; |
| 41755 | } |
| 41756 | |
| 41757 | DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_hthread *thr) { |
| 41758 | duk__get_this_regexp(thr); |
| 41759 | |
| 41760 | /* [ regexp input ] */ |
| 41761 | |
| 41762 | duk_regexp_match(thr); |
| 41763 | |
| 41764 | /* [ result ] */ |
| 41765 | |
| 41766 | return 1; |
| 41767 | } |
| 41768 | |
| 41769 | DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_hthread *thr) { |
| 41770 | duk__get_this_regexp(thr); |
| 41771 | |
| 41772 | /* [ regexp input ] */ |
| 41773 | |
| 41774 | /* result object is created and discarded; wasteful but saves code space */ |
| 41775 | duk_regexp_match(thr); |
| 41776 | |
| 41777 | /* [ result ] */ |
| 41778 | |
| 41779 | duk_push_boolean(thr, (duk_is_null(thr, -1) ? 0 : 1)); |
| 41780 | |
| 41781 | return 1; |
| 41782 | } |
| 41783 | |
| 41784 | DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) { |
| 41785 | /* This must be generic in ES2015 and later. */ |
| 41786 | DUK_ASSERT_TOP(thr, 0); |
| 41787 | duk_push_this(thr); |
| 41788 | duk_push_literal(thr, "/" ); |
| 41789 | duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE); |
| 41790 | duk_dup_m2(thr); /* another "/" */ |
| 41791 | duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS); |
| 41792 | duk_concat(thr, 4); |
| 41793 | return 1; |
| 41794 | } |
| 41795 | |
| 41796 | DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_hthread *thr) { |
| 41797 | /* .flags is ES2015 but present even when ES2015 bindings are |
| 41798 | * disabled because the constructor relies on it. |
| 41799 | */ |
| 41800 | duk_uint8_t buf[8]; /* enough for all flags + NUL */ |
| 41801 | duk_uint8_t *p = buf; |
| 41802 | |
| 41803 | /* .flags is generic and works on any object. */ |
| 41804 | duk_push_this(thr); |
| 41805 | (void) duk_require_hobject(thr, -1); |
| 41806 | if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL)) { |
| 41807 | *p++ = DUK_ASC_LC_G; |
| 41808 | } |
| 41809 | if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_IGNORE_CASE, NULL)) { |
| 41810 | *p++ = DUK_ASC_LC_I; |
| 41811 | } |
| 41812 | if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_MULTILINE, NULL)) { |
| 41813 | *p++ = DUK_ASC_LC_M; |
| 41814 | } |
| 41815 | /* .unicode: to be added */ |
| 41816 | /* .sticky: to be added */ |
| 41817 | *p++ = DUK_ASC_NUL; |
| 41818 | DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf)); |
| 41819 | |
| 41820 | duk_push_string(thr, (const char *) buf); |
| 41821 | return 1; |
| 41822 | } |
| 41823 | |
| 41824 | /* Shared helper for providing .source, .global, .multiline, etc getters. */ |
| 41825 | DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) { |
| 41826 | duk_hstring *h_bc; |
| 41827 | duk_small_uint_t re_flags; |
| 41828 | duk_hobject *h; |
| 41829 | duk_int_t magic; |
| 41830 | |
| 41831 | DUK_ASSERT_TOP(thr, 0); |
| 41832 | |
| 41833 | duk_push_this(thr); |
| 41834 | h = duk_require_hobject(thr, -1); |
| 41835 | magic = duk_get_current_magic(thr); |
| 41836 | |
| 41837 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) { |
| 41838 | duk_xget_owndataprop_stridx_short(thr, 0, DUK_STRIDX_INT_SOURCE); |
| 41839 | duk_xget_owndataprop_stridx_short(thr, 0, DUK_STRIDX_INT_BYTECODE); |
| 41840 | h_bc = duk_require_hstring(thr, -1); |
| 41841 | re_flags = (duk_small_uint_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */ |
| 41842 | duk_pop(thr); |
| 41843 | } else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) { |
| 41844 | /* In ES2015 and ES2016 a TypeError would be thrown here. |
| 41845 | * However, this had real world issues so ES2017 draft |
| 41846 | * allows RegExp.prototype specifically, returning '(?:)' |
| 41847 | * for .source and undefined for all flags. |
| 41848 | */ |
| 41849 | if (magic != 16 /* .source */) { |
| 41850 | return 0; |
| 41851 | } |
| 41852 | duk_push_literal(thr, "(?:)" ); /* .source handled by switch-case */ |
| 41853 | re_flags = 0; |
| 41854 | } else { |
| 41855 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 41856 | } |
| 41857 | |
| 41858 | /* [ regexp source ] */ |
| 41859 | |
| 41860 | switch (magic) { |
| 41861 | case 0: { /* global */ |
| 41862 | duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_GLOBAL)); |
| 41863 | break; |
| 41864 | } |
| 41865 | case 1: { /* ignoreCase */ |
| 41866 | duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_IGNORE_CASE)); |
| 41867 | break; |
| 41868 | } |
| 41869 | case 2: { /* multiline */ |
| 41870 | duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_MULTILINE)); |
| 41871 | break; |
| 41872 | } |
| 41873 | #if 0 |
| 41874 | /* Don't provide until implemented to avoid interfering with feature |
| 41875 | * detection in user code. |
| 41876 | */ |
| 41877 | case 3: /* sticky */ |
| 41878 | case 4: { /* unicode */ |
| 41879 | duk_push_false(thr); |
| 41880 | break; |
| 41881 | } |
| 41882 | #endif |
| 41883 | default: { /* source */ |
| 41884 | /* leave 'source' on top */ |
| 41885 | break; |
| 41886 | } |
| 41887 | } |
| 41888 | |
| 41889 | return 1; |
| 41890 | } |
| 41891 | |
| 41892 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 41893 | #line 1 "duk_bi_string.c" |
| 41894 | /* |
| 41895 | * String built-ins |
| 41896 | * |
| 41897 | * Most String built-ins must only accept strings (or String objects). |
| 41898 | * Symbols, represented internally as strings, must be generally rejected. |
| 41899 | * The duk_push_this_coercible_to_string() helper does this automatically. |
| 41900 | */ |
| 41901 | |
| 41902 | /* XXX: There are several limitations in the current implementation for |
| 41903 | * strings with >= 0x80000000UL characters. In some cases one would need |
| 41904 | * to be able to represent the range [-0xffffffff,0xffffffff] and so on. |
| 41905 | * Generally character and byte length are assumed to fit into signed 32 |
| 41906 | * bits (< 0x80000000UL). Places with issues are not marked explicitly |
| 41907 | * below in all cases, look for signed type usage (duk_int_t etc) for |
| 41908 | * offsets/lengths. |
| 41909 | */ |
| 41910 | |
| 41911 | /* #include duk_internal.h -> already included */ |
| 41912 | |
| 41913 | #if defined(DUK_USE_STRING_BUILTIN) |
| 41914 | |
| 41915 | /* |
| 41916 | * Helpers |
| 41917 | */ |
| 41918 | |
| 41919 | DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t idx) { |
| 41920 | duk_hstring *h; |
| 41921 | |
| 41922 | if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) { |
| 41923 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 41924 | DUK_WO_NORETURN(return NULL;); |
| 41925 | } |
| 41926 | h = duk_to_hstring(thr, idx); |
| 41927 | DUK_ASSERT(h != NULL); |
| 41928 | |
| 41929 | return h; |
| 41930 | } |
| 41931 | |
| 41932 | DUK_LOCAL duk_int_t duk__str_search_shared(duk_hthread *thr, duk_hstring *h_this, duk_hstring *h_search, duk_int_t start_cpos, duk_bool_t backwards) { |
| 41933 | duk_int_t cpos; |
| 41934 | duk_int_t bpos; |
| 41935 | const duk_uint8_t *p_start, *p_end, *p; |
| 41936 | const duk_uint8_t *q_start; |
| 41937 | duk_int_t q_blen; |
| 41938 | duk_uint8_t firstbyte; |
| 41939 | duk_uint8_t t; |
| 41940 | |
| 41941 | cpos = start_cpos; |
| 41942 | |
| 41943 | /* Empty searchstring always matches; cpos must be clamped here. |
| 41944 | * (If q_blen were < 0 due to clamped coercion, it would also be |
| 41945 | * caught here.) |
| 41946 | */ |
| 41947 | q_start = DUK_HSTRING_GET_DATA(h_search); |
| 41948 | q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search); |
| 41949 | if (q_blen <= 0) { |
| 41950 | return cpos; |
| 41951 | } |
| 41952 | DUK_ASSERT(q_blen > 0); |
| 41953 | |
| 41954 | bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos); |
| 41955 | |
| 41956 | p_start = DUK_HSTRING_GET_DATA(h_this); |
| 41957 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this); |
| 41958 | p = p_start + bpos; |
| 41959 | |
| 41960 | /* This loop is optimized for size. For speed, there should be |
| 41961 | * two separate loops, and we should ensure that memcmp() can be |
| 41962 | * used without an extra "will searchstring fit" check. Doing |
| 41963 | * the preconditioning for 'p' and 'p_end' is easy but cpos |
| 41964 | * must be updated if 'p' is wound back (backward scanning). |
| 41965 | */ |
| 41966 | |
| 41967 | firstbyte = q_start[0]; /* leading byte of match string */ |
| 41968 | while (p <= p_end && p >= p_start) { |
| 41969 | t = *p; |
| 41970 | |
| 41971 | /* For ECMAScript strings, this check can only match for |
| 41972 | * initial UTF-8 bytes (not continuation bytes). For other |
| 41973 | * strings all bets are off. |
| 41974 | */ |
| 41975 | |
| 41976 | if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) { |
| 41977 | DUK_ASSERT(q_blen > 0); |
| 41978 | if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { |
| 41979 | return cpos; |
| 41980 | } |
| 41981 | } |
| 41982 | |
| 41983 | /* track cpos while scanning */ |
| 41984 | if (backwards) { |
| 41985 | /* when going backwards, we decrement cpos 'early'; |
| 41986 | * 'p' may point to a continuation byte of the char |
| 41987 | * at offset 'cpos', but that's OK because we'll |
| 41988 | * backtrack all the way to the initial byte. |
| 41989 | */ |
| 41990 | if ((t & 0xc0) != 0x80) { |
| 41991 | cpos--; |
| 41992 | } |
| 41993 | p--; |
| 41994 | } else { |
| 41995 | if ((t & 0xc0) != 0x80) { |
| 41996 | cpos++; |
| 41997 | } |
| 41998 | p++; |
| 41999 | } |
| 42000 | } |
| 42001 | |
| 42002 | /* Not found. Empty string case is handled specially above. */ |
| 42003 | return -1; |
| 42004 | } |
| 42005 | |
| 42006 | /* |
| 42007 | * Constructor |
| 42008 | */ |
| 42009 | |
| 42010 | DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_hthread *thr) { |
| 42011 | duk_hstring *h; |
| 42012 | duk_uint_t flags; |
| 42013 | |
| 42014 | /* String constructor needs to distinguish between an argument not given at all |
| 42015 | * vs. given as 'undefined'. We're a vararg function to handle this properly. |
| 42016 | */ |
| 42017 | |
| 42018 | /* XXX: copy current activation flags to thr, including current magic, |
| 42019 | * is_constructor_call etc. This takes a few bytes in duk_hthread but |
| 42020 | * makes call sites smaller (there are >30 is_constructor_call and get |
| 42021 | * current magic call sites. |
| 42022 | */ |
| 42023 | |
| 42024 | if (duk_get_top(thr) == 0) { |
| 42025 | duk_push_hstring_empty(thr); |
| 42026 | } else { |
| 42027 | h = duk_to_hstring_acceptsymbol(thr, 0); |
| 42028 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(thr))) { |
| 42029 | duk_push_symbol_descriptive_string(thr, h); |
| 42030 | duk_replace(thr, 0); |
| 42031 | } |
| 42032 | } |
| 42033 | duk_to_string(thr, 0); /* catches symbol argument for constructor call */ |
| 42034 | DUK_ASSERT(duk_is_string(thr, 0)); |
| 42035 | duk_set_top(thr, 1); /* Top may be 1 or larger. */ |
| 42036 | |
| 42037 | if (duk_is_constructor_call(thr)) { |
| 42038 | /* String object internal value is immutable */ |
| 42039 | flags = DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 42040 | DUK_HOBJECT_FLAG_FASTREFS | |
| 42041 | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | |
| 42042 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING); |
| 42043 | duk_push_object_helper(thr, flags, DUK_BIDX_STRING_PROTOTYPE); |
| 42044 | duk_dup_0(thr); |
| 42045 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); |
| 42046 | } |
| 42047 | /* Note: unbalanced stack on purpose */ |
| 42048 | |
| 42049 | return 1; |
| 42050 | } |
| 42051 | |
| 42052 | DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_hthread *thr, duk_bool_t nonbmp) { |
| 42053 | duk_bufwriter_ctx bw_alloc; |
| 42054 | duk_bufwriter_ctx *bw; |
| 42055 | duk_idx_t i, n; |
| 42056 | duk_ucodepoint_t cp; |
| 42057 | |
| 42058 | /* XXX: It would be nice to build the string directly but ToUint16() |
| 42059 | * coercion is needed so a generic helper would not be very |
| 42060 | * helpful (perhaps coerce the value stack first here and then |
| 42061 | * build a string from a duk_tval number sequence in one go?). |
| 42062 | */ |
| 42063 | |
| 42064 | n = duk_get_top(thr); |
| 42065 | |
| 42066 | bw = &bw_alloc; |
| 42067 | DUK_BW_INIT_PUSHBUF(thr, bw, (duk_size_t) n); /* initial estimate for ASCII only codepoints */ |
| 42068 | |
| 42069 | for (i = 0; i < n; i++) { |
| 42070 | /* XXX: could improve bufwriter handling to write multiple codepoints |
| 42071 | * with one ensure call but the relative benefit would be quite small. |
| 42072 | */ |
| 42073 | |
| 42074 | if (nonbmp) { |
| 42075 | /* ES2015 requires that (1) SameValue(cp, ToInteger(cp)) and |
| 42076 | * (2) cp >= 0 and cp <= 0x10ffff. This check does not |
| 42077 | * implement the steps exactly but the outcome should be |
| 42078 | * the same. |
| 42079 | */ |
| 42080 | duk_int32_t i32 = 0; |
| 42081 | if (!duk_is_whole_get_int32(duk_to_number(thr, i), &i32) || |
| 42082 | i32 < 0 || i32 > 0x10ffffL) { |
| 42083 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 42084 | } |
| 42085 | DUK_ASSERT(i32 >= 0 && i32 <= 0x10ffffL); |
| 42086 | cp = (duk_ucodepoint_t) i32; |
| 42087 | DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp); |
| 42088 | } else { |
| 42089 | #if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT) |
| 42090 | /* ToUint16() coercion is mandatory in the E5.1 specification, but |
| 42091 | * this non-compliant behavior makes more sense because we support |
| 42092 | * non-BMP codepoints. Don't use CESU-8 because that'd create |
| 42093 | * surrogate pairs. |
| 42094 | */ |
| 42095 | cp = (duk_ucodepoint_t) duk_to_uint32(thr, i); |
| 42096 | DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp); |
| 42097 | #else |
| 42098 | cp = (duk_ucodepoint_t) duk_to_uint16(thr, i); |
| 42099 | DUK_ASSERT(cp >= 0 && cp <= 0x10ffffL); |
| 42100 | DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp); |
| 42101 | #endif |
| 42102 | } |
| 42103 | } |
| 42104 | |
| 42105 | DUK_BW_COMPACT(thr, bw); |
| 42106 | (void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 or CESU-8 encoded. */ |
| 42107 | return 1; |
| 42108 | } |
| 42109 | |
| 42110 | DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_hthread *thr) { |
| 42111 | return duk__construct_from_codepoints(thr, 0 /*nonbmp*/); |
| 42112 | } |
| 42113 | |
| 42114 | #if defined(DUK_USE_ES6) |
| 42115 | DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_hthread *thr) { |
| 42116 | return duk__construct_from_codepoints(thr, 1 /*nonbmp*/); |
| 42117 | } |
| 42118 | #endif |
| 42119 | |
| 42120 | /* |
| 42121 | * toString(), valueOf() |
| 42122 | */ |
| 42123 | |
| 42124 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) { |
| 42125 | duk_tval *tv; |
| 42126 | |
| 42127 | duk_push_this(thr); |
| 42128 | tv = duk_require_tval(thr, -1); |
| 42129 | DUK_ASSERT(tv != NULL); |
| 42130 | |
| 42131 | if (DUK_TVAL_IS_STRING(tv)) { |
| 42132 | /* return as is */ |
| 42133 | } else if (DUK_TVAL_IS_OBJECT(tv)) { |
| 42134 | duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); |
| 42135 | DUK_ASSERT(h != NULL); |
| 42136 | |
| 42137 | /* Must be a "string object", i.e. class "String" */ |
| 42138 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) { |
| 42139 | goto type_error; |
| 42140 | } |
| 42141 | |
| 42142 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE); |
| 42143 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 42144 | } else { |
| 42145 | goto type_error; |
| 42146 | } |
| 42147 | |
| 42148 | (void) duk_require_hstring_notsymbol(thr, -1); /* Reject symbols (and wrapped symbols). */ |
| 42149 | return 1; |
| 42150 | |
| 42151 | type_error: |
| 42152 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 42153 | } |
| 42154 | |
| 42155 | /* |
| 42156 | * Character and charcode access |
| 42157 | */ |
| 42158 | |
| 42159 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) { |
| 42160 | duk_hstring *h; |
| 42161 | duk_int_t pos; |
| 42162 | |
| 42163 | /* XXX: faster implementation */ |
| 42164 | |
| 42165 | h = duk_push_this_coercible_to_string(thr); |
| 42166 | DUK_ASSERT(h != NULL); |
| 42167 | |
| 42168 | pos = duk_to_int(thr, 0); |
| 42169 | |
| 42170 | if (sizeof(duk_size_t) >= sizeof(duk_uint_t)) { |
| 42171 | /* Cast to duk_size_t works in this case: |
| 42172 | * - If pos < 0, (duk_size_t) pos will always be |
| 42173 | * >= max_charlen, and result will be the empty string |
| 42174 | * (see duk_substring()). |
| 42175 | * - If pos >= 0, pos + 1 cannot wrap. |
| 42176 | */ |
| 42177 | DUK_ASSERT((duk_size_t) DUK_INT_MIN >= DUK_HSTRING_MAX_BYTELEN); |
| 42178 | DUK_ASSERT((duk_size_t) DUK_INT_MAX + 1U > (duk_size_t) DUK_INT_MAX); |
| 42179 | duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U); |
| 42180 | } else { |
| 42181 | /* If size_t is smaller than int, explicit bounds checks |
| 42182 | * are needed because an int may wrap multiple times. |
| 42183 | */ |
| 42184 | if (DUK_UNLIKELY(pos < 0 || (duk_uint_t) pos >= (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h))) { |
| 42185 | duk_push_hstring_empty(thr); |
| 42186 | } else { |
| 42187 | duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U); |
| 42188 | } |
| 42189 | } |
| 42190 | |
| 42191 | return 1; |
| 42192 | } |
| 42193 | |
| 42194 | /* Magic: 0=charCodeAt, 1=codePointAt */ |
| 42195 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_hthread *thr) { |
| 42196 | duk_int_t pos; |
| 42197 | duk_hstring *h; |
| 42198 | duk_bool_t clamped; |
| 42199 | duk_uint32_t cp; |
| 42200 | duk_int_t magic; |
| 42201 | |
| 42202 | /* XXX: faster implementation */ |
| 42203 | |
| 42204 | DUK_DDD(DUK_DDDPRINT("arg=%!T" , (duk_tval *) duk_get_tval(thr, 0))); |
| 42205 | |
| 42206 | h = duk_push_this_coercible_to_string(thr); |
| 42207 | DUK_ASSERT(h != NULL); |
| 42208 | |
| 42209 | pos = duk_to_int_clamped_raw(thr, |
| 42210 | 0 /*index*/, |
| 42211 | 0 /*min(incl)*/, |
| 42212 | (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/, |
| 42213 | &clamped /*out_clamped*/); |
| 42214 | #if defined(DUK_USE_ES6) |
| 42215 | magic = duk_get_current_magic(thr); |
| 42216 | #else |
| 42217 | DUK_ASSERT(duk_get_current_magic(thr) == 0); |
| 42218 | magic = 0; |
| 42219 | #endif |
| 42220 | if (clamped) { |
| 42221 | /* For out-of-bounds indices .charCodeAt() returns NaN and |
| 42222 | * .codePointAt() returns undefined. |
| 42223 | */ |
| 42224 | if (magic != 0) { |
| 42225 | return 0; |
| 42226 | } |
| 42227 | duk_push_nan(thr); |
| 42228 | } else { |
| 42229 | DUK_ASSERT(pos >= 0); |
| 42230 | cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) pos, (duk_bool_t) magic /*surrogate_aware*/); |
| 42231 | duk_push_u32(thr, cp); |
| 42232 | } |
| 42233 | return 1; |
| 42234 | } |
| 42235 | |
| 42236 | /* |
| 42237 | * substring(), substr(), slice() |
| 42238 | */ |
| 42239 | |
| 42240 | /* XXX: any chance of merging these three similar but still slightly |
| 42241 | * different algorithms so that footprint would be reduced? |
| 42242 | */ |
| 42243 | |
| 42244 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_hthread *thr) { |
| 42245 | duk_hstring *h; |
| 42246 | duk_int_t start_pos, end_pos; |
| 42247 | duk_int_t len; |
| 42248 | |
| 42249 | h = duk_push_this_coercible_to_string(thr); |
| 42250 | DUK_ASSERT(h != NULL); |
| 42251 | len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); |
| 42252 | |
| 42253 | /* [ start end str ] */ |
| 42254 | |
| 42255 | start_pos = duk_to_int_clamped(thr, 0, 0, len); |
| 42256 | if (duk_is_undefined(thr, 1)) { |
| 42257 | end_pos = len; |
| 42258 | } else { |
| 42259 | end_pos = duk_to_int_clamped(thr, 1, 0, len); |
| 42260 | } |
| 42261 | DUK_ASSERT(start_pos >= 0 && start_pos <= len); |
| 42262 | DUK_ASSERT(end_pos >= 0 && end_pos <= len); |
| 42263 | |
| 42264 | if (start_pos > end_pos) { |
| 42265 | duk_int_t tmp = start_pos; |
| 42266 | start_pos = end_pos; |
| 42267 | end_pos = tmp; |
| 42268 | } |
| 42269 | |
| 42270 | DUK_ASSERT(end_pos >= start_pos); |
| 42271 | |
| 42272 | duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos); |
| 42273 | return 1; |
| 42274 | } |
| 42275 | |
| 42276 | #if defined(DUK_USE_SECTION_B) |
| 42277 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_hthread *thr) { |
| 42278 | duk_hstring *h; |
| 42279 | duk_int_t start_pos, end_pos; |
| 42280 | duk_int_t len; |
| 42281 | |
| 42282 | /* Unlike non-obsolete String calls, substr() algorithm in E5.1 |
| 42283 | * specification will happily coerce undefined and null to strings |
| 42284 | * ("undefined" and "null"). |
| 42285 | */ |
| 42286 | duk_push_this(thr); |
| 42287 | h = duk_to_hstring_m1(thr); /* Reject Symbols. */ |
| 42288 | DUK_ASSERT(h != NULL); |
| 42289 | len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); |
| 42290 | |
| 42291 | /* [ start length str ] */ |
| 42292 | |
| 42293 | /* The implementation for computing of start_pos and end_pos differs |
| 42294 | * from the standard algorithm, but is intended to result in the exactly |
| 42295 | * same behavior. This is not always obvious. |
| 42296 | */ |
| 42297 | |
| 42298 | /* combines steps 2 and 5; -len ensures max() not needed for step 5 */ |
| 42299 | start_pos = duk_to_int_clamped(thr, 0, -len, len); |
| 42300 | if (start_pos < 0) { |
| 42301 | start_pos = len + start_pos; |
| 42302 | } |
| 42303 | DUK_ASSERT(start_pos >= 0 && start_pos <= len); |
| 42304 | |
| 42305 | /* combines steps 3, 6; step 7 is not needed */ |
| 42306 | if (duk_is_undefined(thr, 1)) { |
| 42307 | end_pos = len; |
| 42308 | } else { |
| 42309 | DUK_ASSERT(start_pos <= len); |
| 42310 | end_pos = start_pos + duk_to_int_clamped(thr, 1, 0, len - start_pos); |
| 42311 | } |
| 42312 | DUK_ASSERT(start_pos >= 0 && start_pos <= len); |
| 42313 | DUK_ASSERT(end_pos >= 0 && end_pos <= len); |
| 42314 | DUK_ASSERT(end_pos >= start_pos); |
| 42315 | |
| 42316 | duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos); |
| 42317 | return 1; |
| 42318 | } |
| 42319 | #endif /* DUK_USE_SECTION_B */ |
| 42320 | |
| 42321 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_hthread *thr) { |
| 42322 | duk_hstring *h; |
| 42323 | duk_int_t start_pos, end_pos; |
| 42324 | duk_int_t len; |
| 42325 | |
| 42326 | h = duk_push_this_coercible_to_string(thr); |
| 42327 | DUK_ASSERT(h != NULL); |
| 42328 | len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); |
| 42329 | |
| 42330 | /* [ start end str ] */ |
| 42331 | |
| 42332 | start_pos = duk_to_int_clamped(thr, 0, -len, len); |
| 42333 | if (start_pos < 0) { |
| 42334 | start_pos = len + start_pos; |
| 42335 | } |
| 42336 | if (duk_is_undefined(thr, 1)) { |
| 42337 | end_pos = len; |
| 42338 | } else { |
| 42339 | end_pos = duk_to_int_clamped(thr, 1, -len, len); |
| 42340 | if (end_pos < 0) { |
| 42341 | end_pos = len + end_pos; |
| 42342 | } |
| 42343 | } |
| 42344 | DUK_ASSERT(start_pos >= 0 && start_pos <= len); |
| 42345 | DUK_ASSERT(end_pos >= 0 && end_pos <= len); |
| 42346 | |
| 42347 | if (end_pos < start_pos) { |
| 42348 | end_pos = start_pos; |
| 42349 | } |
| 42350 | |
| 42351 | DUK_ASSERT(end_pos >= start_pos); |
| 42352 | |
| 42353 | duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos); |
| 42354 | return 1; |
| 42355 | } |
| 42356 | |
| 42357 | /* |
| 42358 | * Case conversion |
| 42359 | */ |
| 42360 | |
| 42361 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_hthread *thr) { |
| 42362 | duk_small_int_t uppercase = duk_get_current_magic(thr); |
| 42363 | |
| 42364 | (void) duk_push_this_coercible_to_string(thr); |
| 42365 | duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase); |
| 42366 | return 1; |
| 42367 | } |
| 42368 | |
| 42369 | /* |
| 42370 | * indexOf() and lastIndexOf() |
| 42371 | */ |
| 42372 | |
| 42373 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_hthread *thr) { |
| 42374 | duk_hstring *h_this; |
| 42375 | duk_hstring *h_search; |
| 42376 | duk_int_t clen_this; |
| 42377 | duk_int_t cpos; |
| 42378 | duk_small_uint_t is_lastindexof = (duk_small_uint_t) duk_get_current_magic(thr); /* 0=indexOf, 1=lastIndexOf */ |
| 42379 | |
| 42380 | h_this = duk_push_this_coercible_to_string(thr); |
| 42381 | DUK_ASSERT(h_this != NULL); |
| 42382 | clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this); |
| 42383 | |
| 42384 | h_search = duk_to_hstring(thr, 0); |
| 42385 | DUK_ASSERT(h_search != NULL); |
| 42386 | |
| 42387 | duk_to_number(thr, 1); |
| 42388 | if (duk_is_nan(thr, 1) && is_lastindexof) { |
| 42389 | /* indexOf: NaN should cause pos to be zero. |
| 42390 | * lastIndexOf: NaN should cause pos to be +Infinity |
| 42391 | * (and later be clamped to len). |
| 42392 | */ |
| 42393 | cpos = clen_this; |
| 42394 | } else { |
| 42395 | cpos = duk_to_int_clamped(thr, 1, 0, clen_this); |
| 42396 | } |
| 42397 | |
| 42398 | cpos = duk__str_search_shared(thr, h_this, h_search, cpos, is_lastindexof /*backwards*/); |
| 42399 | duk_push_int(thr, cpos); |
| 42400 | return 1; |
| 42401 | } |
| 42402 | |
| 42403 | /* |
| 42404 | * replace() |
| 42405 | */ |
| 42406 | |
| 42407 | /* XXX: the current implementation works but is quite clunky; it compiles |
| 42408 | * to almost 1,4kB of x86 code so it needs to be simplified (better approach, |
| 42409 | * shared helpers, etc). Some ideas for refactoring: |
| 42410 | * |
| 42411 | * - a primitive to convert a string into a regexp matcher (reduces matching |
| 42412 | * code at the cost of making matching much slower) |
| 42413 | * - use replace() as a basic helper for match() and split(), which are both |
| 42414 | * much simpler |
| 42415 | * - API call to get_prop and to_boolean |
| 42416 | */ |
| 42417 | |
| 42418 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) { |
| 42419 | duk_hstring *h_input; |
| 42420 | duk_hstring *h_match; |
| 42421 | duk_hstring *h_search; |
| 42422 | duk_hobject *h_re; |
| 42423 | duk_bufwriter_ctx bw_alloc; |
| 42424 | duk_bufwriter_ctx *bw; |
| 42425 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42426 | duk_bool_t is_regexp; |
| 42427 | duk_bool_t is_global; |
| 42428 | #endif |
| 42429 | duk_bool_t is_repl_func; |
| 42430 | duk_uint32_t match_start_coff, match_start_boff; |
| 42431 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42432 | duk_int_t match_caps; |
| 42433 | #endif |
| 42434 | duk_uint32_t prev_match_end_boff; |
| 42435 | const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */ |
| 42436 | duk_size_t tmp_sz; |
| 42437 | |
| 42438 | DUK_ASSERT_TOP(thr, 2); |
| 42439 | h_input = duk_push_this_coercible_to_string(thr); |
| 42440 | DUK_ASSERT(h_input != NULL); |
| 42441 | |
| 42442 | bw = &bw_alloc; |
| 42443 | DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */ |
| 42444 | |
| 42445 | DUK_ASSERT_TOP(thr, 4); |
| 42446 | |
| 42447 | /* stack[0] = search value |
| 42448 | * stack[1] = replace value |
| 42449 | * stack[2] = input string |
| 42450 | * stack[3] = result buffer |
| 42451 | */ |
| 42452 | |
| 42453 | h_re = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP); |
| 42454 | if (h_re) { |
| 42455 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42456 | is_regexp = 1; |
| 42457 | is_global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL); |
| 42458 | |
| 42459 | if (is_global) { |
| 42460 | /* start match from beginning */ |
| 42461 | duk_push_int(thr, 0); |
| 42462 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 42463 | } |
| 42464 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 42465 | DUK_DCERROR_UNSUPPORTED(thr); |
| 42466 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 42467 | } else { |
| 42468 | duk_to_string(thr, 0); /* rejects symbols */ |
| 42469 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42470 | is_regexp = 0; |
| 42471 | is_global = 0; |
| 42472 | #endif |
| 42473 | } |
| 42474 | |
| 42475 | if (duk_is_function(thr, 1)) { |
| 42476 | is_repl_func = 1; |
| 42477 | r_start = NULL; |
| 42478 | r_end = NULL; |
| 42479 | } else { |
| 42480 | duk_hstring *h_repl; |
| 42481 | |
| 42482 | is_repl_func = 0; |
| 42483 | h_repl = duk_to_hstring(thr, 1); /* reject symbols */ |
| 42484 | DUK_ASSERT(h_repl != NULL); |
| 42485 | r_start = DUK_HSTRING_GET_DATA(h_repl); |
| 42486 | r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl); |
| 42487 | } |
| 42488 | |
| 42489 | prev_match_end_boff = 0; |
| 42490 | |
| 42491 | for (;;) { |
| 42492 | /* |
| 42493 | * If matching with a regexp: |
| 42494 | * - non-global RegExp: lastIndex not touched on a match, zeroed |
| 42495 | * on a non-match |
| 42496 | * - global RegExp: on match, lastIndex will be updated by regexp |
| 42497 | * executor to point to next char after the matching part (so that |
| 42498 | * characters in the matching part are not matched again) |
| 42499 | * |
| 42500 | * If matching with a string: |
| 42501 | * - always non-global match, find first occurrence |
| 42502 | * |
| 42503 | * We need: |
| 42504 | * - The character offset of start-of-match for the replacer function |
| 42505 | * - The byte offsets for start-of-match and end-of-match to implement |
| 42506 | * the replacement values $&, $`, and $', and to copy non-matching |
| 42507 | * input string portions (including header and trailer) verbatim. |
| 42508 | * |
| 42509 | * NOTE: the E5.1 specification is a bit vague how the RegExp should |
| 42510 | * behave in the replacement process; e.g. is matching done first for |
| 42511 | * all matches (in the global RegExp case) before any replacer calls |
| 42512 | * are made? See: test-bi-string-proto-replace.js for discussion. |
| 42513 | */ |
| 42514 | |
| 42515 | DUK_ASSERT_TOP(thr, 4); |
| 42516 | |
| 42517 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42518 | if (is_regexp) { |
| 42519 | duk_dup_0(thr); |
| 42520 | duk_dup_2(thr); |
| 42521 | duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */ |
| 42522 | if (!duk_is_object(thr, -1)) { |
| 42523 | duk_pop(thr); |
| 42524 | break; |
| 42525 | } |
| 42526 | |
| 42527 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX); |
| 42528 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 42529 | match_start_coff = duk_get_uint(thr, -1); |
| 42530 | duk_pop(thr); |
| 42531 | |
| 42532 | duk_get_prop_index(thr, -1, 0); |
| 42533 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 42534 | h_match = duk_known_hstring(thr, -1); |
| 42535 | duk_pop(thr); /* h_match is borrowed, remains reachable through match_obj */ |
| 42536 | |
| 42537 | if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) { |
| 42538 | /* This should be equivalent to match() algorithm step 8.f.iii.2: |
| 42539 | * detect an empty match and allow it, but don't allow it twice. |
| 42540 | */ |
| 42541 | duk_uint32_t last_index; |
| 42542 | |
| 42543 | duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 42544 | last_index = (duk_uint32_t) duk_get_uint(thr, -1); |
| 42545 | DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld" , |
| 42546 | (long) last_index, (long) (last_index + 1))); |
| 42547 | duk_pop(thr); |
| 42548 | duk_push_uint(thr, (duk_uint_t) (last_index + 1)); |
| 42549 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 42550 | } |
| 42551 | |
| 42552 | DUK_ASSERT(duk_get_length(thr, -1) <= DUK_INT_MAX); /* string limits */ |
| 42553 | match_caps = (duk_int_t) duk_get_length(thr, -1); |
| 42554 | } else { |
| 42555 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 42556 | { /* unconditionally */ |
| 42557 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 42558 | const duk_uint8_t *p_start, *p_end, *p; /* input string scan */ |
| 42559 | const duk_uint8_t *q_start; /* match string */ |
| 42560 | duk_size_t p_blen; |
| 42561 | duk_size_t q_blen; |
| 42562 | |
| 42563 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42564 | DUK_ASSERT(!is_global); /* single match always */ |
| 42565 | #endif |
| 42566 | |
| 42567 | p_start = DUK_HSTRING_GET_DATA(h_input); |
| 42568 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); |
| 42569 | p_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_input); |
| 42570 | p = p_start; |
| 42571 | |
| 42572 | h_search = duk_known_hstring(thr, 0); |
| 42573 | q_start = DUK_HSTRING_GET_DATA(h_search); |
| 42574 | q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search); |
| 42575 | |
| 42576 | if (q_blen > p_blen) { |
| 42577 | break; /* no match */ |
| 42578 | } |
| 42579 | |
| 42580 | p_end -= q_blen; /* ensure full memcmp() fits in while */ |
| 42581 | DUK_ASSERT(p_end >= p); |
| 42582 | |
| 42583 | match_start_coff = 0; |
| 42584 | |
| 42585 | while (p <= p_end) { |
| 42586 | DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); |
| 42587 | if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { |
| 42588 | duk_dup_0(thr); |
| 42589 | h_match = duk_known_hstring(thr, -1); |
| 42590 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42591 | match_caps = 0; |
| 42592 | #endif |
| 42593 | goto found; |
| 42594 | } |
| 42595 | |
| 42596 | /* track utf-8 non-continuation bytes */ |
| 42597 | if ((p[0] & 0xc0) != 0x80) { |
| 42598 | match_start_coff++; |
| 42599 | } |
| 42600 | p++; |
| 42601 | } |
| 42602 | |
| 42603 | /* not found */ |
| 42604 | break; |
| 42605 | } |
| 42606 | found: |
| 42607 | |
| 42608 | /* stack[0] = search value |
| 42609 | * stack[1] = replace value |
| 42610 | * stack[2] = input string |
| 42611 | * stack[3] = result buffer |
| 42612 | * stack[4] = regexp match OR match string |
| 42613 | */ |
| 42614 | |
| 42615 | match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff); |
| 42616 | |
| 42617 | tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff); |
| 42618 | DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz); |
| 42619 | |
| 42620 | prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match); |
| 42621 | |
| 42622 | if (is_repl_func) { |
| 42623 | duk_idx_t idx_args; |
| 42624 | duk_hstring *h_repl; |
| 42625 | |
| 42626 | /* regexp res_obj is at index 4 */ |
| 42627 | |
| 42628 | duk_dup_1(thr); |
| 42629 | idx_args = duk_get_top(thr); |
| 42630 | |
| 42631 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42632 | if (is_regexp) { |
| 42633 | duk_int_t idx; |
| 42634 | duk_require_stack(thr, match_caps + 2); |
| 42635 | for (idx = 0; idx < match_caps; idx++) { |
| 42636 | /* match followed by capture(s) */ |
| 42637 | duk_get_prop_index(thr, 4, (duk_uarridx_t) idx); |
| 42638 | } |
| 42639 | } else { |
| 42640 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 42641 | { /* unconditionally */ |
| 42642 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 42643 | /* match == search string, by definition */ |
| 42644 | duk_dup_0(thr); |
| 42645 | } |
| 42646 | duk_push_uint(thr, (duk_uint_t) match_start_coff); |
| 42647 | duk_dup_2(thr); |
| 42648 | |
| 42649 | /* [ ... replacer match [captures] match_char_offset input ] */ |
| 42650 | |
| 42651 | duk_call(thr, duk_get_top(thr) - idx_args); |
| 42652 | h_repl = duk_to_hstring_m1(thr); /* -> [ ... repl_value ] */ |
| 42653 | DUK_ASSERT(h_repl != NULL); |
| 42654 | |
| 42655 | DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl); |
| 42656 | |
| 42657 | duk_pop(thr); /* repl_value */ |
| 42658 | } else { |
| 42659 | r = r_start; |
| 42660 | |
| 42661 | while (r < r_end) { |
| 42662 | duk_int_t ch1; |
| 42663 | duk_int_t ch2; |
| 42664 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42665 | duk_int_t ch3; |
| 42666 | #endif |
| 42667 | duk_size_t left; |
| 42668 | |
| 42669 | ch1 = *r++; |
| 42670 | if (ch1 != DUK_ASC_DOLLAR) { |
| 42671 | goto repl_write; |
| 42672 | } |
| 42673 | DUK_ASSERT(r <= r_end); |
| 42674 | left = (duk_size_t) (r_end - r); |
| 42675 | |
| 42676 | if (left <= 0) { |
| 42677 | goto repl_write; |
| 42678 | } |
| 42679 | |
| 42680 | ch2 = r[0]; |
| 42681 | switch (ch2) { |
| 42682 | case DUK_ASC_DOLLAR: { |
| 42683 | ch1 = (1 << 8) + DUK_ASC_DOLLAR; |
| 42684 | goto repl_write; |
| 42685 | } |
| 42686 | case DUK_ASC_AMP: { |
| 42687 | DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match); |
| 42688 | r++; |
| 42689 | continue; |
| 42690 | } |
| 42691 | case DUK_ASC_GRAVE: { |
| 42692 | tmp_sz = (duk_size_t) match_start_boff; |
| 42693 | DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz); |
| 42694 | r++; |
| 42695 | continue; |
| 42696 | } |
| 42697 | case DUK_ASC_SINGLEQUOTE: { |
| 42698 | duk_uint32_t match_end_boff; |
| 42699 | |
| 42700 | /* Use match charlen instead of bytelen, just in case the input and |
| 42701 | * match codepoint encodings would have different lengths. |
| 42702 | */ |
| 42703 | /* XXX: charlen computed here, and also in char2byte helper. */ |
| 42704 | match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, |
| 42705 | h_input, |
| 42706 | match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match)); |
| 42707 | |
| 42708 | tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff); |
| 42709 | DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz); |
| 42710 | r++; |
| 42711 | continue; |
| 42712 | } |
| 42713 | default: { |
| 42714 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42715 | duk_int_t capnum, captmp, capadv; |
| 42716 | /* XXX: optional check, match_caps is zero if no regexp, |
| 42717 | * so dollar will be interpreted literally anyway. |
| 42718 | */ |
| 42719 | |
| 42720 | if (!is_regexp) { |
| 42721 | goto repl_write; |
| 42722 | } |
| 42723 | |
| 42724 | if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) { |
| 42725 | goto repl_write; |
| 42726 | } |
| 42727 | capnum = ch2 - DUK_ASC_0; |
| 42728 | capadv = 1; |
| 42729 | |
| 42730 | if (left >= 2) { |
| 42731 | ch3 = r[1]; |
| 42732 | if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) { |
| 42733 | captmp = capnum * 10 + (ch3 - DUK_ASC_0); |
| 42734 | if (captmp < match_caps) { |
| 42735 | capnum = captmp; |
| 42736 | capadv = 2; |
| 42737 | } |
| 42738 | } |
| 42739 | } |
| 42740 | |
| 42741 | if (capnum > 0 && capnum < match_caps) { |
| 42742 | DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */ |
| 42743 | |
| 42744 | /* regexp res_obj is at offset 4 */ |
| 42745 | duk_get_prop_index(thr, 4, (duk_uarridx_t) capnum); |
| 42746 | if (duk_is_string(thr, -1)) { |
| 42747 | duk_hstring *h_tmp_str; |
| 42748 | |
| 42749 | h_tmp_str = duk_known_hstring(thr, -1); |
| 42750 | |
| 42751 | DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str); |
| 42752 | } else { |
| 42753 | /* undefined -> skip (replaced with empty) */ |
| 42754 | } |
| 42755 | duk_pop(thr); |
| 42756 | r += capadv; |
| 42757 | continue; |
| 42758 | } else { |
| 42759 | goto repl_write; |
| 42760 | } |
| 42761 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 42762 | goto repl_write; /* unconditionally */ |
| 42763 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 42764 | } /* default case */ |
| 42765 | } /* switch (ch2) */ |
| 42766 | |
| 42767 | repl_write: |
| 42768 | /* ch1 = (r_increment << 8) + byte */ |
| 42769 | |
| 42770 | DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff)); |
| 42771 | r += ch1 >> 8; |
| 42772 | } /* while repl */ |
| 42773 | } /* if (is_repl_func) */ |
| 42774 | |
| 42775 | duk_pop(thr); /* pop regexp res_obj or match string */ |
| 42776 | |
| 42777 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42778 | if (!is_global) { |
| 42779 | #else |
| 42780 | { /* unconditionally; is_global==0 */ |
| 42781 | #endif |
| 42782 | break; |
| 42783 | } |
| 42784 | } |
| 42785 | |
| 42786 | /* trailer */ |
| 42787 | tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff); |
| 42788 | DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz); |
| 42789 | |
| 42790 | DUK_ASSERT_TOP(thr, 4); |
| 42791 | DUK_BW_COMPACT(thr, bw); |
| 42792 | (void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */ |
| 42793 | return 1; |
| 42794 | } |
| 42795 | |
| 42796 | /* |
| 42797 | * split() |
| 42798 | */ |
| 42799 | |
| 42800 | /* XXX: very messy now, but works; clean up, remove unused variables (nomimally |
| 42801 | * used so compiler doesn't complain). |
| 42802 | */ |
| 42803 | |
| 42804 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) { |
| 42805 | duk_hstring *h_input; |
| 42806 | duk_hstring *h_sep; |
| 42807 | duk_uint32_t limit; |
| 42808 | duk_uint32_t arr_idx; |
| 42809 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42810 | duk_bool_t is_regexp; |
| 42811 | #endif |
| 42812 | duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */ |
| 42813 | duk_uint32_t prev_match_end_coff, prev_match_end_boff; |
| 42814 | duk_uint32_t match_start_boff, match_start_coff; |
| 42815 | duk_uint32_t match_end_boff, match_end_coff; |
| 42816 | |
| 42817 | h_input = duk_push_this_coercible_to_string(thr); |
| 42818 | DUK_ASSERT(h_input != NULL); |
| 42819 | |
| 42820 | duk_push_array(thr); |
| 42821 | |
| 42822 | if (duk_is_undefined(thr, 1)) { |
| 42823 | limit = 0xffffffffUL; |
| 42824 | } else { |
| 42825 | limit = duk_to_uint32(thr, 1); |
| 42826 | } |
| 42827 | |
| 42828 | if (limit == 0) { |
| 42829 | return 1; |
| 42830 | } |
| 42831 | |
| 42832 | /* If the separator is a RegExp, make a "clone" of it. The specification |
| 42833 | * algorithm calls [[Match]] directly for specific indices; we emulate this |
| 42834 | * by tweaking lastIndex and using a "force global" variant of duk_regexp_match() |
| 42835 | * which will use global-style matching even when the RegExp itself is non-global. |
| 42836 | */ |
| 42837 | |
| 42838 | if (duk_is_undefined(thr, 0)) { |
| 42839 | /* The spec algorithm first does "R = ToString(separator)" before checking |
| 42840 | * whether separator is undefined. Since this is side effect free, we can |
| 42841 | * skip the ToString() here. |
| 42842 | */ |
| 42843 | duk_dup_2(thr); |
| 42844 | duk_put_prop_index(thr, 3, 0); |
| 42845 | return 1; |
| 42846 | } else if (duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) { |
| 42847 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42848 | duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR); |
| 42849 | duk_dup_0(thr); |
| 42850 | duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */ |
| 42851 | duk_replace(thr, 0); |
| 42852 | /* lastIndex is initialized to zero by new RegExp() */ |
| 42853 | is_regexp = 1; |
| 42854 | #else |
| 42855 | DUK_DCERROR_UNSUPPORTED(thr); |
| 42856 | #endif |
| 42857 | } else { |
| 42858 | duk_to_string(thr, 0); |
| 42859 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42860 | is_regexp = 0; |
| 42861 | #endif |
| 42862 | } |
| 42863 | |
| 42864 | /* stack[0] = separator (string or regexp) |
| 42865 | * stack[1] = limit |
| 42866 | * stack[2] = input string |
| 42867 | * stack[3] = result array |
| 42868 | */ |
| 42869 | |
| 42870 | prev_match_end_boff = 0; |
| 42871 | prev_match_end_coff = 0; |
| 42872 | arr_idx = 0; |
| 42873 | matched = 0; |
| 42874 | |
| 42875 | for (;;) { |
| 42876 | /* |
| 42877 | * The specification uses RegExp [[Match]] to attempt match at specific |
| 42878 | * offsets. We don't have such a primitive, so we use an actual RegExp |
| 42879 | * and tweak lastIndex. Since the RegExp may be non-global, we use a |
| 42880 | * special variant which forces global-like behavior for matching. |
| 42881 | */ |
| 42882 | |
| 42883 | DUK_ASSERT_TOP(thr, 4); |
| 42884 | |
| 42885 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 42886 | if (is_regexp) { |
| 42887 | duk_dup_0(thr); |
| 42888 | duk_dup_2(thr); |
| 42889 | duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */ |
| 42890 | if (!duk_is_object(thr, -1)) { |
| 42891 | duk_pop(thr); |
| 42892 | break; |
| 42893 | } |
| 42894 | matched = 1; |
| 42895 | |
| 42896 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX); |
| 42897 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 42898 | match_start_coff = duk_get_uint(thr, -1); |
| 42899 | match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff); |
| 42900 | duk_pop(thr); |
| 42901 | |
| 42902 | if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) { |
| 42903 | /* don't allow an empty match at the end of the string */ |
| 42904 | duk_pop(thr); |
| 42905 | break; |
| 42906 | } |
| 42907 | |
| 42908 | duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 42909 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 42910 | match_end_coff = duk_get_uint(thr, -1); |
| 42911 | match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff); |
| 42912 | duk_pop(thr); |
| 42913 | |
| 42914 | /* empty match -> bump and continue */ |
| 42915 | if (prev_match_end_boff == match_end_boff) { |
| 42916 | duk_push_uint(thr, (duk_uint_t) (match_end_coff + 1)); |
| 42917 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 42918 | duk_pop(thr); |
| 42919 | continue; |
| 42920 | } |
| 42921 | } else { |
| 42922 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 42923 | { /* unconditionally */ |
| 42924 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 42925 | const duk_uint8_t *p_start, *p_end, *p; /* input string scan */ |
| 42926 | const duk_uint8_t *q_start; /* match string */ |
| 42927 | duk_size_t q_blen, q_clen; |
| 42928 | |
| 42929 | p_start = DUK_HSTRING_GET_DATA(h_input); |
| 42930 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input); |
| 42931 | p = p_start + prev_match_end_boff; |
| 42932 | |
| 42933 | h_sep = duk_known_hstring(thr, 0); /* symbol already rejected above */ |
| 42934 | q_start = DUK_HSTRING_GET_DATA(h_sep); |
| 42935 | q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep); |
| 42936 | q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep); |
| 42937 | |
| 42938 | p_end -= q_blen; /* ensure full memcmp() fits in while */ |
| 42939 | |
| 42940 | match_start_coff = prev_match_end_coff; |
| 42941 | |
| 42942 | if (q_blen == 0) { |
| 42943 | /* Handle empty separator case: it will always match, and always |
| 42944 | * triggers the check in step 13.c.iii initially. Note that we |
| 42945 | * must skip to either end of string or start of first codepoint, |
| 42946 | * skipping over any continuation bytes! |
| 42947 | * |
| 42948 | * Don't allow an empty string to match at the end of the input. |
| 42949 | */ |
| 42950 | |
| 42951 | matched = 1; /* empty separator can always match */ |
| 42952 | |
| 42953 | match_start_coff++; |
| 42954 | p++; |
| 42955 | while (p < p_end) { |
| 42956 | if ((p[0] & 0xc0) != 0x80) { |
| 42957 | goto found; |
| 42958 | } |
| 42959 | p++; |
| 42960 | } |
| 42961 | goto not_found; |
| 42962 | } |
| 42963 | |
| 42964 | DUK_ASSERT(q_blen > 0 && q_clen > 0); |
| 42965 | while (p <= p_end) { |
| 42966 | DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input)); |
| 42967 | DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */ |
| 42968 | if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) { |
| 42969 | /* never an empty match, so step 13.c.iii can't be triggered */ |
| 42970 | goto found; |
| 42971 | } |
| 42972 | |
| 42973 | /* track utf-8 non-continuation bytes */ |
| 42974 | if ((p[0] & 0xc0) != 0x80) { |
| 42975 | match_start_coff++; |
| 42976 | } |
| 42977 | p++; |
| 42978 | } |
| 42979 | |
| 42980 | not_found: |
| 42981 | /* not found */ |
| 42982 | break; |
| 42983 | |
| 42984 | found: |
| 42985 | matched = 1; |
| 42986 | match_start_boff = (duk_uint32_t) (p - p_start); |
| 42987 | match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */ |
| 42988 | match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */ |
| 42989 | |
| 42990 | /* empty match (may happen with empty separator) -> bump and continue */ |
| 42991 | if (prev_match_end_boff == match_end_boff) { |
| 42992 | prev_match_end_boff++; |
| 42993 | prev_match_end_coff++; |
| 42994 | continue; |
| 42995 | } |
| 42996 | } /* if (is_regexp) */ |
| 42997 | |
| 42998 | /* stack[0] = separator (string or regexp) |
| 42999 | * stack[1] = limit |
| 43000 | * stack[2] = input string |
| 43001 | * stack[3] = result array |
| 43002 | * stack[4] = regexp res_obj (if is_regexp) |
| 43003 | */ |
| 43004 | |
| 43005 | DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld" , |
| 43006 | (long) match_start_boff, (long) match_start_coff, |
| 43007 | (long) match_end_boff, (long) match_end_coff, |
| 43008 | (long) prev_match_end_boff, (long) prev_match_end_coff)); |
| 43009 | |
| 43010 | duk_push_lstring(thr, |
| 43011 | (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff), |
| 43012 | (duk_size_t) (match_start_boff - prev_match_end_boff)); |
| 43013 | duk_put_prop_index(thr, 3, arr_idx); |
| 43014 | arr_idx++; |
| 43015 | if (arr_idx >= limit) { |
| 43016 | goto hit_limit; |
| 43017 | } |
| 43018 | |
| 43019 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 43020 | if (is_regexp) { |
| 43021 | duk_size_t i, len; |
| 43022 | |
| 43023 | len = duk_get_length(thr, 4); |
| 43024 | for (i = 1; i < len; i++) { |
| 43025 | DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */ |
| 43026 | duk_get_prop_index(thr, 4, (duk_uarridx_t) i); |
| 43027 | duk_put_prop_index(thr, 3, arr_idx); |
| 43028 | arr_idx++; |
| 43029 | if (arr_idx >= limit) { |
| 43030 | goto hit_limit; |
| 43031 | } |
| 43032 | } |
| 43033 | |
| 43034 | duk_pop(thr); |
| 43035 | /* lastIndex already set up for next match */ |
| 43036 | } else { |
| 43037 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 43038 | { /* unconditionally */ |
| 43039 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 43040 | /* no action */ |
| 43041 | } |
| 43042 | |
| 43043 | prev_match_end_boff = match_end_boff; |
| 43044 | prev_match_end_coff = match_end_coff; |
| 43045 | continue; |
| 43046 | } /* for */ |
| 43047 | |
| 43048 | /* Combined step 11 (empty string special case) and 14-15. */ |
| 43049 | |
| 43050 | DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld" , |
| 43051 | (long) prev_match_end_boff, (long) prev_match_end_coff)); |
| 43052 | |
| 43053 | if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) { |
| 43054 | /* Add trailer if: |
| 43055 | * a) non-empty input |
| 43056 | * b) empty input and no (zero size) match found (step 11) |
| 43057 | */ |
| 43058 | |
| 43059 | duk_push_lstring(thr, |
| 43060 | (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, |
| 43061 | (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff)); |
| 43062 | duk_put_prop_index(thr, 3, arr_idx); |
| 43063 | /* No arr_idx update or limit check */ |
| 43064 | } |
| 43065 | |
| 43066 | return 1; |
| 43067 | |
| 43068 | hit_limit: |
| 43069 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 43070 | if (is_regexp) { |
| 43071 | duk_pop(thr); |
| 43072 | } |
| 43073 | #endif |
| 43074 | |
| 43075 | return 1; |
| 43076 | } |
| 43077 | |
| 43078 | /* |
| 43079 | * Various |
| 43080 | */ |
| 43081 | |
| 43082 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 43083 | DUK_LOCAL void duk__to_regexp_helper(duk_hthread *thr, duk_idx_t idx, duk_bool_t force_new) { |
| 43084 | duk_hobject *h; |
| 43085 | |
| 43086 | /* Shared helper for match() steps 3-4, search() steps 3-4. */ |
| 43087 | |
| 43088 | DUK_ASSERT(idx >= 0); |
| 43089 | |
| 43090 | if (force_new) { |
| 43091 | goto do_new; |
| 43092 | } |
| 43093 | |
| 43094 | h = duk_get_hobject_with_class(thr, idx, DUK_HOBJECT_CLASS_REGEXP); |
| 43095 | if (!h) { |
| 43096 | goto do_new; |
| 43097 | } |
| 43098 | return; |
| 43099 | |
| 43100 | do_new: |
| 43101 | duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR); |
| 43102 | duk_dup(thr, idx); |
| 43103 | duk_new(thr, 1); /* [ ... RegExp val ] -> [ ... res ] */ |
| 43104 | duk_replace(thr, idx); |
| 43105 | } |
| 43106 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 43107 | |
| 43108 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 43109 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_hthread *thr) { |
| 43110 | /* Easiest way to implement the search required by the specification |
| 43111 | * is to do a RegExp test() with lastIndex forced to zero. To avoid |
| 43112 | * side effects on the argument, "clone" the RegExp if a RegExp was |
| 43113 | * given as input. |
| 43114 | * |
| 43115 | * The global flag of the RegExp should be ignored; setting lastIndex |
| 43116 | * to zero (which happens when "cloning" the RegExp) should have an |
| 43117 | * equivalent effect. |
| 43118 | */ |
| 43119 | |
| 43120 | DUK_ASSERT_TOP(thr, 1); |
| 43121 | (void) duk_push_this_coercible_to_string(thr); /* at index 1 */ |
| 43122 | duk__to_regexp_helper(thr, 0 /*index*/, 1 /*force_new*/); |
| 43123 | |
| 43124 | /* stack[0] = regexp |
| 43125 | * stack[1] = string |
| 43126 | */ |
| 43127 | |
| 43128 | /* Avoid using RegExp.prototype methods, as they're writable and |
| 43129 | * configurable and may have been changed. |
| 43130 | */ |
| 43131 | |
| 43132 | duk_dup_0(thr); |
| 43133 | duk_dup_1(thr); /* [ ... re_obj input ] */ |
| 43134 | duk_regexp_match(thr); /* -> [ ... res_obj ] */ |
| 43135 | |
| 43136 | if (!duk_is_object(thr, -1)) { |
| 43137 | duk_push_int(thr, -1); |
| 43138 | return 1; |
| 43139 | } |
| 43140 | |
| 43141 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX); |
| 43142 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 43143 | return 1; |
| 43144 | } |
| 43145 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 43146 | |
| 43147 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 43148 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_hthread *thr) { |
| 43149 | duk_bool_t global; |
| 43150 | duk_int_t prev_last_index; |
| 43151 | duk_int_t this_index; |
| 43152 | duk_int_t arr_idx; |
| 43153 | |
| 43154 | DUK_ASSERT_TOP(thr, 1); |
| 43155 | (void) duk_push_this_coercible_to_string(thr); |
| 43156 | duk__to_regexp_helper(thr, 0 /*index*/, 0 /*force_new*/); |
| 43157 | global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL); |
| 43158 | DUK_ASSERT_TOP(thr, 2); |
| 43159 | |
| 43160 | /* stack[0] = regexp |
| 43161 | * stack[1] = string |
| 43162 | */ |
| 43163 | |
| 43164 | if (!global) { |
| 43165 | duk_regexp_match(thr); /* -> [ res_obj ] */ |
| 43166 | return 1; /* return 'res_obj' */ |
| 43167 | } |
| 43168 | |
| 43169 | /* Global case is more complex. */ |
| 43170 | |
| 43171 | /* [ regexp string ] */ |
| 43172 | |
| 43173 | duk_push_int(thr, 0); |
| 43174 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 43175 | duk_push_array(thr); |
| 43176 | |
| 43177 | /* [ regexp string res_arr ] */ |
| 43178 | |
| 43179 | prev_last_index = 0; |
| 43180 | arr_idx = 0; |
| 43181 | |
| 43182 | for (;;) { |
| 43183 | DUK_ASSERT_TOP(thr, 3); |
| 43184 | |
| 43185 | duk_dup_0(thr); |
| 43186 | duk_dup_1(thr); |
| 43187 | duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */ |
| 43188 | |
| 43189 | if (!duk_is_object(thr, -1)) { |
| 43190 | duk_pop(thr); |
| 43191 | break; |
| 43192 | } |
| 43193 | |
| 43194 | duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 43195 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 43196 | this_index = duk_get_int(thr, -1); |
| 43197 | duk_pop(thr); |
| 43198 | |
| 43199 | if (this_index == prev_last_index) { |
| 43200 | this_index++; |
| 43201 | duk_push_int(thr, this_index); |
| 43202 | duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX); |
| 43203 | } |
| 43204 | prev_last_index = this_index; |
| 43205 | |
| 43206 | duk_get_prop_index(thr, -1, 0); /* match string */ |
| 43207 | duk_put_prop_index(thr, 2, (duk_uarridx_t) arr_idx); |
| 43208 | arr_idx++; |
| 43209 | duk_pop(thr); /* res_obj */ |
| 43210 | } |
| 43211 | |
| 43212 | if (arr_idx == 0) { |
| 43213 | duk_push_null(thr); |
| 43214 | } |
| 43215 | |
| 43216 | return 1; /* return 'res_arr' or 'null' */ |
| 43217 | } |
| 43218 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 43219 | |
| 43220 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_hthread *thr) { |
| 43221 | /* duk_concat() coerces arguments with ToString() in correct order */ |
| 43222 | (void) duk_push_this_coercible_to_string(thr); |
| 43223 | duk_insert(thr, 0); /* this is relatively expensive */ |
| 43224 | duk_concat(thr, duk_get_top(thr)); |
| 43225 | return 1; |
| 43226 | } |
| 43227 | |
| 43228 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_hthread *thr) { |
| 43229 | DUK_ASSERT_TOP(thr, 0); |
| 43230 | (void) duk_push_this_coercible_to_string(thr); |
| 43231 | duk_trim(thr, 0); |
| 43232 | DUK_ASSERT_TOP(thr, 1); |
| 43233 | return 1; |
| 43234 | } |
| 43235 | |
| 43236 | #if defined(DUK_USE_ES6) |
| 43237 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) { |
| 43238 | duk_hstring *h_input; |
| 43239 | duk_size_t input_blen; |
| 43240 | duk_size_t result_len; |
| 43241 | duk_int_t count_signed; |
| 43242 | duk_uint_t count; |
| 43243 | const duk_uint8_t *src; |
| 43244 | duk_uint8_t *buf; |
| 43245 | duk_uint8_t *p; |
| 43246 | duk_double_t d; |
| 43247 | #if !defined(DUK_USE_PREFER_SIZE) |
| 43248 | duk_size_t copy_size; |
| 43249 | duk_uint8_t *p_end; |
| 43250 | #endif |
| 43251 | |
| 43252 | DUK_ASSERT_TOP(thr, 1); |
| 43253 | h_input = duk_push_this_coercible_to_string(thr); |
| 43254 | DUK_ASSERT(h_input != NULL); |
| 43255 | input_blen = DUK_HSTRING_GET_BYTELEN(h_input); |
| 43256 | |
| 43257 | /* Count is ToNumber() coerced; +Infinity must be always rejected |
| 43258 | * (even if input string is zero length), as well as negative values |
| 43259 | * and -Infinity. -Infinity doesn't require an explicit check |
| 43260 | * because duk_get_int() clamps it to DUK_INT_MIN which gets rejected |
| 43261 | * as a negative value (regardless of input string length). |
| 43262 | */ |
| 43263 | d = duk_to_number(thr, 0); |
| 43264 | if (duk_double_is_posinf(d)) { |
| 43265 | goto fail_range; |
| 43266 | } |
| 43267 | count_signed = duk_get_int(thr, 0); |
| 43268 | if (count_signed < 0) { |
| 43269 | goto fail_range; |
| 43270 | } |
| 43271 | count = (duk_uint_t) count_signed; |
| 43272 | |
| 43273 | /* Overflow check for result length. */ |
| 43274 | result_len = count * input_blen; |
| 43275 | if (count != 0 && result_len / count != input_blen) { |
| 43276 | goto fail_range; |
| 43277 | } |
| 43278 | |
| 43279 | /* Temporary fixed buffer, later converted to string. */ |
| 43280 | buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len); |
| 43281 | DUK_ASSERT(buf != NULL); |
| 43282 | src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); |
| 43283 | DUK_ASSERT(src != NULL); |
| 43284 | |
| 43285 | #if defined(DUK_USE_PREFER_SIZE) |
| 43286 | p = buf; |
| 43287 | while (count-- > 0) { |
| 43288 | duk_memcpy((void *) p, (const void *) src, input_blen); /* copy size may be zero, but pointers are valid */ |
| 43289 | p += input_blen; |
| 43290 | } |
| 43291 | #else /* DUK_USE_PREFER_SIZE */ |
| 43292 | /* Take advantage of already copied pieces to speed up the process |
| 43293 | * especially for small repeated strings. |
| 43294 | */ |
| 43295 | p = buf; |
| 43296 | p_end = p + result_len; |
| 43297 | copy_size = input_blen; |
| 43298 | for (;;) { |
| 43299 | duk_size_t remain = (duk_size_t) (p_end - p); |
| 43300 | DUK_DDD(DUK_DDDPRINT("remain=%ld, copy_size=%ld, input_blen=%ld, result_len=%ld" , |
| 43301 | (long) remain, (long) copy_size, (long) input_blen, |
| 43302 | (long) result_len)); |
| 43303 | if (remain <= copy_size) { |
| 43304 | /* If result_len is zero, this case is taken and does |
| 43305 | * a zero size copy (with valid pointers). |
| 43306 | */ |
| 43307 | duk_memcpy((void *) p, (const void *) src, remain); |
| 43308 | break; |
| 43309 | } else { |
| 43310 | duk_memcpy((void *) p, (const void *) src, copy_size); |
| 43311 | p += copy_size; |
| 43312 | } |
| 43313 | |
| 43314 | src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */ |
| 43315 | copy_size = (duk_size_t) (p - buf); |
| 43316 | } |
| 43317 | #endif /* DUK_USE_PREFER_SIZE */ |
| 43318 | |
| 43319 | /* XXX: It would be useful to be able to create a duk_hstring with |
| 43320 | * a certain byte size whose data area wasn't initialized and which |
| 43321 | * wasn't in the string table yet. This would allow a string to be |
| 43322 | * constructed directly without a buffer temporary and when it was |
| 43323 | * finished, it could be injected into the string table. Currently |
| 43324 | * this isn't possible because duk_hstrings are only tracked by the |
| 43325 | * intern table (they are not in heap_allocated). |
| 43326 | */ |
| 43327 | |
| 43328 | duk_buffer_to_string(thr, -1); /* Safe if input is safe. */ |
| 43329 | return 1; |
| 43330 | |
| 43331 | fail_range: |
| 43332 | DUK_DCERROR_RANGE_INVALID_ARGS(thr); |
| 43333 | } |
| 43334 | #endif /* DUK_USE_ES6 */ |
| 43335 | |
| 43336 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr) { |
| 43337 | duk_hstring *h1; |
| 43338 | duk_hstring *h2; |
| 43339 | duk_size_t h1_len, h2_len, prefix_len; |
| 43340 | duk_small_int_t ret = 0; |
| 43341 | duk_small_int_t rc; |
| 43342 | |
| 43343 | /* The current implementation of localeCompare() is simply a codepoint |
| 43344 | * by codepoint comparison, implemented with a simple string compare |
| 43345 | * because UTF-8 should preserve codepoint ordering (assuming valid |
| 43346 | * shortest UTF-8 encoding). |
| 43347 | * |
| 43348 | * The specification requires that the return value must be related |
| 43349 | * to the sort order: e.g. negative means that 'this' comes before |
| 43350 | * 'that' in sort order. We assume an ascending sort order. |
| 43351 | */ |
| 43352 | |
| 43353 | /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */ |
| 43354 | |
| 43355 | h1 = duk_push_this_coercible_to_string(thr); |
| 43356 | DUK_ASSERT(h1 != NULL); |
| 43357 | |
| 43358 | h2 = duk_to_hstring(thr, 0); |
| 43359 | DUK_ASSERT(h2 != NULL); |
| 43360 | |
| 43361 | h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1); |
| 43362 | h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2); |
| 43363 | prefix_len = (h1_len <= h2_len ? h1_len : h2_len); |
| 43364 | |
| 43365 | rc = (duk_small_int_t) duk_memcmp((const void *) DUK_HSTRING_GET_DATA(h1), |
| 43366 | (const void *) DUK_HSTRING_GET_DATA(h2), |
| 43367 | (size_t) prefix_len); |
| 43368 | |
| 43369 | if (rc < 0) { |
| 43370 | ret = -1; |
| 43371 | goto done; |
| 43372 | } else if (rc > 0) { |
| 43373 | ret = 1; |
| 43374 | goto done; |
| 43375 | } |
| 43376 | |
| 43377 | /* prefix matches, lengths matter now */ |
| 43378 | if (h1_len > h2_len) { |
| 43379 | ret = 1; |
| 43380 | goto done; |
| 43381 | } else if (h1_len == h2_len) { |
| 43382 | DUK_ASSERT(ret == 0); |
| 43383 | goto done; |
| 43384 | } |
| 43385 | ret = -1; |
| 43386 | goto done; |
| 43387 | |
| 43388 | done: |
| 43389 | duk_push_int(thr, (duk_int_t) ret); |
| 43390 | return 1; |
| 43391 | } |
| 43392 | |
| 43393 | #if defined(DUK_USE_ES6) |
| 43394 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *thr) { |
| 43395 | duk_int_t magic; |
| 43396 | duk_hstring *h_target; |
| 43397 | duk_size_t blen_target; |
| 43398 | duk_hstring *h_search; |
| 43399 | duk_size_t blen_search; |
| 43400 | duk_int_t off; |
| 43401 | duk_bool_t result = 0; |
| 43402 | duk_size_t blen_left; |
| 43403 | |
| 43404 | /* Because string byte lengths are in [0,DUK_INT_MAX] it's safe to |
| 43405 | * subtract two string lengths without overflow. |
| 43406 | */ |
| 43407 | DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX); |
| 43408 | |
| 43409 | h_target = duk_push_this_coercible_to_string(thr); |
| 43410 | DUK_ASSERT(h_target != NULL); |
| 43411 | |
| 43412 | h_search = duk__str_tostring_notregexp(thr, 0); |
| 43413 | DUK_ASSERT(h_search != NULL); |
| 43414 | |
| 43415 | magic = duk_get_current_magic(thr); |
| 43416 | |
| 43417 | /* Careful to avoid pointer overflows in the matching logic. */ |
| 43418 | |
| 43419 | blen_target = DUK_HSTRING_GET_BYTELEN(h_target); |
| 43420 | blen_search = DUK_HSTRING_GET_BYTELEN(h_search); |
| 43421 | |
| 43422 | #if 0 |
| 43423 | /* If search string is longer than the target string, we can |
| 43424 | * never match. Could check explicitly, but should be handled |
| 43425 | * correctly below. |
| 43426 | */ |
| 43427 | if (blen_search > blen_target) { |
| 43428 | goto finish; |
| 43429 | } |
| 43430 | #endif |
| 43431 | |
| 43432 | off = 0; |
| 43433 | if (duk_is_undefined(thr, 1)) { |
| 43434 | if (magic) { |
| 43435 | off = (duk_int_t) blen_target - (duk_int_t) blen_search; |
| 43436 | } else { |
| 43437 | DUK_ASSERT(off == 0); |
| 43438 | } |
| 43439 | } else { |
| 43440 | duk_int_t len; |
| 43441 | duk_int_t pos; |
| 43442 | |
| 43443 | DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX); |
| 43444 | len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_target); |
| 43445 | pos = duk_to_int_clamped(thr, 1, 0, len); |
| 43446 | DUK_ASSERT(pos >= 0 && pos <= len); |
| 43447 | |
| 43448 | off = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_target, (duk_uint_fast32_t) pos); |
| 43449 | if (magic) { |
| 43450 | off -= (duk_int_t) blen_search; |
| 43451 | } |
| 43452 | } |
| 43453 | if (off < 0 || off > (duk_int_t) blen_target) { |
| 43454 | goto finish; |
| 43455 | } |
| 43456 | |
| 43457 | /* The main comparison can be done using a memcmp() rather than |
| 43458 | * doing codepoint comparisons: for CESU-8 strings there is a |
| 43459 | * canonical representation for every codepoint. But we do need |
| 43460 | * to deal with the char/byte offset translation to find the |
| 43461 | * comparison range. |
| 43462 | */ |
| 43463 | |
| 43464 | DUK_ASSERT(off >= 0); |
| 43465 | DUK_ASSERT((duk_size_t) off <= blen_target); |
| 43466 | blen_left = blen_target - (duk_size_t) off; |
| 43467 | if (blen_left >= blen_search) { |
| 43468 | const duk_uint8_t *p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_target) + off; |
| 43469 | const duk_uint8_t *p_search = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_search); |
| 43470 | if (duk_memcmp_unsafe((const void *) p_cmp_start, (const void *) p_search, (size_t) blen_search) == 0) { |
| 43471 | result = 1; |
| 43472 | } |
| 43473 | } |
| 43474 | |
| 43475 | finish: |
| 43476 | duk_push_boolean(thr, result); |
| 43477 | return 1; |
| 43478 | } |
| 43479 | #endif /* DUK_USE_ES6 */ |
| 43480 | |
| 43481 | #if defined(DUK_USE_ES6) |
| 43482 | DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_hthread *thr) { |
| 43483 | duk_hstring *h; |
| 43484 | duk_hstring *h_search; |
| 43485 | duk_int_t len; |
| 43486 | duk_int_t pos; |
| 43487 | |
| 43488 | h = duk_push_this_coercible_to_string(thr); |
| 43489 | DUK_ASSERT(h != NULL); |
| 43490 | |
| 43491 | h_search = duk__str_tostring_notregexp(thr, 0); |
| 43492 | DUK_ASSERT(h_search != NULL); |
| 43493 | |
| 43494 | len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h); |
| 43495 | pos = duk_to_int_clamped(thr, 1, 0, len); |
| 43496 | DUK_ASSERT(pos >= 0 && pos <= len); |
| 43497 | |
| 43498 | pos = duk__str_search_shared(thr, h, h_search, pos, 0 /*backwards*/); |
| 43499 | duk_push_boolean(thr, pos >= 0); |
| 43500 | return 1; |
| 43501 | } |
| 43502 | #endif /* DUK_USE_ES6 */ |
| 43503 | #endif /* DUK_USE_STRING_BUILTIN */ |
| 43504 | #line 1 "duk_bi_symbol.c" |
| 43505 | /* |
| 43506 | * Symbol built-in |
| 43507 | */ |
| 43508 | |
| 43509 | /* #include duk_internal.h -> already included */ |
| 43510 | |
| 43511 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 43512 | |
| 43513 | /* |
| 43514 | * Constructor |
| 43515 | */ |
| 43516 | |
| 43517 | DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) { |
| 43518 | const duk_uint8_t *desc; |
| 43519 | duk_size_t len; |
| 43520 | duk_uint8_t *buf; |
| 43521 | duk_uint8_t *p; |
| 43522 | duk_int_t magic; |
| 43523 | |
| 43524 | magic = duk_get_current_magic(thr); |
| 43525 | if (duk_is_undefined(thr, 0) && (magic == 0)) { |
| 43526 | /* Symbol() accepts undefined and empty string, but they are |
| 43527 | * treated differently. |
| 43528 | */ |
| 43529 | desc = NULL; |
| 43530 | len = 0; |
| 43531 | } else { |
| 43532 | /* Symbol.for() coerces undefined to 'undefined' */ |
| 43533 | desc = (const duk_uint8_t *) duk_to_lstring(thr, 0, &len); |
| 43534 | } |
| 43535 | |
| 43536 | /* Maximum symbol data length: |
| 43537 | * +1 initial byte (0x80 or 0x81) |
| 43538 | * +len description |
| 43539 | * +1 0xff after description, before unique suffix |
| 43540 | * +17 autogenerated unique suffix: 'ffffffff-ffffffff' is longest |
| 43541 | * +1 0xff after unique suffix for symbols with undefined description |
| 43542 | */ |
| 43543 | buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1); |
| 43544 | DUK_ASSERT(buf != NULL); |
| 43545 | p = buf + 1; |
| 43546 | DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */ |
| 43547 | duk_memcpy_unsafe((void *) p, (const void *) desc, len); |
| 43548 | p += len; |
| 43549 | if (magic == 0) { |
| 43550 | /* Symbol(): create unique symbol. Use two 32-bit values |
| 43551 | * to avoid dependency on 64-bit types and 64-bit integer |
| 43552 | * formatting (at least for now). |
| 43553 | */ |
| 43554 | if (++thr->heap->sym_counter[0] == 0) { |
| 43555 | thr->heap->sym_counter[1]++; |
| 43556 | } |
| 43557 | p += DUK_SPRINTF((char *) p, "\xFF" "%lx-%lx" , |
| 43558 | (unsigned long) thr->heap->sym_counter[1], |
| 43559 | (unsigned long) thr->heap->sym_counter[0]); |
| 43560 | if (desc == NULL) { |
| 43561 | /* Special case for 'undefined' description, trailing |
| 43562 | * 0xff distinguishes from empty string description, |
| 43563 | * but needs minimal special case handling elsewhere. |
| 43564 | */ |
| 43565 | *p++ = 0xff; |
| 43566 | } |
| 43567 | buf[0] = 0x81; |
| 43568 | } else { |
| 43569 | /* Symbol.for(): create a global symbol */ |
| 43570 | buf[0] = 0x80; |
| 43571 | } |
| 43572 | |
| 43573 | duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf)); |
| 43574 | DUK_DDD(DUK_DDDPRINT("created symbol: %!T" , duk_get_tval(thr, -1))); |
| 43575 | return 1; |
| 43576 | } |
| 43577 | |
| 43578 | DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_hthread *thr, duk_tval *tv_arg) { |
| 43579 | duk_tval *tv; |
| 43580 | duk_hobject *h_obj; |
| 43581 | duk_hstring *h_str; |
| 43582 | |
| 43583 | DUK_ASSERT(tv_arg != NULL); |
| 43584 | |
| 43585 | /* XXX: add internal helper: duk_auto_unbox_tval(thr, tv, mask); */ |
| 43586 | /* XXX: add internal helper: duk_auto_unbox(thr, tv, idx); */ |
| 43587 | |
| 43588 | tv = tv_arg; |
| 43589 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 43590 | h_obj = DUK_TVAL_GET_OBJECT(tv); |
| 43591 | DUK_ASSERT(h_obj != NULL); |
| 43592 | if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) { |
| 43593 | tv = duk_hobject_get_internal_value_tval_ptr(thr->heap, h_obj); |
| 43594 | if (tv == NULL) { |
| 43595 | return NULL; |
| 43596 | } |
| 43597 | } else { |
| 43598 | return NULL; |
| 43599 | } |
| 43600 | } |
| 43601 | |
| 43602 | if (!DUK_TVAL_IS_STRING(tv)) { |
| 43603 | return NULL; |
| 43604 | } |
| 43605 | h_str = DUK_TVAL_GET_STRING(tv); |
| 43606 | DUK_ASSERT(h_str != NULL); |
| 43607 | |
| 43608 | /* Here symbol is more expected than not. */ |
| 43609 | if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) { |
| 43610 | return NULL; |
| 43611 | } |
| 43612 | |
| 43613 | return h_str; |
| 43614 | } |
| 43615 | |
| 43616 | DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_hthread *thr) { |
| 43617 | duk_hstring *h_str; |
| 43618 | |
| 43619 | h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr)); |
| 43620 | if (h_str == NULL) { |
| 43621 | return DUK_RET_TYPE_ERROR; |
| 43622 | } |
| 43623 | |
| 43624 | if (duk_get_current_magic(thr) == 0) { |
| 43625 | /* .toString() */ |
| 43626 | duk_push_symbol_descriptive_string(thr, h_str); |
| 43627 | } else { |
| 43628 | /* .valueOf() */ |
| 43629 | duk_push_hstring(thr, h_str); |
| 43630 | } |
| 43631 | return 1; |
| 43632 | } |
| 43633 | |
| 43634 | DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_hthread *thr) { |
| 43635 | duk_hstring *h; |
| 43636 | const duk_uint8_t *p; |
| 43637 | |
| 43638 | /* Argument must be a symbol but not checked here. The initial byte |
| 43639 | * check will catch non-symbol strings. |
| 43640 | */ |
| 43641 | h = duk_require_hstring(thr, 0); |
| 43642 | DUK_ASSERT(h != NULL); |
| 43643 | |
| 43644 | p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); |
| 43645 | DUK_ASSERT(p != NULL); |
| 43646 | |
| 43647 | /* Even for zero length strings there's at least one NUL byte so |
| 43648 | * we can safely check the initial byte. |
| 43649 | */ |
| 43650 | if (p[0] == 0x80) { |
| 43651 | /* Global symbol, return its key (bytes just after the initial byte). */ |
| 43652 | duk_push_lstring(thr, (const char *) (p + 1), (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h) - 1)); |
| 43653 | return 1; |
| 43654 | } else if (p[0] == 0x81 || p[0] == 0x82 || p[0] == 0xff) { |
| 43655 | /* Local symbol or hidden symbol, return undefined. */ |
| 43656 | return 0; |
| 43657 | } |
| 43658 | |
| 43659 | /* Covers normal strings and unknown initial bytes. */ |
| 43660 | return DUK_RET_TYPE_ERROR; |
| 43661 | } |
| 43662 | |
| 43663 | DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_hthread *thr) { |
| 43664 | duk_hstring *h_str; |
| 43665 | |
| 43666 | h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr)); |
| 43667 | if (h_str == NULL) { |
| 43668 | return DUK_RET_TYPE_ERROR; |
| 43669 | } |
| 43670 | duk_push_hstring(thr, h_str); |
| 43671 | return 1; |
| 43672 | } |
| 43673 | |
| 43674 | #endif /* DUK_USE_SYMBOL_BUILTIN */ |
| 43675 | #line 1 "duk_bi_thread.c" |
| 43676 | /* |
| 43677 | * Thread builtins |
| 43678 | */ |
| 43679 | |
| 43680 | /* #include duk_internal.h -> already included */ |
| 43681 | |
| 43682 | /* |
| 43683 | * Constructor |
| 43684 | */ |
| 43685 | |
| 43686 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 43687 | DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) { |
| 43688 | duk_hthread *new_thr; |
| 43689 | duk_hobject *func; |
| 43690 | |
| 43691 | /* Check that the argument is callable; this is not 100% because we |
| 43692 | * don't allow native functions to be a thread's initial function. |
| 43693 | * Resume will reject such functions in any case. |
| 43694 | */ |
| 43695 | /* XXX: need a duk_require_func_promote_lfunc() */ |
| 43696 | func = duk_require_hobject_promote_lfunc(thr, 0); |
| 43697 | DUK_ASSERT(func != NULL); |
| 43698 | duk_require_callable(thr, 0); |
| 43699 | |
| 43700 | duk_push_thread(thr); |
| 43701 | new_thr = (duk_hthread *) duk_known_hobject(thr, -1); |
| 43702 | new_thr->state = DUK_HTHREAD_STATE_INACTIVE; |
| 43703 | |
| 43704 | /* push initial function call to new thread stack; this is |
| 43705 | * picked up by resume(). |
| 43706 | */ |
| 43707 | duk_push_hobject(new_thr, func); |
| 43708 | |
| 43709 | return 1; /* return thread */ |
| 43710 | } |
| 43711 | #endif |
| 43712 | |
| 43713 | /* |
| 43714 | * Resume a thread. |
| 43715 | * |
| 43716 | * The thread must be in resumable state, either (a) new thread which hasn't |
| 43717 | * yet started, or (b) a thread which has previously yielded. This method |
| 43718 | * must be called from an ECMAScript function. |
| 43719 | * |
| 43720 | * Args: |
| 43721 | * - thread |
| 43722 | * - value |
| 43723 | * - isError (defaults to false) |
| 43724 | * |
| 43725 | * Note: yield and resume handling is currently asymmetric. |
| 43726 | */ |
| 43727 | |
| 43728 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 43729 | DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) { |
| 43730 | duk_hthread *thr = (duk_hthread *) ctx; |
| 43731 | duk_hthread *thr_resume; |
| 43732 | duk_hobject *caller_func; |
| 43733 | duk_small_uint_t is_error; |
| 43734 | |
| 43735 | DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T" , |
| 43736 | (duk_tval *) duk_get_tval(thr, 0), |
| 43737 | (duk_tval *) duk_get_tval(thr, 1), |
| 43738 | (duk_tval *) duk_get_tval(thr, 2))); |
| 43739 | |
| 43740 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); |
| 43741 | DUK_ASSERT(thr->heap->curr_thread == thr); |
| 43742 | |
| 43743 | thr_resume = duk_require_hthread(thr, 0); |
| 43744 | DUK_ASSERT(duk_get_top(thr) == 3); |
| 43745 | is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr); |
| 43746 | DUK_ASSERT(duk_get_top(thr) == 2); |
| 43747 | |
| 43748 | /* [ thread value ] */ |
| 43749 | |
| 43750 | /* |
| 43751 | * Thread state and calling context checks |
| 43752 | */ |
| 43753 | |
| 43754 | if (thr->callstack_top < 2) { |
| 43755 | DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)" )); |
| 43756 | goto state_error; |
| 43757 | } |
| 43758 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 43759 | DUK_ASSERT(thr->callstack_curr->parent != NULL); |
| 43760 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */ |
| 43761 | DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); |
| 43762 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */ |
| 43763 | |
| 43764 | caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent); |
| 43765 | if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { |
| 43766 | DUK_DD(DUK_DDPRINT("resume state invalid: caller must be ECMAScript code" )); |
| 43767 | goto state_error; |
| 43768 | } |
| 43769 | |
| 43770 | /* Note: there is no requirement that: 'thr->callstack_preventcount == 1' |
| 43771 | * like for yield. |
| 43772 | */ |
| 43773 | |
| 43774 | if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE && |
| 43775 | thr_resume->state != DUK_HTHREAD_STATE_YIELDED) { |
| 43776 | DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED" )); |
| 43777 | goto state_error; |
| 43778 | } |
| 43779 | |
| 43780 | DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE || |
| 43781 | thr_resume->state == DUK_HTHREAD_STATE_YIELDED); |
| 43782 | |
| 43783 | /* Further state-dependent pre-checks */ |
| 43784 | |
| 43785 | if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) { |
| 43786 | /* no pre-checks now, assume a previous yield() has left things in |
| 43787 | * tip-top shape (longjmp handler will assert for these). |
| 43788 | */ |
| 43789 | } else { |
| 43790 | duk_hobject *h_fun; |
| 43791 | |
| 43792 | DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE); |
| 43793 | |
| 43794 | /* The initial function must be an ECMAScript function (but |
| 43795 | * can be bound). We must make sure of that before we longjmp |
| 43796 | * because an error in the RESUME handler call processing will |
| 43797 | * not be handled very cleanly. |
| 43798 | */ |
| 43799 | if ((thr_resume->callstack_top != 0) || |
| 43800 | (thr_resume->valstack_top - thr_resume->valstack != 1)) { |
| 43801 | goto state_error; |
| 43802 | } |
| 43803 | |
| 43804 | duk_push_tval(thr, DUK_GET_TVAL_NEGIDX(thr_resume, -1)); |
| 43805 | duk_resolve_nonbound_function(thr); |
| 43806 | h_fun = duk_require_hobject(thr, -1); /* reject lightfuncs on purpose */ |
| 43807 | if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) { |
| 43808 | goto state_error; |
| 43809 | } |
| 43810 | duk_pop(thr); |
| 43811 | } |
| 43812 | |
| 43813 | #if 0 |
| 43814 | /* This check would prevent a heap destruction time finalizer from |
| 43815 | * launching a coroutine, which would ensure that during finalization |
| 43816 | * 'thr' would always equal heap_thread. Normal runtime finalizers |
| 43817 | * run with ms_running == 0, i.e. outside mark-and-sweep. See GH-2030. |
| 43818 | */ |
| 43819 | if (thr->heap->ms_running) { |
| 43820 | DUK_D(DUK_DPRINT("refuse Duktape.Thread.resume() when ms_running != 0" )); |
| 43821 | goto state_error; |
| 43822 | } |
| 43823 | #endif |
| 43824 | |
| 43825 | /* |
| 43826 | * The error object has been augmented with a traceback and other |
| 43827 | * info from its creation point -- usually another thread. The |
| 43828 | * error handler is called here right before throwing, but it also |
| 43829 | * runs in the resumer's thread. It might be nice to get a traceback |
| 43830 | * from the resumee but this is not the case now. |
| 43831 | */ |
| 43832 | |
| 43833 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) |
| 43834 | if (is_error) { |
| 43835 | DUK_ASSERT_TOP(thr, 2); /* value (error) is at stack top */ |
| 43836 | duk_err_augment_error_throw(thr); /* in resumer's context */ |
| 43837 | } |
| 43838 | #endif |
| 43839 | |
| 43840 | #if defined(DUK_USE_DEBUG) |
| 43841 | if (is_error) { |
| 43842 | DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T" , |
| 43843 | (duk_tval *) duk_get_tval(thr, 0), |
| 43844 | (duk_tval *) duk_get_tval(thr, 1))); |
| 43845 | } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) { |
| 43846 | DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T" , |
| 43847 | (duk_tval *) duk_get_tval(thr, 0), |
| 43848 | (duk_tval *) duk_get_tval(thr, 1))); |
| 43849 | } else { |
| 43850 | DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T" , |
| 43851 | (duk_tval *) duk_get_tval(thr, 0), |
| 43852 | (duk_tval *) duk_get_tval(thr, 1))); |
| 43853 | } |
| 43854 | #endif |
| 43855 | |
| 43856 | thr->heap->lj.type = DUK_LJ_TYPE_RESUME; |
| 43857 | |
| 43858 | /* lj value2: thread */ |
| 43859 | DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); |
| 43860 | DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */ |
| 43861 | |
| 43862 | /* lj value1: value */ |
| 43863 | DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top); |
| 43864 | DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */ |
| 43865 | DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1); |
| 43866 | |
| 43867 | thr->heap->lj.iserror = is_error; |
| 43868 | |
| 43869 | DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */ |
| 43870 | duk_err_longjmp(thr); /* execution resumes in bytecode executor */ |
| 43871 | DUK_UNREACHABLE(); |
| 43872 | /* Never here, fall through to error (from compiler point of view). */ |
| 43873 | |
| 43874 | state_error: |
| 43875 | DUK_DCERROR_TYPE_INVALID_STATE(thr); |
| 43876 | } |
| 43877 | #endif |
| 43878 | |
| 43879 | /* |
| 43880 | * Yield the current thread. |
| 43881 | * |
| 43882 | * The thread must be in yieldable state: it must have a resumer, and there |
| 43883 | * must not be any yield-preventing calls (native calls and constructor calls, |
| 43884 | * currently) in the thread's call stack (otherwise a resume would not be |
| 43885 | * possible later). This method must be called from an ECMAScript function. |
| 43886 | * |
| 43887 | * Args: |
| 43888 | * - value |
| 43889 | * - isError (defaults to false) |
| 43890 | * |
| 43891 | * Note: yield and resume handling is currently asymmetric. |
| 43892 | */ |
| 43893 | |
| 43894 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 43895 | DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) { |
| 43896 | duk_hobject *caller_func; |
| 43897 | duk_small_uint_t is_error; |
| 43898 | |
| 43899 | DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T" , |
| 43900 | (duk_tval *) duk_get_tval(thr, 0), |
| 43901 | (duk_tval *) duk_get_tval(thr, 1))); |
| 43902 | |
| 43903 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); |
| 43904 | DUK_ASSERT(thr->heap->curr_thread == thr); |
| 43905 | |
| 43906 | DUK_ASSERT(duk_get_top(thr) == 2); |
| 43907 | is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr); |
| 43908 | DUK_ASSERT(duk_get_top(thr) == 1); |
| 43909 | |
| 43910 | /* [ value ] */ |
| 43911 | |
| 43912 | /* |
| 43913 | * Thread state and calling context checks |
| 43914 | */ |
| 43915 | |
| 43916 | if (!thr->resumer) { |
| 43917 | DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer" )); |
| 43918 | goto state_error; |
| 43919 | } |
| 43920 | DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); |
| 43921 | |
| 43922 | if (thr->callstack_top < 2) { |
| 43923 | DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)" )); |
| 43924 | goto state_error; |
| 43925 | } |
| 43926 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 43927 | DUK_ASSERT(thr->callstack_curr->parent != NULL); |
| 43928 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */ |
| 43929 | DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); |
| 43930 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */ |
| 43931 | |
| 43932 | caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent); |
| 43933 | if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) { |
| 43934 | DUK_DD(DUK_DDPRINT("yield state invalid: caller must be ECMAScript code" )); |
| 43935 | goto state_error; |
| 43936 | } |
| 43937 | |
| 43938 | DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */ |
| 43939 | if (thr->callstack_preventcount != 1) { |
| 43940 | /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */ |
| 43941 | DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)" , |
| 43942 | (long) thr->callstack_preventcount)); |
| 43943 | goto state_error; |
| 43944 | } |
| 43945 | |
| 43946 | /* |
| 43947 | * The error object has been augmented with a traceback and other |
| 43948 | * info from its creation point -- usually the current thread. |
| 43949 | * The error handler, however, is called right before throwing |
| 43950 | * and runs in the yielder's thread. |
| 43951 | */ |
| 43952 | |
| 43953 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) |
| 43954 | if (is_error) { |
| 43955 | DUK_ASSERT_TOP(thr, 1); /* value (error) is at stack top */ |
| 43956 | duk_err_augment_error_throw(thr); /* in yielder's context */ |
| 43957 | } |
| 43958 | #endif |
| 43959 | |
| 43960 | #if defined(DUK_USE_DEBUG) |
| 43961 | if (is_error) { |
| 43962 | DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T" , |
| 43963 | (duk_tval *) duk_get_tval(thr, 0))); |
| 43964 | } else { |
| 43965 | DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T" , |
| 43966 | (duk_tval *) duk_get_tval(thr, 0))); |
| 43967 | } |
| 43968 | #endif |
| 43969 | |
| 43970 | /* |
| 43971 | * Process yield |
| 43972 | * |
| 43973 | * After longjmp(), processing continues in bytecode executor longjmp |
| 43974 | * handler, which will e.g. update thr->resumer to NULL. |
| 43975 | */ |
| 43976 | |
| 43977 | thr->heap->lj.type = DUK_LJ_TYPE_YIELD; |
| 43978 | |
| 43979 | /* lj value1: value */ |
| 43980 | DUK_ASSERT(thr->valstack_bottom < thr->valstack_top); |
| 43981 | DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */ |
| 43982 | DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1); |
| 43983 | |
| 43984 | thr->heap->lj.iserror = is_error; |
| 43985 | |
| 43986 | DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */ |
| 43987 | duk_err_longjmp(thr); /* execution resumes in bytecode executor */ |
| 43988 | DUK_UNREACHABLE(); |
| 43989 | /* Never here, fall through to error (from compiler point of view). */ |
| 43990 | |
| 43991 | state_error: |
| 43992 | DUK_DCERROR_TYPE_INVALID_STATE(thr); |
| 43993 | } |
| 43994 | #endif |
| 43995 | |
| 43996 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 43997 | DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_hthread *thr) { |
| 43998 | duk_push_current_thread(thr); |
| 43999 | return 1; |
| 44000 | } |
| 44001 | #endif |
| 44002 | #line 1 "duk_bi_thrower.c" |
| 44003 | /* |
| 44004 | * Type error thrower, E5 Section 13.2.3. |
| 44005 | */ |
| 44006 | |
| 44007 | /* #include duk_internal.h -> already included */ |
| 44008 | |
| 44009 | DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_hthread *thr) { |
| 44010 | DUK_DCERROR_TYPE_INVALID_ARGS(thr); |
| 44011 | } |
| 44012 | #line 1 "duk_debug_fixedbuffer.c" |
| 44013 | /* |
| 44014 | * Fixed buffer helper useful for debugging, requires no allocation |
| 44015 | * which is critical for debugging. |
| 44016 | */ |
| 44017 | |
| 44018 | /* #include duk_internal.h -> already included */ |
| 44019 | |
| 44020 | #if defined(DUK_USE_DEBUG) |
| 44021 | |
| 44022 | DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) { |
| 44023 | duk_size_t avail; |
| 44024 | duk_size_t copylen; |
| 44025 | |
| 44026 | avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset)); |
| 44027 | if (length > avail) { |
| 44028 | copylen = avail; |
| 44029 | fb->truncated = 1; |
| 44030 | } else { |
| 44031 | copylen = length; |
| 44032 | } |
| 44033 | duk_memcpy_unsafe(fb->buffer + fb->offset, buffer, copylen); |
| 44034 | fb->offset += copylen; |
| 44035 | } |
| 44036 | |
| 44037 | DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) { |
| 44038 | duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1); |
| 44039 | } |
| 44040 | |
| 44041 | DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) { |
| 44042 | duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x)); |
| 44043 | } |
| 44044 | |
| 44045 | DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) { |
| 44046 | duk_size_t avail; |
| 44047 | va_list ap; |
| 44048 | |
| 44049 | va_start(ap, fmt); |
| 44050 | avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset)); |
| 44051 | if (avail > 0) { |
| 44052 | duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap); |
| 44053 | if (res < 0) { |
| 44054 | /* error */ |
| 44055 | } else if ((duk_size_t) res >= avail) { |
| 44056 | /* (maybe) truncated */ |
| 44057 | fb->offset += avail; |
| 44058 | if ((duk_size_t) res > avail) { |
| 44059 | /* actual chars dropped (not just NUL term) */ |
| 44060 | fb->truncated = 1; |
| 44061 | } |
| 44062 | } else { |
| 44063 | /* normal */ |
| 44064 | fb->offset += (duk_size_t) res; |
| 44065 | } |
| 44066 | } |
| 44067 | va_end(ap); |
| 44068 | } |
| 44069 | |
| 44070 | DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) { |
| 44071 | char buf[64+1]; |
| 44072 | duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size); |
| 44073 | buf[sizeof(buf) - 1] = (char) 0; |
| 44074 | duk_fb_put_cstring(fb, buf); |
| 44075 | } |
| 44076 | |
| 44077 | DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) { |
| 44078 | return (fb->offset >= fb->length); |
| 44079 | } |
| 44080 | |
| 44081 | #endif /* DUK_USE_DEBUG */ |
| 44082 | #line 1 "duk_debug_vsnprintf.c" |
| 44083 | /* |
| 44084 | * Custom formatter for debug printing, allowing Duktape specific data |
| 44085 | * structures (such as tagged values and heap objects) to be printed with |
| 44086 | * a nice format string. Because debug printing should not affect execution |
| 44087 | * state, formatting here must be independent of execution (see implications |
| 44088 | * below) and must not allocate memory. |
| 44089 | * |
| 44090 | * Custom format tags begin with a '%!' to safely distinguish them from |
| 44091 | * standard format tags. The following conversions are supported: |
| 44092 | * |
| 44093 | * %!T tagged value (duk_tval *) |
| 44094 | * %!O heap object (duk_heaphdr *) |
| 44095 | * %!I decoded bytecode instruction |
| 44096 | * %!X bytecode instruction opcode name (arg is long) |
| 44097 | * %!C catcher (duk_catcher *) |
| 44098 | * %!A activation (duk_activation *) |
| 44099 | * |
| 44100 | * Everything is serialized in a JSON-like manner. The default depth is one |
| 44101 | * level, internal prototype is not followed, and internal properties are not |
| 44102 | * serialized. The following modifiers change this behavior: |
| 44103 | * |
| 44104 | * @ print pointers |
| 44105 | * # print binary representations (where applicable) |
| 44106 | * d deep traversal of own properties (not prototype) |
| 44107 | * p follow prototype chain (useless without 'd') |
| 44108 | * i include internal properties (other than prototype) |
| 44109 | * x hexdump buffers |
| 44110 | * h heavy formatting |
| 44111 | * |
| 44112 | * For instance, the following serializes objects recursively, but does not |
| 44113 | * follow the prototype chain nor print internal properties: "%!dO". |
| 44114 | * |
| 44115 | * Notes: |
| 44116 | * |
| 44117 | * * Standard snprintf return value semantics seem to vary. This |
| 44118 | * implementation returns the number of bytes it actually wrote |
| 44119 | * (excluding the null terminator). If retval == buffer size, |
| 44120 | * output was truncated (except for corner cases). |
| 44121 | * |
| 44122 | * * Output format is intentionally different from ECMAScript |
| 44123 | * formatting requirements, as formatting here serves debugging |
| 44124 | * of internals. |
| 44125 | * |
| 44126 | * * Depth checking (and updating) is done in each type printer |
| 44127 | * separately, to allow them to call each other freely. |
| 44128 | * |
| 44129 | * * Some pathological structures might take ages to print (e.g. |
| 44130 | * self recursion with 100 properties pointing to the object |
| 44131 | * itself). To guard against these, each printer also checks |
| 44132 | * whether the output buffer is full; if so, early exit. |
| 44133 | * |
| 44134 | * * Reference loops are detected using a loop stack. |
| 44135 | */ |
| 44136 | |
| 44137 | /* #include duk_internal.h -> already included */ |
| 44138 | |
| 44139 | #if defined(DUK_USE_DEBUG) |
| 44140 | |
| 44141 | /* #include stdio.h -> already included */ |
| 44142 | /* #include stdarg.h -> already included */ |
| 44143 | #include <string.h> |
| 44144 | |
| 44145 | /* list of conversion specifiers that terminate a format tag; |
| 44146 | * this is unfortunately guesswork. |
| 44147 | */ |
| 44148 | #define DUK__ALLOWED_STANDARD_SPECIFIERS "diouxXeEfFgGaAcsCSpnm" |
| 44149 | |
| 44150 | /* maximum length of standard format tag that we support */ |
| 44151 | #define DUK__MAX_FORMAT_TAG_LENGTH 32 |
| 44152 | |
| 44153 | /* heapobj recursion depth when deep printing is selected */ |
| 44154 | #define DUK__DEEP_DEPTH_LIMIT 8 |
| 44155 | |
| 44156 | /* maximum recursion depth for loop detection stacks */ |
| 44157 | #define DUK__LOOP_STACK_DEPTH 256 |
| 44158 | |
| 44159 | /* must match bytecode defines now; build autogenerate? */ |
| 44160 | DUK_LOCAL const char * const duk__bc_optab[256] = { |
| 44161 | "LDREG" , "STREG" , "JUMP" , "LDCONST" , "LDINT" , "LDINTX" , "LDTHIS" , "LDUNDEF" , |
| 44162 | "LDNULL" , "LDTRUE" , "LDFALSE" , "GETVAR" , "BNOT" , "LNOT" , "UNM" , "UNP" , |
| 44163 | "EQ_RR" , "EQ_CR" , "EQ_RC" , "EQ_CC" , "NEQ_RR" , "NEQ_CR" , "NEQ_RC" , "NEQ_CC" , |
| 44164 | "SEQ_RR" , "SEQ_CR" , "SEQ_RC" , "SEQ_CC" , "SNEQ_RR" , "SNEQ_CR" , "SNEQ_RC" , "SNEQ_CC" , |
| 44165 | |
| 44166 | "GT_RR" , "GT_CR" , "GT_RC" , "GT_CC" , "GE_RR" , "GE_CR" , "GE_RC" , "GE_CC" , |
| 44167 | "LT_RR" , "LT_CR" , "LT_RC" , "LT_CC" , "LE_RR" , "LE_CR" , "LE_RC" , "LE_CC" , |
| 44168 | "IFTRUE_R" , "IFTRUE_C" , "IFFALSE_R" , "IFFALSE_C" , "ADD_RR" , "ADD_CR" , "ADD_RC" , "ADD_CC" , |
| 44169 | "SUB_RR" , "SUB_CR" , "SUB_RC" , "SUB_CC" , "MUL_RR" , "MUL_CR" , "MUL_RC" , "MUL_CC" , |
| 44170 | |
| 44171 | "DIV_RR" , "DIV_CR" , "DIV_RC" , "DIV_CC" , "MOD_RR" , "MOD_CR" , "MOD_RC" , "MOD_CC" , |
| 44172 | "EXP_RR" , "EXP_CR" , "EXP_RC" , "EXP_CC" , "BAND_RR" , "BAND_CR" , "BAND_RC" , "BAND_CC" , |
| 44173 | "BOR_RR" , "BOR_CR" , "BOR_RC" , "BOR_CC" , "BXOR_RR" , "BXOR_CR" , "BXOR_RC" , "BXOR_CC" , |
| 44174 | "BASL_RR" , "BASL_CR" , "BASL_RC" , "BASL_CC" , "BLSR_RR" , "BLSR_CR" , "BLSR_RC" , "BLSR_CC" , |
| 44175 | |
| 44176 | "BASR_RR" , "BASR_CR" , "BASR_RC" , "BASR_CC" , "INSTOF_RR" , "INSTOF_CR" , "INSTOF_RC" , "INSTOF_CC" , |
| 44177 | "IN_RR" , "IN_CR" , "IN_RC" , "IN_CC" , "GETPROP_RR" , "GETPROP_CR" , "GETPROP_RC" , "GETPROP_CC" , |
| 44178 | "PUTPROP_RR" , "PUTPROP_CR" , "PUTPROP_RC" , "PUTPROP_CC" , "DELPROP_RR" , "DELPROP_CR" , "DELPROP_RC" , "DELPROP_CC" , |
| 44179 | "PREINCR" , "PREDECR" , "POSTINCR" , "POSTDECR" , "PREINCV" , "PREDECV" , "POSTINCV" , "POSTDECV" , |
| 44180 | |
| 44181 | "PREINCP_RR" , "PREINCP_CR" , "PREINCP_RC" , "PREINCP_CC" , "PREDECP_RR" , "PREDECP_CR" , "PREDECP_RC" , "PREDECP_CC" , |
| 44182 | "POSTINCP_RR" , "POSTINCP_CR" , "POSTINCP_RC" , "POSTINCP_CC" , "POSTDECP_RR" , "POSTDECP_CR" , "POSTDECP_RC" , "POSTDECP_CC" , |
| 44183 | "DECLVAR_RR" , "DECLVAR_CR" , "DECLVAR_RC" , "DECLVAR_CC" , "REGEXP_RR" , "REGEXP_RC" , "REGEXP_CR" , "REGEXP_CC" , |
| 44184 | "CLOSURE" , "TYPEOF" , "TYPEOFID" , "PUTVAR" , "DELVAR" , "RETREG" , "RETUNDEF" , "RETCONST" , |
| 44185 | |
| 44186 | "RETCONSTN" , "LABEL" , "ENDLABEL" , "BREAK" , "CONTINUE" , "TRYCATCH" , "ENDTRY" , "ENDCATCH" , |
| 44187 | "ENDFIN" , "THROW" , "INVLHS" , "CSREG" , "CSVAR_RR" , "CSVAR_CR" , "CSVAR_RC" , "CSVAR_CC" , |
| 44188 | "CALL0" , "CALL1" , "CALL2" , "CALL3" , "CALL4" , "CALL5" , "CALL6" , "CALL7" , |
| 44189 | "CALL8" , "CALL9" , "CALL10" , "CALL11" , "CALL12" , "CALL13" , "CALL14" , "CALL15" , |
| 44190 | |
| 44191 | "NEWOBJ" , "NEWARR" , "MPUTOBJ" , "MPUTOBJI" , "INITSET" , "INITGET" , "MPUTARR" , "MPUTARRI" , |
| 44192 | "SETALEN" , "INITENUM" , "NEXTENUM" , "NEWTARGET" , "DEBUGGER" , "NOP" , "INVALID" , "UNUSED207" , |
| 44193 | "GETPROPC_RR" , "GETPROPC_CR" , "GETPROPC_RC" , "GETPROPC_CC" , "UNUSED212" , "UNUSED213" , "UNUSED214" , "UNUSED215" , |
| 44194 | "UNUSED216" , "UNUSED217" , "UNUSED218" , "UNUSED219" , "UNUSED220" , "UNUSED221" , "UNUSED222" , "UNUSED223" , |
| 44195 | |
| 44196 | "UNUSED224" , "UNUSED225" , "UNUSED226" , "UNUSED227" , "UNUSED228" , "UNUSED229" , "UNUSED230" , "UNUSED231" , |
| 44197 | "UNUSED232" , "UNUSED233" , "UNUSED234" , "UNUSED235" , "UNUSED236" , "UNUSED237" , "UNUSED238" , "UNUSED239" , |
| 44198 | "UNUSED240" , "UNUSED241" , "UNUSED242" , "UNUSED243" , "UNUSED244" , "UNUSED245" , "UNUSED246" , "UNUSED247" , |
| 44199 | "UNUSED248" , "UNUSED249" , "UNUSED250" , "UNUSED251" , "UNUSED252" , "UNUSED253" , "UNUSED254" , "UNUSED255" |
| 44200 | }; |
| 44201 | |
| 44202 | typedef struct duk__dprint_state duk__dprint_state; |
| 44203 | struct duk__dprint_state { |
| 44204 | duk_fixedbuffer *fb; |
| 44205 | |
| 44206 | /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice |
| 44207 | * to not couple these two mechanisms unnecessarily. |
| 44208 | */ |
| 44209 | duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH]; |
| 44210 | duk_int_t loop_stack_index; |
| 44211 | duk_int_t loop_stack_limit; |
| 44212 | |
| 44213 | duk_int_t depth; |
| 44214 | duk_int_t depth_limit; |
| 44215 | |
| 44216 | duk_bool_t pointer; |
| 44217 | duk_bool_t heavy; |
| 44218 | duk_bool_t binary; |
| 44219 | duk_bool_t follow_proto; |
| 44220 | duk_bool_t internal; |
| 44221 | duk_bool_t hexdump; |
| 44222 | }; |
| 44223 | |
| 44224 | /* helpers */ |
| 44225 | DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes); |
| 44226 | DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h); |
| 44227 | DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h); |
| 44228 | DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv); |
| 44229 | DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins); |
| 44230 | DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h); |
| 44231 | DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h); |
| 44232 | DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h); |
| 44233 | |
| 44234 | DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) { |
| 44235 | duk_fixedbuffer *fb = st->fb; |
| 44236 | |
| 44237 | if (st->heavy) { |
| 44238 | duk_fb_sprintf(fb, "(%p)" , (void *) h); |
| 44239 | } |
| 44240 | |
| 44241 | if (!h) { |
| 44242 | return; |
| 44243 | } |
| 44244 | |
| 44245 | if (st->binary) { |
| 44246 | duk_size_t i; |
| 44247 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET); |
| 44248 | for (i = 0; i < (duk_size_t) sizeof(*h); i++) { |
| 44249 | duk_fb_sprintf(fb, "%02lx" , (unsigned long) ((duk_uint8_t *)h)[i]); |
| 44250 | } |
| 44251 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET); |
| 44252 | } |
| 44253 | |
| 44254 | #if defined(DUK_USE_REFERENCE_COUNTING) /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */ |
| 44255 | if (st->heavy) { |
| 44256 | duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld," |
| 44257 | "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]" , |
| 44258 | (void *) DUK_HEAPHDR_GET_NEXT(NULL, h), |
| 44259 | (void *) DUK_HEAPHDR_GET_PREV(NULL, h), |
| 44260 | (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h), |
| 44261 | (unsigned long) DUK_HEAPHDR_GET_FLAGS(h), |
| 44262 | (long) DUK_HEAPHDR_GET_TYPE(h), |
| 44263 | (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0), |
| 44264 | (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0), |
| 44265 | (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0), |
| 44266 | (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0)); |
| 44267 | } |
| 44268 | #else |
| 44269 | if (st->heavy) { |
| 44270 | duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]" , |
| 44271 | (void *) DUK_HEAPHDR_GET_NEXT(NULL, h), |
| 44272 | (unsigned long) DUK_HEAPHDR_GET_FLAGS(h), |
| 44273 | (long) DUK_HEAPHDR_GET_TYPE(h), |
| 44274 | (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0), |
| 44275 | (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0), |
| 44276 | (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0), |
| 44277 | (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0)); |
| 44278 | } |
| 44279 | #endif |
| 44280 | } |
| 44281 | |
| 44282 | DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) { |
| 44283 | duk_fixedbuffer *fb = st->fb; |
| 44284 | |
| 44285 | if (st->heavy) { |
| 44286 | duk_fb_sprintf(fb, "(%p)" , (void *) h); |
| 44287 | } |
| 44288 | |
| 44289 | if (!h) { |
| 44290 | return; |
| 44291 | } |
| 44292 | |
| 44293 | if (st->binary) { |
| 44294 | duk_size_t i; |
| 44295 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET); |
| 44296 | for (i = 0; i < (duk_size_t) sizeof(*h); i++) { |
| 44297 | duk_fb_sprintf(fb, "%02lx" , (unsigned long) ((duk_uint8_t *)h)[i]); |
| 44298 | } |
| 44299 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET); |
| 44300 | } |
| 44301 | |
| 44302 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 44303 | if (st->heavy) { |
| 44304 | duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]" , |
| 44305 | (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h), |
| 44306 | (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h), |
| 44307 | (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h), |
| 44308 | (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0), |
| 44309 | (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0), |
| 44310 | (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0), |
| 44311 | (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0)); |
| 44312 | } |
| 44313 | #else |
| 44314 | if (st->heavy) { |
| 44315 | duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]" , |
| 44316 | (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h), |
| 44317 | (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h), |
| 44318 | (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0), |
| 44319 | (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0), |
| 44320 | (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0), |
| 44321 | (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0)); |
| 44322 | } |
| 44323 | #endif |
| 44324 | } |
| 44325 | |
| 44326 | DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) { |
| 44327 | duk_fixedbuffer *fb = st->fb; |
| 44328 | const duk_uint8_t *p; |
| 44329 | const duk_uint8_t *p_end; |
| 44330 | |
| 44331 | /* terminal type: no depth check */ |
| 44332 | |
| 44333 | if (duk_fb_is_full(fb)) { |
| 44334 | return; |
| 44335 | } |
| 44336 | |
| 44337 | duk__print_shared_heaphdr_string(st, &h->hdr); |
| 44338 | |
| 44339 | if (!h) { |
| 44340 | duk_fb_put_cstring(fb, "NULL" ); |
| 44341 | return; |
| 44342 | } |
| 44343 | |
| 44344 | p = DUK_HSTRING_GET_DATA(h); |
| 44345 | p_end = p + DUK_HSTRING_GET_BYTELEN(h); |
| 44346 | |
| 44347 | if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) { |
| 44348 | /* If property key begins with underscore, encode it with |
| 44349 | * forced quotes (e.g. "_Foo") to distinguish it from encoded |
| 44350 | * internal properties (e.g. \x82Bar -> _Bar). |
| 44351 | */ |
| 44352 | quotes = 1; |
| 44353 | } |
| 44354 | |
| 44355 | if (quotes) { |
| 44356 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE); |
| 44357 | } |
| 44358 | while (p < p_end) { |
| 44359 | duk_uint8_t ch = *p++; |
| 44360 | |
| 44361 | /* two special escapes: '\' and '"', other printables as is */ |
| 44362 | if (ch == '\\') { |
| 44363 | duk_fb_sprintf(fb, "\\\\" ); |
| 44364 | } else if (ch == '"') { |
| 44365 | duk_fb_sprintf(fb, "\\\"" ); |
| 44366 | } else if (ch >= 0x20 && ch <= 0x7e) { |
| 44367 | duk_fb_put_byte(fb, ch); |
| 44368 | } else if (ch == 0x82 && !quotes) { |
| 44369 | /* encode \x82Bar as _Bar if no quotes are |
| 44370 | * applied, this is for readable internal keys. |
| 44371 | */ |
| 44372 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE); |
| 44373 | } else { |
| 44374 | duk_fb_sprintf(fb, "\\x%02lx" , (unsigned long) ch); |
| 44375 | } |
| 44376 | } |
| 44377 | if (quotes) { |
| 44378 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE); |
| 44379 | } |
| 44380 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 44381 | /* XXX: limit to quoted strings only, to save keys from being cluttered? */ |
| 44382 | duk_fb_sprintf(fb, "/%lu" , (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr)); |
| 44383 | #endif |
| 44384 | } |
| 44385 | |
| 44386 | #define DUK__COMMA() do { \ |
| 44387 | if (first) { \ |
| 44388 | first = 0; \ |
| 44389 | } else { \ |
| 44390 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \ |
| 44391 | } \ |
| 44392 | } while (0) |
| 44393 | |
| 44394 | DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) { |
| 44395 | duk_fixedbuffer *fb = st->fb; |
| 44396 | duk_uint_fast32_t i; |
| 44397 | duk_tval *tv; |
| 44398 | duk_hstring *key; |
| 44399 | duk_bool_t first = 1; |
| 44400 | const char *brace1 = "{" ; |
| 44401 | const char *brace2 = "}" ; |
| 44402 | duk_bool_t pushed_loopstack = 0; |
| 44403 | |
| 44404 | if (duk_fb_is_full(fb)) { |
| 44405 | return; |
| 44406 | } |
| 44407 | |
| 44408 | duk__print_shared_heaphdr(st, &h->hdr); |
| 44409 | |
| 44410 | if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) { |
| 44411 | brace1 = "[" ; |
| 44412 | brace2 = "]" ; |
| 44413 | } |
| 44414 | |
| 44415 | if (!h) { |
| 44416 | duk_fb_put_cstring(fb, "NULL" ); |
| 44417 | goto finished; |
| 44418 | } |
| 44419 | |
| 44420 | if (st->depth >= st->depth_limit) { |
| 44421 | const char *subtype = "generic" ; |
| 44422 | |
| 44423 | if (DUK_HOBJECT_IS_COMPFUNC(h)) { |
| 44424 | subtype = "compfunc" ; |
| 44425 | } else if (DUK_HOBJECT_IS_NATFUNC(h)) { |
| 44426 | subtype = "natfunc" ; |
| 44427 | } else if (DUK_HOBJECT_IS_THREAD(h)) { |
| 44428 | subtype = "thread" ; |
| 44429 | } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 44430 | subtype = "bufobj" ; |
| 44431 | } else if (DUK_HOBJECT_IS_ARRAY(h)) { |
| 44432 | subtype = "array" ; |
| 44433 | } |
| 44434 | duk_fb_sprintf(fb, "%sobject/%s %p%s" , (const char *) brace1, subtype, (void *) h, (const char *) brace2); |
| 44435 | return; |
| 44436 | } |
| 44437 | |
| 44438 | for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) { |
| 44439 | if (st->loop_stack[i] == h) { |
| 44440 | duk_fb_sprintf(fb, "%sLOOP:%p%s" , (const char *) brace1, (void *) h, (const char *) brace2); |
| 44441 | return; |
| 44442 | } |
| 44443 | } |
| 44444 | |
| 44445 | /* after this, return paths should 'goto finished' for decrement */ |
| 44446 | st->depth++; |
| 44447 | |
| 44448 | if (st->loop_stack_index >= st->loop_stack_limit) { |
| 44449 | duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s" , (const char *) brace1, (const char *) brace2); |
| 44450 | goto finished; |
| 44451 | } |
| 44452 | st->loop_stack[st->loop_stack_index++] = h; |
| 44453 | pushed_loopstack = 1; |
| 44454 | |
| 44455 | /* |
| 44456 | * Notation: double underscore used for internal properties which are not |
| 44457 | * stored in the property allocation (e.g. '__valstack'). |
| 44458 | */ |
| 44459 | |
| 44460 | duk_fb_put_cstring(fb, brace1); |
| 44461 | |
| 44462 | if (DUK_HOBJECT_GET_PROPS(NULL, h)) { |
| 44463 | duk_uint32_t a_limit; |
| 44464 | |
| 44465 | a_limit = DUK_HOBJECT_GET_ASIZE(h); |
| 44466 | if (st->internal) { |
| 44467 | /* dump all allocated entries, unused entries print as 'unused', |
| 44468 | * note that these may extend beyond current 'length' and look |
| 44469 | * a bit funny. |
| 44470 | */ |
| 44471 | } else { |
| 44472 | /* leave out trailing 'unused' elements */ |
| 44473 | while (a_limit > 0) { |
| 44474 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1); |
| 44475 | if (!DUK_TVAL_IS_UNUSED(tv)) { |
| 44476 | break; |
| 44477 | } |
| 44478 | a_limit--; |
| 44479 | } |
| 44480 | } |
| 44481 | |
| 44482 | for (i = 0; i < a_limit; i++) { |
| 44483 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i); |
| 44484 | DUK__COMMA(); |
| 44485 | duk__print_tval(st, tv); |
| 44486 | } |
| 44487 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) { |
| 44488 | key = DUK_HOBJECT_E_GET_KEY(NULL, h, i); |
| 44489 | if (!key) { |
| 44490 | continue; |
| 44491 | } |
| 44492 | if (!st->internal && DUK_HSTRING_HAS_HIDDEN(key)) { |
| 44493 | continue; |
| 44494 | } |
| 44495 | DUK__COMMA(); |
| 44496 | duk__print_hstring(st, key, 0); |
| 44497 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON); |
| 44498 | if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) { |
| 44499 | duk_fb_sprintf(fb, "[get:%p,set:%p]" , |
| 44500 | (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get, |
| 44501 | (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set); |
| 44502 | } else { |
| 44503 | tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v; |
| 44504 | duk__print_tval(st, tv); |
| 44505 | } |
| 44506 | if (st->heavy) { |
| 44507 | duk_fb_sprintf(fb, "<%02lx>" , (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i)); |
| 44508 | } |
| 44509 | } |
| 44510 | } |
| 44511 | if (st->internal) { |
| 44512 | if (DUK_HOBJECT_IS_ARRAY(h)) { |
| 44513 | DUK__COMMA(); duk_fb_sprintf(fb, "__array:true" ); |
| 44514 | } |
| 44515 | if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) { |
| 44516 | DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true" ); |
| 44517 | } |
| 44518 | if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) { |
| 44519 | DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true" ); |
| 44520 | } |
| 44521 | if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) { |
| 44522 | DUK__COMMA(); duk_fb_sprintf(fb, "__boundfunc:true" ); |
| 44523 | } |
| 44524 | if (DUK_HOBJECT_HAS_COMPFUNC(h)) { |
| 44525 | DUK__COMMA(); duk_fb_sprintf(fb, "__compfunc:true" ); |
| 44526 | } |
| 44527 | if (DUK_HOBJECT_HAS_NATFUNC(h)) { |
| 44528 | DUK__COMMA(); duk_fb_sprintf(fb, "__natfunc:true" ); |
| 44529 | } |
| 44530 | if (DUK_HOBJECT_HAS_BUFOBJ(h)) { |
| 44531 | DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true" ); |
| 44532 | } |
| 44533 | if (DUK_HOBJECT_IS_THREAD(h)) { |
| 44534 | DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true" ); |
| 44535 | } |
| 44536 | if (DUK_HOBJECT_HAS_ARRAY_PART(h)) { |
| 44537 | DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true" ); |
| 44538 | } |
| 44539 | if (DUK_HOBJECT_HAS_STRICT(h)) { |
| 44540 | DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true" ); |
| 44541 | } |
| 44542 | if (DUK_HOBJECT_HAS_NOTAIL(h)) { |
| 44543 | DUK__COMMA(); duk_fb_sprintf(fb, "__notail:true" ); |
| 44544 | } |
| 44545 | if (DUK_HOBJECT_HAS_NEWENV(h)) { |
| 44546 | DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true" ); |
| 44547 | } |
| 44548 | if (DUK_HOBJECT_HAS_NAMEBINDING(h)) { |
| 44549 | DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true" ); |
| 44550 | } |
| 44551 | if (DUK_HOBJECT_HAS_CREATEARGS(h)) { |
| 44552 | DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true" ); |
| 44553 | } |
| 44554 | if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) { |
| 44555 | DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true" ); |
| 44556 | } |
| 44557 | if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) { |
| 44558 | DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true" ); |
| 44559 | } |
| 44560 | if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) { |
| 44561 | DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true" ); |
| 44562 | } |
| 44563 | if (DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 44564 | DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true" ); |
| 44565 | } |
| 44566 | if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) { |
| 44567 | DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true" ); |
| 44568 | } |
| 44569 | } |
| 44570 | |
| 44571 | if (st->internal && DUK_HOBJECT_IS_ARRAY(h)) { |
| 44572 | duk_harray *a = (duk_harray *) h; |
| 44573 | DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld" , (long) a->length); |
| 44574 | DUK__COMMA(); duk_fb_sprintf(fb, "__length_nonwritable:%ld" , (long) a->length_nonwritable); |
| 44575 | } else if (st->internal && DUK_HOBJECT_IS_COMPFUNC(h)) { |
| 44576 | duk_hcompfunc *f = (duk_hcompfunc *) h; |
| 44577 | DUK__COMMA(); duk_fb_put_cstring(fb, "__data:" ); |
| 44578 | duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f)); |
| 44579 | DUK__COMMA(); duk_fb_put_cstring(fb, "__lexenv:" ); duk__print_hobject(st, DUK_HCOMPFUNC_GET_LEXENV(NULL, f)); |
| 44580 | DUK__COMMA(); duk_fb_put_cstring(fb, "__varenv:" ); duk__print_hobject(st, DUK_HCOMPFUNC_GET_VARENV(NULL, f)); |
| 44581 | DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld" , (long) f->nregs); |
| 44582 | DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld" , (long) f->nargs); |
| 44583 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 44584 | DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld" , (long) f->start_line); |
| 44585 | DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld" , (long) f->end_line); |
| 44586 | #endif |
| 44587 | DUK__COMMA(); duk_fb_put_cstring(fb, "__data:" ); |
| 44588 | duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f)); |
| 44589 | } else if (st->internal && DUK_HOBJECT_IS_NATFUNC(h)) { |
| 44590 | duk_hnatfunc *f = (duk_hnatfunc *) h; |
| 44591 | DUK__COMMA(); duk_fb_sprintf(fb, "__func:" ); |
| 44592 | duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func)); |
| 44593 | DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld" , (long) f->nargs); |
| 44594 | DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld" , (long) f->magic); |
| 44595 | } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) { |
| 44596 | duk_hdecenv *e = (duk_hdecenv *) h; |
| 44597 | DUK__COMMA(); duk_fb_sprintf(fb, "__thread:" ); duk__print_hobject(st, (duk_hobject *) e->thread); |
| 44598 | DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:" ); duk__print_hobject(st, (duk_hobject *) e->varmap); |
| 44599 | DUK__COMMA(); duk_fb_sprintf(fb, "__regbase_byteoff:%ld" , (long) e->regbase_byteoff); |
| 44600 | } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) { |
| 44601 | duk_hobjenv *e = (duk_hobjenv *) h; |
| 44602 | DUK__COMMA(); duk_fb_sprintf(fb, "__target:" ); duk__print_hobject(st, (duk_hobject *) e->target); |
| 44603 | DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld" , (long) e->has_this); |
| 44604 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 44605 | } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 44606 | duk_hbufobj *b = (duk_hbufobj *) h; |
| 44607 | DUK__COMMA(); duk_fb_sprintf(fb, "__buf:" ); |
| 44608 | duk__print_hbuffer(st, (duk_hbuffer *) b->buf); |
| 44609 | DUK__COMMA(); duk_fb_sprintf(fb, "__buf_prop:" ); |
| 44610 | duk__print_hobject(st, (duk_hobject *) b->buf_prop); |
| 44611 | DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld" , (long) b->offset); |
| 44612 | DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld" , (long) b->length); |
| 44613 | DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld" , (long) b->shift); |
| 44614 | DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld" , (long) b->elem_type); |
| 44615 | #endif |
| 44616 | } else if (st->internal && DUK_HOBJECT_IS_PROXY(h)) { |
| 44617 | duk_hproxy *p = (duk_hproxy *) h; |
| 44618 | DUK__COMMA(); duk_fb_sprintf(fb, "__target:" ); |
| 44619 | duk__print_hobject(st, p->target); |
| 44620 | DUK__COMMA(); duk_fb_sprintf(fb, "__handler:" ); |
| 44621 | duk__print_hobject(st, p->handler); |
| 44622 | } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) { |
| 44623 | duk_hthread *t = (duk_hthread *) h; |
| 44624 | DUK__COMMA(); duk_fb_sprintf(fb, "__ptr_curr_pc:%p" , (void *) t->ptr_curr_pc); |
| 44625 | DUK__COMMA(); duk_fb_sprintf(fb, "__heap:%p" , (void *) t->heap); |
| 44626 | DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld" , (long) t->strict); |
| 44627 | DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld" , (long) t->state); |
| 44628 | DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld" , (long) t->unused1); |
| 44629 | DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld" , (long) t->unused2); |
| 44630 | DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p" , (void *) t->valstack); |
| 44631 | DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld" , (void *) t->valstack_end, (long) (t->valstack_end - t->valstack)); |
| 44632 | DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_alloc_end:%p/%ld" , (void *) t->valstack_alloc_end, (long) (t->valstack_alloc_end - t->valstack)); |
| 44633 | DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld" , (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack)); |
| 44634 | DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld" , (void *) t->valstack_top, (long) (t->valstack_top - t->valstack)); |
| 44635 | DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_curr:%p" , (void *) t->callstack_curr); |
| 44636 | DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_top:%ld" , (long) t->callstack_top); |
| 44637 | DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_preventcount:%ld" , (long) t->callstack_preventcount); |
| 44638 | DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:" ); duk__print_hobject(st, (duk_hobject *) t->resumer); |
| 44639 | DUK__COMMA(); duk_fb_sprintf(fb, "__compile_ctx:%p" , (void *) t->compile_ctx); |
| 44640 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 44641 | DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_counter:%ld" , (long) t->interrupt_counter); |
| 44642 | DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_init:%ld" , (long) t->interrupt_init); |
| 44643 | #endif |
| 44644 | |
| 44645 | /* XXX: print built-ins array? */ |
| 44646 | |
| 44647 | } |
| 44648 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 44649 | if (st->internal) { |
| 44650 | DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu" , (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h)); |
| 44651 | } |
| 44652 | #endif |
| 44653 | if (st->internal) { |
| 44654 | DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld" , (long) DUK_HOBJECT_GET_CLASS_NUMBER(h)); |
| 44655 | } |
| 44656 | |
| 44657 | DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p" , (void *) h); /* own pointer */ |
| 44658 | |
| 44659 | /* prototype should be last, for readability */ |
| 44660 | if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) { |
| 44661 | if (st->follow_proto) { |
| 44662 | DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:" ); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h)); |
| 44663 | } else { |
| 44664 | DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p" , (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h)); |
| 44665 | } |
| 44666 | } |
| 44667 | |
| 44668 | duk_fb_put_cstring(fb, brace2); |
| 44669 | |
| 44670 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 44671 | if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) { |
| 44672 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE); |
| 44673 | for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) { |
| 44674 | duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i); |
| 44675 | if (i > 0) { |
| 44676 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); |
| 44677 | } |
| 44678 | if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) { |
| 44679 | duk_fb_sprintf(fb, "u" ); |
| 44680 | } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) { |
| 44681 | duk_fb_sprintf(fb, "d" ); |
| 44682 | } else { |
| 44683 | duk_fb_sprintf(fb, "%ld" , (long) h_idx); |
| 44684 | } |
| 44685 | } |
| 44686 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE); |
| 44687 | } |
| 44688 | #endif |
| 44689 | |
| 44690 | finished: |
| 44691 | st->depth--; |
| 44692 | if (pushed_loopstack) { |
| 44693 | st->loop_stack_index--; |
| 44694 | st->loop_stack[st->loop_stack_index] = NULL; |
| 44695 | } |
| 44696 | } |
| 44697 | |
| 44698 | DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) { |
| 44699 | duk_fixedbuffer *fb = st->fb; |
| 44700 | duk_size_t i, n; |
| 44701 | duk_uint8_t *p; |
| 44702 | |
| 44703 | if (duk_fb_is_full(fb)) { |
| 44704 | return; |
| 44705 | } |
| 44706 | |
| 44707 | /* terminal type: no depth check */ |
| 44708 | |
| 44709 | if (!h) { |
| 44710 | duk_fb_put_cstring(fb, "NULL" ); |
| 44711 | return; |
| 44712 | } |
| 44713 | |
| 44714 | if (DUK_HBUFFER_HAS_DYNAMIC(h)) { |
| 44715 | if (DUK_HBUFFER_HAS_EXTERNAL(h)) { |
| 44716 | duk_hbuffer_external *g = (duk_hbuffer_external *) h; |
| 44717 | duk_fb_sprintf(fb, "buffer:external:%p:%ld" , |
| 44718 | (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g), |
| 44719 | (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g)); |
| 44720 | } else { |
| 44721 | duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h; |
| 44722 | duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld" , |
| 44723 | (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g), |
| 44724 | (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g)); |
| 44725 | } |
| 44726 | } else { |
| 44727 | duk_fb_sprintf(fb, "buffer:fixed:%ld" , (long) DUK_HBUFFER_GET_SIZE(h)); |
| 44728 | } |
| 44729 | |
| 44730 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 44731 | duk_fb_sprintf(fb, "/%lu" , (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr)); |
| 44732 | #endif |
| 44733 | |
| 44734 | if (st->hexdump) { |
| 44735 | duk_fb_sprintf(fb, "=[" ); |
| 44736 | n = DUK_HBUFFER_GET_SIZE(h); |
| 44737 | p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h); |
| 44738 | for (i = 0; i < n; i++) { |
| 44739 | duk_fb_sprintf(fb, "%02lx" , (unsigned long) p[i]); |
| 44740 | } |
| 44741 | duk_fb_sprintf(fb, "]" ); |
| 44742 | } |
| 44743 | } |
| 44744 | |
| 44745 | DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) { |
| 44746 | duk_fixedbuffer *fb = st->fb; |
| 44747 | |
| 44748 | if (duk_fb_is_full(fb)) { |
| 44749 | return; |
| 44750 | } |
| 44751 | |
| 44752 | if (!h) { |
| 44753 | duk_fb_put_cstring(fb, "NULL" ); |
| 44754 | return; |
| 44755 | } |
| 44756 | |
| 44757 | switch (DUK_HEAPHDR_GET_TYPE(h)) { |
| 44758 | case DUK_HTYPE_STRING: |
| 44759 | duk__print_hstring(st, (duk_hstring *) h, 1); |
| 44760 | break; |
| 44761 | case DUK_HTYPE_OBJECT: |
| 44762 | duk__print_hobject(st, (duk_hobject *) h); |
| 44763 | break; |
| 44764 | case DUK_HTYPE_BUFFER: |
| 44765 | duk__print_hbuffer(st, (duk_hbuffer *) h); |
| 44766 | break; |
| 44767 | default: |
| 44768 | duk_fb_sprintf(fb, "[unknown htype %ld]" , (long) DUK_HEAPHDR_GET_TYPE(h)); |
| 44769 | break; |
| 44770 | } |
| 44771 | } |
| 44772 | |
| 44773 | DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) { |
| 44774 | duk_fixedbuffer *fb = st->fb; |
| 44775 | |
| 44776 | if (duk_fb_is_full(fb)) { |
| 44777 | return; |
| 44778 | } |
| 44779 | |
| 44780 | /* depth check is done when printing an actual type */ |
| 44781 | |
| 44782 | if (st->heavy) { |
| 44783 | duk_fb_sprintf(fb, "(%p)" , (void *) tv); |
| 44784 | } |
| 44785 | |
| 44786 | if (!tv) { |
| 44787 | duk_fb_put_cstring(fb, "NULL" ); |
| 44788 | return; |
| 44789 | } |
| 44790 | |
| 44791 | if (st->binary) { |
| 44792 | duk_size_t i; |
| 44793 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET); |
| 44794 | for (i = 0; i < (duk_size_t) sizeof(*tv); i++) { |
| 44795 | duk_fb_sprintf(fb, "%02lx" , (unsigned long) ((duk_uint8_t *)tv)[i]); |
| 44796 | } |
| 44797 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET); |
| 44798 | } |
| 44799 | |
| 44800 | if (st->heavy) { |
| 44801 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE); |
| 44802 | } |
| 44803 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 44804 | case DUK_TAG_UNDEFINED: { |
| 44805 | duk_fb_put_cstring(fb, "undefined" ); |
| 44806 | break; |
| 44807 | } |
| 44808 | case DUK_TAG_UNUSED: { |
| 44809 | duk_fb_put_cstring(fb, "unused" ); |
| 44810 | break; |
| 44811 | } |
| 44812 | case DUK_TAG_NULL: { |
| 44813 | duk_fb_put_cstring(fb, "null" ); |
| 44814 | break; |
| 44815 | } |
| 44816 | case DUK_TAG_BOOLEAN: { |
| 44817 | duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false" ); |
| 44818 | break; |
| 44819 | } |
| 44820 | case DUK_TAG_STRING: { |
| 44821 | /* Note: string is a terminal heap object, so no depth check here */ |
| 44822 | duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1); |
| 44823 | break; |
| 44824 | } |
| 44825 | case DUK_TAG_OBJECT: { |
| 44826 | duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv)); |
| 44827 | break; |
| 44828 | } |
| 44829 | case DUK_TAG_BUFFER: { |
| 44830 | duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv)); |
| 44831 | break; |
| 44832 | } |
| 44833 | case DUK_TAG_POINTER: { |
| 44834 | duk_fb_sprintf(fb, "pointer:%p" , (void *) DUK_TVAL_GET_POINTER(tv)); |
| 44835 | break; |
| 44836 | } |
| 44837 | case DUK_TAG_LIGHTFUNC: { |
| 44838 | duk_c_function func; |
| 44839 | duk_small_uint_t lf_flags; |
| 44840 | |
| 44841 | DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); |
| 44842 | duk_fb_sprintf(fb, "lightfunc:" ); |
| 44843 | duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func)); |
| 44844 | duk_fb_sprintf(fb, ":%04lx" , (long) lf_flags); |
| 44845 | break; |
| 44846 | } |
| 44847 | #if defined(DUK_USE_FASTINT) |
| 44848 | case DUK_TAG_FASTINT: |
| 44849 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 44850 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 44851 | duk_fb_sprintf(fb, "%.18g_F" , (double) DUK_TVAL_GET_NUMBER(tv)); |
| 44852 | break; |
| 44853 | #endif |
| 44854 | default: { |
| 44855 | /* IEEE double is approximately 16 decimal digits; print a couple extra */ |
| 44856 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 44857 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 44858 | duk_fb_sprintf(fb, "%.18g" , (double) DUK_TVAL_GET_NUMBER(tv)); |
| 44859 | break; |
| 44860 | } |
| 44861 | } |
| 44862 | if (st->heavy) { |
| 44863 | duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE); |
| 44864 | } |
| 44865 | } |
| 44866 | |
| 44867 | DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) { |
| 44868 | duk_fixedbuffer *fb = st->fb; |
| 44869 | duk_small_int_t op; |
| 44870 | const char *op_name; |
| 44871 | |
| 44872 | op = (duk_small_int_t) DUK_DEC_OP(ins); |
| 44873 | op_name = duk__bc_optab[op]; |
| 44874 | |
| 44875 | /* XXX: option to fix opcode length so it lines up nicely */ |
| 44876 | |
| 44877 | if (op == DUK_OP_JUMP) { |
| 44878 | duk_int_t diff1 = (duk_int_t) (DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS); /* from next pc */ |
| 44879 | duk_int_t diff2 = diff1 + 1; /* from curr pc */ |
| 44880 | |
| 44881 | duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)" , |
| 44882 | (const char *) op_name, (long) diff1, |
| 44883 | (int) (diff2 >= 0 ? '+' : '-'), /* char format: use int */ |
| 44884 | (long) (diff2 >= 0 ? diff2 : -diff2)); |
| 44885 | } else { |
| 44886 | duk_fb_sprintf(fb, "%s %ld, %ld, %ld" , |
| 44887 | (const char *) op_name, (long) DUK_DEC_A(ins), |
| 44888 | (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins)); |
| 44889 | } |
| 44890 | } |
| 44891 | |
| 44892 | DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) { |
| 44893 | duk_fixedbuffer *fb = st->fb; |
| 44894 | |
| 44895 | if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) { |
| 44896 | duk_fb_sprintf(fb, "?(%ld)" , (long) opcode); |
| 44897 | } else { |
| 44898 | duk_fb_sprintf(fb, "%s" , (const char *) duk__bc_optab[opcode]); |
| 44899 | } |
| 44900 | } |
| 44901 | |
| 44902 | DUK_LOCAL void duk__print_catcher(duk__dprint_state *st, duk_catcher *cat) { |
| 44903 | duk_fixedbuffer *fb = st->fb; |
| 44904 | |
| 44905 | if (duk_fb_is_full(fb)) { |
| 44906 | return; |
| 44907 | } |
| 44908 | |
| 44909 | if (!cat) { |
| 44910 | duk_fb_put_cstring(fb, "NULL" ); |
| 44911 | return; |
| 44912 | } |
| 44913 | |
| 44914 | duk_fb_sprintf(fb, "[catcher ptr=%p parent=%p varname=%p pc_base=%p, idx_base=%ld, flags=0x%08lx]" , |
| 44915 | (void *) cat, |
| 44916 | (void *) cat->parent, (void *) cat->h_varname, (void *) cat->pc_base, |
| 44917 | (long) cat->idx_base, (unsigned long) cat->flags); |
| 44918 | } |
| 44919 | |
| 44920 | |
| 44921 | DUK_LOCAL void duk__print_activation(duk__dprint_state *st, duk_activation *act) { |
| 44922 | duk_fixedbuffer *fb = st->fb; |
| 44923 | |
| 44924 | if (duk_fb_is_full(fb)) { |
| 44925 | return; |
| 44926 | } |
| 44927 | |
| 44928 | if (!act) { |
| 44929 | duk_fb_put_cstring(fb, "NULL" ); |
| 44930 | return; |
| 44931 | } |
| 44932 | |
| 44933 | /* prev_caller: conditional, omitted on purpose, it's rarely used. */ |
| 44934 | /* prev_line: conditional, omitted on purpose (but would be nice). */ |
| 44935 | duk_fb_sprintf(fb, "[activation ptr=%p tv_func=<omit> func=%p parent=%p var_env=%p lex_env=%p cat=%p curr_pc=%p bottom_byteoff=%ld retval_byteoff=%ld reserve_byteoff=%ld flags=%ld]" , |
| 44936 | (void *) act, |
| 44937 | (void *) act->func, (void *) act->parent, (void *) act->var_env, |
| 44938 | (void *) act->lex_env, (void *) act->cat, (void *) act->curr_pc, |
| 44939 | (long) act->bottom_byteoff, (long) act->retval_byteoff, (long) act->reserve_byteoff, |
| 44940 | (long) act->flags); |
| 44941 | } |
| 44942 | |
| 44943 | DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) { |
| 44944 | duk_fixedbuffer fb; |
| 44945 | const char *p = format; |
| 44946 | const char *p_end = p + DUK_STRLEN(format); |
| 44947 | duk_int_t retval; |
| 44948 | |
| 44949 | duk_memzero(&fb, sizeof(fb)); |
| 44950 | fb.buffer = (duk_uint8_t *) str; |
| 44951 | fb.length = size; |
| 44952 | fb.offset = 0; |
| 44953 | fb.truncated = 0; |
| 44954 | |
| 44955 | while (p < p_end) { |
| 44956 | char ch = *p++; |
| 44957 | const char *p_begfmt = NULL; |
| 44958 | duk_bool_t got_exclamation = 0; |
| 44959 | duk_bool_t got_long = 0; /* %lf, %ld etc */ |
| 44960 | duk__dprint_state st; |
| 44961 | |
| 44962 | if (ch != DUK_ASC_PERCENT) { |
| 44963 | duk_fb_put_byte(&fb, (duk_uint8_t) ch); |
| 44964 | continue; |
| 44965 | } |
| 44966 | |
| 44967 | /* |
| 44968 | * Format tag parsing. Since we don't understand all the |
| 44969 | * possible format tags allowed, we just scan for a terminating |
| 44970 | * specifier and keep track of relevant modifiers that we do |
| 44971 | * understand. See man 3 printf. |
| 44972 | */ |
| 44973 | |
| 44974 | duk_memzero(&st, sizeof(st)); |
| 44975 | st.fb = &fb; |
| 44976 | st.depth = 0; |
| 44977 | st.depth_limit = 1; |
| 44978 | st.loop_stack_index = 0; |
| 44979 | st.loop_stack_limit = DUK__LOOP_STACK_DEPTH; |
| 44980 | |
| 44981 | p_begfmt = p - 1; |
| 44982 | while (p < p_end) { |
| 44983 | ch = *p++; |
| 44984 | |
| 44985 | if (ch == DUK_ASC_STAR) { |
| 44986 | /* unsupported: would consume multiple args */ |
| 44987 | goto format_error; |
| 44988 | } else if (ch == DUK_ASC_PERCENT) { |
| 44989 | duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT); |
| 44990 | break; |
| 44991 | } else if (ch == DUK_ASC_EXCLAMATION) { |
| 44992 | got_exclamation = 1; |
| 44993 | } else if (!got_exclamation && ch == DUK_ASC_LC_L) { |
| 44994 | got_long = 1; |
| 44995 | } else if (got_exclamation && ch == DUK_ASC_LC_D) { |
| 44996 | st.depth_limit = DUK__DEEP_DEPTH_LIMIT; |
| 44997 | } else if (got_exclamation && ch == DUK_ASC_LC_P) { |
| 44998 | st.follow_proto = 1; |
| 44999 | } else if (got_exclamation && ch == DUK_ASC_LC_I) { |
| 45000 | st.internal = 1; |
| 45001 | } else if (got_exclamation && ch == DUK_ASC_LC_X) { |
| 45002 | st.hexdump = 1; |
| 45003 | } else if (got_exclamation && ch == DUK_ASC_LC_H) { |
| 45004 | st.heavy = 1; |
| 45005 | } else if (got_exclamation && ch == DUK_ASC_ATSIGN) { |
| 45006 | st.pointer = 1; |
| 45007 | } else if (got_exclamation && ch == DUK_ASC_HASH) { |
| 45008 | st.binary = 1; |
| 45009 | } else if (got_exclamation && ch == DUK_ASC_UC_T) { |
| 45010 | duk_tval *t = va_arg(ap, duk_tval *); |
| 45011 | if (st.pointer && !st.heavy) { |
| 45012 | duk_fb_sprintf(&fb, "(%p)" , (void *) t); |
| 45013 | } |
| 45014 | duk__print_tval(&st, t); |
| 45015 | break; |
| 45016 | } else if (got_exclamation && ch == DUK_ASC_UC_O) { |
| 45017 | duk_heaphdr *t = va_arg(ap, duk_heaphdr *); |
| 45018 | if (st.pointer && !st.heavy) { |
| 45019 | duk_fb_sprintf(&fb, "(%p)" , (void *) t); |
| 45020 | } |
| 45021 | duk__print_heaphdr(&st, t); |
| 45022 | break; |
| 45023 | } else if (got_exclamation && ch == DUK_ASC_UC_I) { |
| 45024 | duk_instr_t t = va_arg(ap, duk_instr_t); |
| 45025 | duk__print_instr(&st, t); |
| 45026 | break; |
| 45027 | } else if (got_exclamation && ch == DUK_ASC_UC_X) { |
| 45028 | long t = va_arg(ap, long); |
| 45029 | duk__print_opcode(&st, (duk_small_int_t) t); |
| 45030 | break; |
| 45031 | } else if (got_exclamation && ch == DUK_ASC_UC_C) { |
| 45032 | duk_catcher *t = va_arg(ap, duk_catcher *); |
| 45033 | duk__print_catcher(&st, t); |
| 45034 | break; |
| 45035 | } else if (got_exclamation && ch == DUK_ASC_UC_A) { |
| 45036 | duk_activation *t = va_arg(ap, duk_activation *); |
| 45037 | duk__print_activation(&st, t); |
| 45038 | break; |
| 45039 | } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) { |
| 45040 | char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH]; |
| 45041 | duk_size_t fmtlen; |
| 45042 | |
| 45043 | DUK_ASSERT(p >= p_begfmt); |
| 45044 | fmtlen = (duk_size_t) (p - p_begfmt); |
| 45045 | if (fmtlen >= sizeof(fmtbuf)) { |
| 45046 | /* format is too large, abort */ |
| 45047 | goto format_error; |
| 45048 | } |
| 45049 | duk_memzero(fmtbuf, sizeof(fmtbuf)); |
| 45050 | duk_memcpy(fmtbuf, p_begfmt, fmtlen); |
| 45051 | |
| 45052 | /* assume exactly 1 arg, which is why '*' is forbidden; arg size still |
| 45053 | * depends on type though. |
| 45054 | */ |
| 45055 | |
| 45056 | if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) { |
| 45057 | /* %f and %lf both consume a 'long' */ |
| 45058 | double arg = va_arg(ap, double); |
| 45059 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45060 | } else if (ch == DUK_ASC_LC_D && got_long) { |
| 45061 | /* %ld */ |
| 45062 | long arg = va_arg(ap, long); |
| 45063 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45064 | } else if (ch == DUK_ASC_LC_D) { |
| 45065 | /* %d; only 16 bits are guaranteed */ |
| 45066 | int arg = va_arg(ap, int); |
| 45067 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45068 | } else if (ch == DUK_ASC_LC_U && got_long) { |
| 45069 | /* %lu */ |
| 45070 | unsigned long arg = va_arg(ap, unsigned long); |
| 45071 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45072 | } else if (ch == DUK_ASC_LC_U) { |
| 45073 | /* %u; only 16 bits are guaranteed */ |
| 45074 | unsigned int arg = va_arg(ap, unsigned int); |
| 45075 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45076 | } else if (ch == DUK_ASC_LC_X && got_long) { |
| 45077 | /* %lx */ |
| 45078 | unsigned long arg = va_arg(ap, unsigned long); |
| 45079 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45080 | } else if (ch == DUK_ASC_LC_X) { |
| 45081 | /* %x; only 16 bits are guaranteed */ |
| 45082 | unsigned int arg = va_arg(ap, unsigned int); |
| 45083 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45084 | } else if (ch == DUK_ASC_LC_S) { |
| 45085 | /* %s */ |
| 45086 | const char *arg = va_arg(ap, const char *); |
| 45087 | if (arg == NULL) { |
| 45088 | /* '%s' and NULL is not portable, so special case |
| 45089 | * it for debug printing. |
| 45090 | */ |
| 45091 | duk_fb_sprintf(&fb, "NULL" ); |
| 45092 | } else { |
| 45093 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45094 | } |
| 45095 | } else if (ch == DUK_ASC_LC_P) { |
| 45096 | /* %p */ |
| 45097 | void *arg = va_arg(ap, void *); |
| 45098 | if (arg == NULL) { |
| 45099 | /* '%p' and NULL is portable, but special case it |
| 45100 | * anyway to get a standard NULL marker in logs. |
| 45101 | */ |
| 45102 | duk_fb_sprintf(&fb, "NULL" ); |
| 45103 | } else { |
| 45104 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45105 | } |
| 45106 | } else if (ch == DUK_ASC_LC_C) { |
| 45107 | /* '%c', passed concretely as int */ |
| 45108 | int arg = va_arg(ap, int); |
| 45109 | duk_fb_sprintf(&fb, fmtbuf, arg); |
| 45110 | } else { |
| 45111 | /* Should not happen. */ |
| 45112 | duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)" , (const char *) fmtbuf); |
| 45113 | } |
| 45114 | break; |
| 45115 | } else { |
| 45116 | /* ignore */ |
| 45117 | } |
| 45118 | } |
| 45119 | } |
| 45120 | goto done; |
| 45121 | |
| 45122 | format_error: |
| 45123 | duk_fb_put_cstring(&fb, "FMTERR" ); |
| 45124 | /* fall through */ |
| 45125 | |
| 45126 | done: |
| 45127 | retval = (duk_int_t) fb.offset; |
| 45128 | duk_fb_put_byte(&fb, (duk_uint8_t) 0); |
| 45129 | |
| 45130 | /* return total chars written excluding terminator */ |
| 45131 | return retval; |
| 45132 | } |
| 45133 | |
| 45134 | #if 0 /*unused*/ |
| 45135 | DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) { |
| 45136 | duk_int_t retval; |
| 45137 | va_list ap; |
| 45138 | va_start(ap, format); |
| 45139 | retval = duk_debug_vsnprintf(str, size, format, ap); |
| 45140 | va_end(ap); |
| 45141 | return retval; |
| 45142 | } |
| 45143 | #endif |
| 45144 | |
| 45145 | /* Formatting function pointers is tricky: there is no standard pointer for |
| 45146 | * function pointers and the size of a function pointer may depend on the |
| 45147 | * specific pointer type. This helper formats a function pointer based on |
| 45148 | * its memory layout to get something useful on most platforms. |
| 45149 | */ |
| 45150 | DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) { |
| 45151 | duk_size_t i; |
| 45152 | duk_uint8_t *p = (duk_uint8_t *) buf; |
| 45153 | duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1); |
| 45154 | |
| 45155 | DUK_ASSERT(buf != NULL); |
| 45156 | duk_memzero(buf, buf_size); |
| 45157 | |
| 45158 | for (i = 0; i < fptr_size; i++) { |
| 45159 | duk_int_t left = (duk_int_t) (p_end - p); |
| 45160 | duk_uint8_t ch; |
| 45161 | if (left <= 0) { |
| 45162 | break; |
| 45163 | } |
| 45164 | |
| 45165 | /* Quite approximate but should be useful for little and big endian. */ |
| 45166 | #if defined(DUK_USE_INTEGER_BE) |
| 45167 | ch = fptr[i]; |
| 45168 | #else |
| 45169 | ch = fptr[fptr_size - 1 - i]; |
| 45170 | #endif |
| 45171 | p += DUK_SNPRINTF((char *) p, (duk_size_t) left, "%02lx" , (unsigned long) ch); |
| 45172 | } |
| 45173 | } |
| 45174 | |
| 45175 | #endif /* DUK_USE_DEBUG */ |
| 45176 | |
| 45177 | /* automatic undefs */ |
| 45178 | #undef DUK__ALLOWED_STANDARD_SPECIFIERS |
| 45179 | #undef DUK__COMMA |
| 45180 | #undef DUK__DEEP_DEPTH_LIMIT |
| 45181 | #undef DUK__LOOP_STACK_DEPTH |
| 45182 | #undef DUK__MAX_FORMAT_TAG_LENGTH |
| 45183 | #line 1 "duk_debugger.c" |
| 45184 | /* |
| 45185 | * Duktape debugger |
| 45186 | */ |
| 45187 | |
| 45188 | /* #include duk_internal.h -> already included */ |
| 45189 | |
| 45190 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 45191 | |
| 45192 | /* |
| 45193 | * Assert helpers |
| 45194 | */ |
| 45195 | |
| 45196 | #if defined(DUK_USE_ASSERTIONS) |
| 45197 | #define DUK__DBG_TPORT_ENTER() do { \ |
| 45198 | DUK_ASSERT(heap->dbg_calling_transport == 0); \ |
| 45199 | heap->dbg_calling_transport = 1; \ |
| 45200 | } while (0) |
| 45201 | #define DUK__DBG_TPORT_EXIT() do { \ |
| 45202 | DUK_ASSERT(heap->dbg_calling_transport == 1); \ |
| 45203 | heap->dbg_calling_transport = 0; \ |
| 45204 | } while (0) |
| 45205 | #else |
| 45206 | #define DUK__DBG_TPORT_ENTER() do {} while (0) |
| 45207 | #define DUK__DBG_TPORT_EXIT() do {} while (0) |
| 45208 | #endif |
| 45209 | |
| 45210 | /* |
| 45211 | * Helper structs |
| 45212 | */ |
| 45213 | |
| 45214 | typedef union { |
| 45215 | void *p; |
| 45216 | duk_uint_t b[1]; |
| 45217 | /* Use b[] to access the size of the union, which is strictly not |
| 45218 | * correct. Can't use fixed size unless there's feature detection |
| 45219 | * for pointer byte size. |
| 45220 | */ |
| 45221 | } duk__ptr_union; |
| 45222 | |
| 45223 | /* |
| 45224 | * Detach handling |
| 45225 | */ |
| 45226 | |
| 45227 | #define DUK__SET_CONN_BROKEN(thr,reason) do { \ |
| 45228 | /* For now shared handler is fine. */ \ |
| 45229 | duk__debug_do_detach1((thr)->heap, (reason)); \ |
| 45230 | } while (0) |
| 45231 | |
| 45232 | DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) { |
| 45233 | /* Can be called multiple times with no harm. Mark the transport |
| 45234 | * bad (dbg_read_cb == NULL) and clear state except for the detached |
| 45235 | * callback and the udata field. The detached callback is delayed |
| 45236 | * to the message loop so that it can be called between messages; |
| 45237 | * this avoids corner cases related to immediate debugger reattach |
| 45238 | * inside the detached callback. |
| 45239 | */ |
| 45240 | |
| 45241 | if (heap->dbg_detaching) { |
| 45242 | DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1" )); |
| 45243 | return; |
| 45244 | } |
| 45245 | |
| 45246 | DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken" )); |
| 45247 | |
| 45248 | heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */ |
| 45249 | |
| 45250 | if (heap->dbg_write_cb != NULL) { |
| 45251 | duk_hthread *thr; |
| 45252 | |
| 45253 | thr = heap->heap_thread; |
| 45254 | DUK_ASSERT(thr != NULL); |
| 45255 | |
| 45256 | duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING); |
| 45257 | duk_debug_write_int(thr, reason); |
| 45258 | duk_debug_write_eom(thr); |
| 45259 | } |
| 45260 | |
| 45261 | heap->dbg_read_cb = NULL; |
| 45262 | heap->dbg_write_cb = NULL; |
| 45263 | heap->dbg_peek_cb = NULL; |
| 45264 | heap->dbg_read_flush_cb = NULL; |
| 45265 | heap->dbg_write_flush_cb = NULL; |
| 45266 | heap->dbg_request_cb = NULL; |
| 45267 | /* heap->dbg_detached_cb: keep */ |
| 45268 | /* heap->dbg_udata: keep */ |
| 45269 | /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */ |
| 45270 | heap->dbg_state_dirty = 0; |
| 45271 | heap->dbg_force_restart = 0; |
| 45272 | heap->dbg_pause_flags = 0; |
| 45273 | heap->dbg_pause_act = NULL; |
| 45274 | heap->dbg_pause_startline = 0; |
| 45275 | heap->dbg_have_next_byte = 0; |
| 45276 | duk_debug_clear_paused(heap); /* XXX: some overlap with field inits above */ |
| 45277 | heap->dbg_state_dirty = 0; /* XXX: clear_paused sets dirty; rework? */ |
| 45278 | |
| 45279 | /* Ensure there are no stale active breakpoint pointers. |
| 45280 | * Breakpoint list is currently kept - we could empty it |
| 45281 | * here but we'd need to handle refcounts correctly, and |
| 45282 | * we'd need a 'thr' reference for that. |
| 45283 | * |
| 45284 | * XXX: clear breakpoint on either attach or detach? |
| 45285 | */ |
| 45286 | heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; |
| 45287 | } |
| 45288 | |
| 45289 | DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) { |
| 45290 | duk_debug_detached_function detached_cb; |
| 45291 | void *detached_udata; |
| 45292 | duk_hthread *thr; |
| 45293 | |
| 45294 | thr = heap->heap_thread; |
| 45295 | if (thr == NULL) { |
| 45296 | DUK_ASSERT(heap->dbg_detached_cb == NULL); |
| 45297 | return; |
| 45298 | } |
| 45299 | |
| 45300 | /* Safe to call multiple times. */ |
| 45301 | |
| 45302 | detached_cb = heap->dbg_detached_cb; |
| 45303 | detached_udata = heap->dbg_udata; |
| 45304 | heap->dbg_detached_cb = NULL; |
| 45305 | heap->dbg_udata = NULL; |
| 45306 | |
| 45307 | if (detached_cb) { |
| 45308 | /* Careful here: state must be wiped before the call |
| 45309 | * so that we can cleanly handle a re-attach from |
| 45310 | * inside the callback. |
| 45311 | */ |
| 45312 | DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb" )); |
| 45313 | detached_cb(thr, detached_udata); |
| 45314 | } |
| 45315 | |
| 45316 | heap->dbg_detaching = 0; |
| 45317 | } |
| 45318 | |
| 45319 | DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) { |
| 45320 | duk__debug_do_detach1(heap, 0); |
| 45321 | duk__debug_do_detach2(heap); |
| 45322 | } |
| 45323 | |
| 45324 | /* Called on a read/write error: NULL all callbacks except the detached |
| 45325 | * callback so that we never accidentally call them after a read/write |
| 45326 | * error has been indicated. This is especially important for the transport |
| 45327 | * I/O callbacks to fulfill guaranteed callback semantics. |
| 45328 | */ |
| 45329 | DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) { |
| 45330 | duk_heap *heap; |
| 45331 | |
| 45332 | DUK_ASSERT(thr != NULL); |
| 45333 | |
| 45334 | heap = thr->heap; |
| 45335 | DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached" )); |
| 45336 | heap->dbg_read_cb = NULL; |
| 45337 | heap->dbg_write_cb = NULL; /* this is especially critical to avoid another write call in detach1() */ |
| 45338 | heap->dbg_peek_cb = NULL; |
| 45339 | heap->dbg_read_flush_cb = NULL; |
| 45340 | heap->dbg_write_flush_cb = NULL; |
| 45341 | heap->dbg_request_cb = NULL; |
| 45342 | /* keep heap->dbg_detached_cb */ |
| 45343 | } |
| 45344 | |
| 45345 | /* |
| 45346 | * Pause handling |
| 45347 | */ |
| 45348 | |
| 45349 | DUK_LOCAL void duk__debug_set_pause_state(duk_hthread *thr, duk_heap *heap, duk_small_uint_t pause_flags) { |
| 45350 | duk_uint_fast32_t line; |
| 45351 | |
| 45352 | line = duk_debug_curr_line(thr); |
| 45353 | if (line == 0) { |
| 45354 | /* No line info for current function. */ |
| 45355 | duk_small_uint_t updated_flags; |
| 45356 | |
| 45357 | updated_flags = pause_flags & ~(DUK_PAUSE_FLAG_LINE_CHANGE); |
| 45358 | DUK_D(DUK_DPRINT("no line info for current activation, disable line-based pause flags: 0x%08lx -> 0x%08lx" , |
| 45359 | (long) pause_flags, (long) updated_flags)); |
| 45360 | pause_flags = updated_flags; |
| 45361 | } |
| 45362 | |
| 45363 | heap->dbg_pause_flags = pause_flags; |
| 45364 | heap->dbg_pause_act = thr->callstack_curr; |
| 45365 | heap->dbg_pause_startline = (duk_uint32_t) line; |
| 45366 | heap->dbg_state_dirty = 1; |
| 45367 | |
| 45368 | DUK_D(DUK_DPRINT("set state for automatic pause triggers, flags=0x%08lx, act=%p, startline=%ld" , |
| 45369 | (long) heap->dbg_pause_flags, (void *) heap->dbg_pause_act, |
| 45370 | (long) heap->dbg_pause_startline)); |
| 45371 | } |
| 45372 | |
| 45373 | /* |
| 45374 | * Debug connection peek and flush primitives |
| 45375 | */ |
| 45376 | |
| 45377 | DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) { |
| 45378 | duk_heap *heap; |
| 45379 | duk_bool_t ret; |
| 45380 | |
| 45381 | DUK_ASSERT(thr != NULL); |
| 45382 | heap = thr->heap; |
| 45383 | DUK_ASSERT(heap != NULL); |
| 45384 | |
| 45385 | if (heap->dbg_read_cb == NULL) { |
| 45386 | DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)" )); |
| 45387 | return 0; |
| 45388 | } |
| 45389 | if (heap->dbg_peek_cb == NULL) { |
| 45390 | DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)" )); |
| 45391 | return 0; |
| 45392 | } |
| 45393 | |
| 45394 | DUK__DBG_TPORT_ENTER(); |
| 45395 | ret = (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0); |
| 45396 | DUK__DBG_TPORT_EXIT(); |
| 45397 | return ret; |
| 45398 | } |
| 45399 | |
| 45400 | DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) { |
| 45401 | duk_heap *heap; |
| 45402 | |
| 45403 | DUK_ASSERT(thr != NULL); |
| 45404 | heap = thr->heap; |
| 45405 | DUK_ASSERT(heap != NULL); |
| 45406 | |
| 45407 | if (heap->dbg_read_cb == NULL) { |
| 45408 | DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore" )); |
| 45409 | return; |
| 45410 | } |
| 45411 | if (heap->dbg_read_flush_cb == NULL) { |
| 45412 | DUK_DD(DUK_DDPRINT("no read flush callback, ignore" )); |
| 45413 | return; |
| 45414 | } |
| 45415 | |
| 45416 | DUK__DBG_TPORT_ENTER(); |
| 45417 | heap->dbg_read_flush_cb(heap->dbg_udata); |
| 45418 | DUK__DBG_TPORT_EXIT(); |
| 45419 | } |
| 45420 | |
| 45421 | DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) { |
| 45422 | duk_heap *heap; |
| 45423 | |
| 45424 | DUK_ASSERT(thr != NULL); |
| 45425 | heap = thr->heap; |
| 45426 | DUK_ASSERT(heap != NULL); |
| 45427 | |
| 45428 | if (heap->dbg_read_cb == NULL) { |
| 45429 | DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore" )); |
| 45430 | return; |
| 45431 | } |
| 45432 | if (heap->dbg_write_flush_cb == NULL) { |
| 45433 | DUK_DD(DUK_DDPRINT("no write flush callback, ignore" )); |
| 45434 | return; |
| 45435 | } |
| 45436 | |
| 45437 | DUK__DBG_TPORT_ENTER(); |
| 45438 | heap->dbg_write_flush_cb(heap->dbg_udata); |
| 45439 | DUK__DBG_TPORT_EXIT(); |
| 45440 | } |
| 45441 | |
| 45442 | /* |
| 45443 | * Debug connection skip primitives |
| 45444 | */ |
| 45445 | |
| 45446 | /* Skip fully. */ |
| 45447 | DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) { |
| 45448 | duk_uint8_t dummy[64]; |
| 45449 | duk_size_t now; |
| 45450 | |
| 45451 | DUK_ASSERT(thr != NULL); |
| 45452 | |
| 45453 | while (length > 0) { |
| 45454 | now = (length > sizeof(dummy) ? sizeof(dummy) : length); |
| 45455 | duk_debug_read_bytes(thr, dummy, now); |
| 45456 | length -= now; |
| 45457 | } |
| 45458 | } |
| 45459 | |
| 45460 | DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) { |
| 45461 | DUK_ASSERT(thr != NULL); |
| 45462 | |
| 45463 | (void) duk_debug_read_byte(thr); |
| 45464 | } |
| 45465 | |
| 45466 | /* |
| 45467 | * Debug connection read primitives |
| 45468 | */ |
| 45469 | |
| 45470 | /* Peek ahead in the stream one byte. */ |
| 45471 | DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) { |
| 45472 | /* It is important not to call this if the last byte read was an EOM. |
| 45473 | * Reading ahead in this scenario would cause unnecessary blocking if |
| 45474 | * another message is not available. |
| 45475 | */ |
| 45476 | |
| 45477 | duk_uint8_t x; |
| 45478 | |
| 45479 | x = duk_debug_read_byte(thr); |
| 45480 | thr->heap->dbg_have_next_byte = 1; |
| 45481 | thr->heap->dbg_next_byte = x; |
| 45482 | return x; |
| 45483 | } |
| 45484 | |
| 45485 | /* Read fully. */ |
| 45486 | DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) { |
| 45487 | duk_heap *heap; |
| 45488 | duk_uint8_t *p; |
| 45489 | duk_size_t left; |
| 45490 | duk_size_t got; |
| 45491 | |
| 45492 | DUK_ASSERT(thr != NULL); |
| 45493 | heap = thr->heap; |
| 45494 | DUK_ASSERT(heap != NULL); |
| 45495 | DUK_ASSERT(data != NULL); |
| 45496 | |
| 45497 | if (heap->dbg_read_cb == NULL) { |
| 45498 | DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data" , (long) length)); |
| 45499 | goto fail; |
| 45500 | } |
| 45501 | |
| 45502 | /* NOTE: length may be zero */ |
| 45503 | p = data; |
| 45504 | if (length >= 1 && heap->dbg_have_next_byte) { |
| 45505 | heap->dbg_have_next_byte = 0; |
| 45506 | *p++ = heap->dbg_next_byte; |
| 45507 | } |
| 45508 | for (;;) { |
| 45509 | left = (duk_size_t) ((data + length) - p); |
| 45510 | if (left == 0) { |
| 45511 | break; |
| 45512 | } |
| 45513 | DUK_ASSERT(heap->dbg_read_cb != NULL); |
| 45514 | DUK_ASSERT(left >= 1); |
| 45515 | #if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE) |
| 45516 | left = 1; |
| 45517 | #endif |
| 45518 | DUK__DBG_TPORT_ENTER(); |
| 45519 | got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left); |
| 45520 | DUK__DBG_TPORT_EXIT(); |
| 45521 | |
| 45522 | if (got == 0 || got > left) { |
| 45523 | DUK_D(DUK_DPRINT("connection error during read, return zero data" )); |
| 45524 | duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */ |
| 45525 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45526 | goto fail; |
| 45527 | } |
| 45528 | p += got; |
| 45529 | } |
| 45530 | return; |
| 45531 | |
| 45532 | fail: |
| 45533 | duk_memzero((void *) data, (size_t) length); |
| 45534 | } |
| 45535 | |
| 45536 | DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) { |
| 45537 | duk_uint8_t x; |
| 45538 | |
| 45539 | x = 0; /* just in case callback is broken and won't write 'x' */ |
| 45540 | duk_debug_read_bytes(thr, &x, 1); |
| 45541 | return x; |
| 45542 | } |
| 45543 | |
| 45544 | DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) { |
| 45545 | duk_uint8_t buf[4]; |
| 45546 | |
| 45547 | DUK_ASSERT(thr != NULL); |
| 45548 | |
| 45549 | duk_debug_read_bytes(thr, buf, 4); |
| 45550 | return ((duk_uint32_t) buf[0] << 24) | |
| 45551 | ((duk_uint32_t) buf[1] << 16) | |
| 45552 | ((duk_uint32_t) buf[2] << 8) | |
| 45553 | (duk_uint32_t) buf[3]; |
| 45554 | } |
| 45555 | |
| 45556 | DUK_LOCAL duk_int32_t duk__debug_read_int32_raw(duk_hthread *thr) { |
| 45557 | return (duk_int32_t) duk__debug_read_uint32_raw(thr); |
| 45558 | } |
| 45559 | |
| 45560 | DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) { |
| 45561 | duk_uint8_t buf[2]; |
| 45562 | |
| 45563 | DUK_ASSERT(thr != NULL); |
| 45564 | |
| 45565 | duk_debug_read_bytes(thr, buf, 2); |
| 45566 | return ((duk_uint16_t) buf[0] << 8) | |
| 45567 | (duk_uint16_t) buf[1]; |
| 45568 | } |
| 45569 | |
| 45570 | DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) { |
| 45571 | duk_small_uint_t x; |
| 45572 | duk_small_uint_t t; |
| 45573 | |
| 45574 | DUK_ASSERT(thr != NULL); |
| 45575 | |
| 45576 | x = duk_debug_read_byte(thr); |
| 45577 | if (x >= 0xc0) { |
| 45578 | t = duk_debug_read_byte(thr); |
| 45579 | return (duk_int32_t) (((x - 0xc0) << 8) + t); |
| 45580 | } else if (x >= 0x80) { |
| 45581 | return (duk_int32_t) (x - 0x80); |
| 45582 | } else if (x == DUK_DBG_IB_INT4) { |
| 45583 | return (duk_int32_t) duk__debug_read_uint32_raw(thr); |
| 45584 | } |
| 45585 | |
| 45586 | DUK_D(DUK_DPRINT("debug connection error: failed to decode int" )); |
| 45587 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45588 | return 0; |
| 45589 | } |
| 45590 | |
| 45591 | DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) { |
| 45592 | duk_uint8_t buf[31]; |
| 45593 | duk_uint8_t *p; |
| 45594 | |
| 45595 | if (len <= sizeof(buf)) { |
| 45596 | duk_debug_read_bytes(thr, buf, (duk_size_t) len); |
| 45597 | duk_push_lstring(thr, (const char *) buf, (duk_size_t) len); |
| 45598 | } else { |
| 45599 | p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */ |
| 45600 | DUK_ASSERT(p != NULL); |
| 45601 | duk_debug_read_bytes(thr, p, (duk_size_t) len); |
| 45602 | (void) duk_buffer_to_string(thr, -1); /* Safety relies on debug client, which is OK. */ |
| 45603 | } |
| 45604 | |
| 45605 | return duk_require_hstring(thr, -1); |
| 45606 | } |
| 45607 | |
| 45608 | DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) { |
| 45609 | duk_small_uint_t x; |
| 45610 | duk_uint32_t len; |
| 45611 | |
| 45612 | DUK_ASSERT(thr != NULL); |
| 45613 | |
| 45614 | x = duk_debug_read_byte(thr); |
| 45615 | if (x >= 0x60 && x <= 0x7f) { |
| 45616 | /* For short strings, use a fixed temp buffer. */ |
| 45617 | len = (duk_uint32_t) (x - 0x60); |
| 45618 | } else if (x == DUK_DBG_IB_STR2) { |
| 45619 | len = (duk_uint32_t) duk__debug_read_uint16_raw(thr); |
| 45620 | } else if (x == DUK_DBG_IB_STR4) { |
| 45621 | len = (duk_uint32_t) duk__debug_read_uint32_raw(thr); |
| 45622 | } else { |
| 45623 | goto fail; |
| 45624 | } |
| 45625 | |
| 45626 | return duk__debug_read_hstring_raw(thr, len); |
| 45627 | |
| 45628 | fail: |
| 45629 | DUK_D(DUK_DPRINT("debug connection error: failed to decode int" )); |
| 45630 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45631 | duk_push_hstring_empty(thr); /* always push some string */ |
| 45632 | return duk_require_hstring(thr, -1); |
| 45633 | } |
| 45634 | |
| 45635 | DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) { |
| 45636 | duk_uint8_t *p; |
| 45637 | |
| 45638 | p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len); /* zero for paranoia */ |
| 45639 | DUK_ASSERT(p != NULL); |
| 45640 | duk_debug_read_bytes(thr, p, (duk_size_t) len); |
| 45641 | |
| 45642 | return duk_require_hbuffer(thr, -1); |
| 45643 | } |
| 45644 | |
| 45645 | DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) { |
| 45646 | duk_small_uint_t x; |
| 45647 | duk__ptr_union pu; |
| 45648 | |
| 45649 | DUK_ASSERT(thr != NULL); |
| 45650 | |
| 45651 | x = duk_debug_read_byte(thr); |
| 45652 | if (x != sizeof(pu)) { |
| 45653 | goto fail; |
| 45654 | } |
| 45655 | duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu)); |
| 45656 | #if defined(DUK_USE_INTEGER_LE) |
| 45657 | duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu)); |
| 45658 | #endif |
| 45659 | return (void *) pu.p; |
| 45660 | |
| 45661 | fail: |
| 45662 | DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer" )); |
| 45663 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45664 | return (void *) NULL; |
| 45665 | } |
| 45666 | |
| 45667 | DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) { |
| 45668 | duk_double_union du; |
| 45669 | |
| 45670 | DUK_ASSERT(sizeof(du.uc) == 8); |
| 45671 | duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc)); |
| 45672 | DUK_DBLUNION_DOUBLE_NTOH(&du); |
| 45673 | return du.d; |
| 45674 | } |
| 45675 | |
| 45676 | #if 0 |
| 45677 | DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) { |
| 45678 | duk_small_uint_t x; |
| 45679 | |
| 45680 | DUK_ASSERT(thr != NULL); |
| 45681 | |
| 45682 | x = duk_debug_read_byte(thr); |
| 45683 | if (x != DUK_DBG_IB_HEAPPTR) { |
| 45684 | goto fail; |
| 45685 | } |
| 45686 | |
| 45687 | return (duk_heaphdr *) duk__debug_read_pointer_raw(thr); |
| 45688 | |
| 45689 | fail: |
| 45690 | DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr" )); |
| 45691 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45692 | return NULL; |
| 45693 | } |
| 45694 | #endif |
| 45695 | |
| 45696 | DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) { |
| 45697 | duk_small_uint_t x; |
| 45698 | |
| 45699 | DUK_ASSERT(thr != NULL); |
| 45700 | |
| 45701 | x = duk_debug_read_byte(thr); |
| 45702 | switch (x) { |
| 45703 | case DUK_DBG_IB_OBJECT: |
| 45704 | case DUK_DBG_IB_POINTER: |
| 45705 | case DUK_DBG_IB_HEAPPTR: |
| 45706 | /* Accept any pointer-like value; for 'object' dvalue, read |
| 45707 | * and ignore the class number. |
| 45708 | */ |
| 45709 | if (x == DUK_DBG_IB_OBJECT) { |
| 45710 | duk_debug_skip_byte(thr); |
| 45711 | } |
| 45712 | break; |
| 45713 | default: |
| 45714 | goto fail; |
| 45715 | } |
| 45716 | |
| 45717 | return (duk_heaphdr *) duk__debug_read_pointer_raw(thr); |
| 45718 | |
| 45719 | fail: |
| 45720 | DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)" )); |
| 45721 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45722 | return NULL; |
| 45723 | } |
| 45724 | |
| 45725 | DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) { |
| 45726 | duk_uint8_t x; |
| 45727 | duk_uint_t t; |
| 45728 | duk_uint32_t len; |
| 45729 | |
| 45730 | DUK_ASSERT(thr != NULL); |
| 45731 | |
| 45732 | x = duk_debug_read_byte(thr); |
| 45733 | |
| 45734 | if (x >= 0xc0) { |
| 45735 | t = (duk_uint_t) (x - 0xc0); |
| 45736 | t = (t << 8) + duk_debug_read_byte(thr); |
| 45737 | duk_push_uint(thr, (duk_uint_t) t); |
| 45738 | goto return_ptr; |
| 45739 | } |
| 45740 | if (x >= 0x80) { |
| 45741 | duk_push_uint(thr, (duk_uint_t) (x - 0x80)); |
| 45742 | goto return_ptr; |
| 45743 | } |
| 45744 | if (x >= 0x60) { |
| 45745 | len = (duk_uint32_t) (x - 0x60); |
| 45746 | duk__debug_read_hstring_raw(thr, len); |
| 45747 | goto return_ptr; |
| 45748 | } |
| 45749 | |
| 45750 | switch (x) { |
| 45751 | case DUK_DBG_IB_INT4: { |
| 45752 | duk_int32_t i = duk__debug_read_int32_raw(thr); |
| 45753 | duk_push_i32(thr, i); |
| 45754 | break; |
| 45755 | } |
| 45756 | case DUK_DBG_IB_STR4: { |
| 45757 | len = duk__debug_read_uint32_raw(thr); |
| 45758 | duk__debug_read_hstring_raw(thr, len); |
| 45759 | break; |
| 45760 | } |
| 45761 | case DUK_DBG_IB_STR2: { |
| 45762 | len = duk__debug_read_uint16_raw(thr); |
| 45763 | duk__debug_read_hstring_raw(thr, len); |
| 45764 | break; |
| 45765 | } |
| 45766 | case DUK_DBG_IB_BUF4: { |
| 45767 | len = duk__debug_read_uint32_raw(thr); |
| 45768 | duk__debug_read_hbuffer_raw(thr, len); |
| 45769 | break; |
| 45770 | } |
| 45771 | case DUK_DBG_IB_BUF2: { |
| 45772 | len = duk__debug_read_uint16_raw(thr); |
| 45773 | duk__debug_read_hbuffer_raw(thr, len); |
| 45774 | break; |
| 45775 | } |
| 45776 | case DUK_DBG_IB_UNDEFINED: { |
| 45777 | duk_push_undefined(thr); |
| 45778 | break; |
| 45779 | } |
| 45780 | case DUK_DBG_IB_NULL: { |
| 45781 | duk_push_null(thr); |
| 45782 | break; |
| 45783 | } |
| 45784 | case DUK_DBG_IB_TRUE: { |
| 45785 | duk_push_true(thr); |
| 45786 | break; |
| 45787 | } |
| 45788 | case DUK_DBG_IB_FALSE: { |
| 45789 | duk_push_false(thr); |
| 45790 | break; |
| 45791 | } |
| 45792 | case DUK_DBG_IB_NUMBER: { |
| 45793 | duk_double_t d; |
| 45794 | d = duk__debug_read_double_raw(thr); |
| 45795 | duk_push_number(thr, d); |
| 45796 | break; |
| 45797 | } |
| 45798 | case DUK_DBG_IB_OBJECT: { |
| 45799 | duk_heaphdr *h; |
| 45800 | duk_debug_skip_byte(thr); |
| 45801 | h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr); |
| 45802 | duk_push_heapptr(thr, (void *) h); |
| 45803 | break; |
| 45804 | } |
| 45805 | case DUK_DBG_IB_POINTER: { |
| 45806 | void *ptr; |
| 45807 | ptr = duk__debug_read_pointer_raw(thr); |
| 45808 | duk_push_pointer(thr, ptr); |
| 45809 | break; |
| 45810 | } |
| 45811 | case DUK_DBG_IB_LIGHTFUNC: { |
| 45812 | /* XXX: Not needed for now, so not implemented. Note that |
| 45813 | * function pointers may have different size/layout than |
| 45814 | * a void pointer. |
| 45815 | */ |
| 45816 | DUK_D(DUK_DPRINT("reading lightfunc values unimplemented" )); |
| 45817 | goto fail; |
| 45818 | } |
| 45819 | case DUK_DBG_IB_HEAPPTR: { |
| 45820 | duk_heaphdr *h; |
| 45821 | h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr); |
| 45822 | duk_push_heapptr(thr, (void *) h); |
| 45823 | break; |
| 45824 | } |
| 45825 | case DUK_DBG_IB_UNUSED: /* unused: not accepted in inbound messages */ |
| 45826 | default: |
| 45827 | goto fail; |
| 45828 | } |
| 45829 | |
| 45830 | return_ptr: |
| 45831 | return DUK_GET_TVAL_NEGIDX(thr, -1); |
| 45832 | |
| 45833 | fail: |
| 45834 | DUK_D(DUK_DPRINT("debug connection error: failed to decode tval" )); |
| 45835 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45836 | return NULL; |
| 45837 | } |
| 45838 | |
| 45839 | /* |
| 45840 | * Debug connection write primitives |
| 45841 | */ |
| 45842 | |
| 45843 | /* Write fully. */ |
| 45844 | DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) { |
| 45845 | duk_heap *heap; |
| 45846 | const duk_uint8_t *p; |
| 45847 | duk_size_t left; |
| 45848 | duk_size_t got; |
| 45849 | |
| 45850 | DUK_ASSERT(thr != NULL); |
| 45851 | DUK_ASSERT(length == 0 || data != NULL); |
| 45852 | heap = thr->heap; |
| 45853 | DUK_ASSERT(heap != NULL); |
| 45854 | |
| 45855 | if (heap->dbg_write_cb == NULL) { |
| 45856 | DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore" , (long) length)); |
| 45857 | return; |
| 45858 | } |
| 45859 | if (length == 0) { |
| 45860 | /* Avoid doing an actual write callback with length == 0, |
| 45861 | * because that's reserved for a write flush. |
| 45862 | */ |
| 45863 | return; |
| 45864 | } |
| 45865 | DUK_ASSERT(data != NULL); |
| 45866 | |
| 45867 | p = data; |
| 45868 | for (;;) { |
| 45869 | left = (duk_size_t) ((data + length) - p); |
| 45870 | if (left == 0) { |
| 45871 | break; |
| 45872 | } |
| 45873 | DUK_ASSERT(heap->dbg_write_cb != NULL); |
| 45874 | DUK_ASSERT(left >= 1); |
| 45875 | #if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE) |
| 45876 | left = 1; |
| 45877 | #endif |
| 45878 | DUK__DBG_TPORT_ENTER(); |
| 45879 | got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left); |
| 45880 | DUK__DBG_TPORT_EXIT(); |
| 45881 | |
| 45882 | if (got == 0 || got > left) { |
| 45883 | duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */ |
| 45884 | DUK_D(DUK_DPRINT("connection error during write" )); |
| 45885 | DUK__SET_CONN_BROKEN(thr, 1); |
| 45886 | return; |
| 45887 | } |
| 45888 | p += got; |
| 45889 | } |
| 45890 | } |
| 45891 | |
| 45892 | DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) { |
| 45893 | duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1); |
| 45894 | } |
| 45895 | |
| 45896 | DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) { |
| 45897 | duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED); |
| 45898 | } |
| 45899 | |
| 45900 | DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) { |
| 45901 | duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED); |
| 45902 | } |
| 45903 | |
| 45904 | #if defined(DUK_USE_DEBUGGER_INSPECT) |
| 45905 | DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) { |
| 45906 | duk_debug_write_byte(thr, DUK_DBG_IB_NULL); |
| 45907 | } |
| 45908 | #endif |
| 45909 | |
| 45910 | DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) { |
| 45911 | duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE); |
| 45912 | } |
| 45913 | |
| 45914 | /* Write signed 32-bit integer. */ |
| 45915 | DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) { |
| 45916 | duk_uint8_t buf[5]; |
| 45917 | duk_size_t len; |
| 45918 | |
| 45919 | DUK_ASSERT(thr != NULL); |
| 45920 | |
| 45921 | if (x >= 0 && x <= 0x3fL) { |
| 45922 | buf[0] = (duk_uint8_t) (0x80 + x); |
| 45923 | len = 1; |
| 45924 | } else if (x >= 0 && x <= 0x3fffL) { |
| 45925 | buf[0] = (duk_uint8_t) (0xc0 + (x >> 8)); |
| 45926 | buf[1] = (duk_uint8_t) (x & 0xff); |
| 45927 | len = 2; |
| 45928 | } else { |
| 45929 | /* Signed integers always map to 4 bytes now. */ |
| 45930 | buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4; |
| 45931 | buf[1] = (duk_uint8_t) ((x >> 24) & 0xff); |
| 45932 | buf[2] = (duk_uint8_t) ((x >> 16) & 0xff); |
| 45933 | buf[3] = (duk_uint8_t) ((x >> 8) & 0xff); |
| 45934 | buf[4] = (duk_uint8_t) (x & 0xff); |
| 45935 | len = 5; |
| 45936 | } |
| 45937 | duk_debug_write_bytes(thr, buf, len); |
| 45938 | } |
| 45939 | |
| 45940 | /* Write unsigned 32-bit integer. */ |
| 45941 | DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) { |
| 45942 | /* The debugger protocol doesn't support a plain integer encoding for |
| 45943 | * the full 32-bit unsigned range (only 32-bit signed). For now, |
| 45944 | * unsigned 32-bit values simply written as signed ones. This is not |
| 45945 | * a concrete issue except for 32-bit heaphdr fields. Proper solutions |
| 45946 | * would be to (a) write such integers as IEEE doubles or (b) add an |
| 45947 | * unsigned 32-bit dvalue. |
| 45948 | */ |
| 45949 | if (x >= 0x80000000UL) { |
| 45950 | DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer" , |
| 45951 | (long) x)); |
| 45952 | } |
| 45953 | duk_debug_write_int(thr, (duk_int32_t) x); |
| 45954 | } |
| 45955 | |
| 45956 | DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) { |
| 45957 | duk_uint8_t buf[5]; |
| 45958 | duk_size_t buflen; |
| 45959 | |
| 45960 | DUK_ASSERT(thr != NULL); |
| 45961 | DUK_ASSERT(length == 0 || data != NULL); |
| 45962 | |
| 45963 | if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) { |
| 45964 | /* For strings, special form for short lengths. */ |
| 45965 | buf[0] = (duk_uint8_t) (0x60 + length); |
| 45966 | buflen = 1; |
| 45967 | } else if (length <= 0xffffUL) { |
| 45968 | buf[0] = (duk_uint8_t) (marker_base + 1); |
| 45969 | buf[1] = (duk_uint8_t) (length >> 8); |
| 45970 | buf[2] = (duk_uint8_t) (length & 0xff); |
| 45971 | buflen = 3; |
| 45972 | } else { |
| 45973 | buf[0] = (duk_uint8_t) marker_base; |
| 45974 | buf[1] = (duk_uint8_t) (length >> 24); |
| 45975 | buf[2] = (duk_uint8_t) ((length >> 16) & 0xff); |
| 45976 | buf[3] = (duk_uint8_t) ((length >> 8) & 0xff); |
| 45977 | buf[4] = (duk_uint8_t) (length & 0xff); |
| 45978 | buflen = 5; |
| 45979 | } |
| 45980 | |
| 45981 | duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen); |
| 45982 | duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length); |
| 45983 | } |
| 45984 | |
| 45985 | DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) { |
| 45986 | duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4); |
| 45987 | } |
| 45988 | |
| 45989 | DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) { |
| 45990 | DUK_ASSERT(thr != NULL); |
| 45991 | |
| 45992 | duk_debug_write_string(thr, |
| 45993 | data, |
| 45994 | data ? DUK_STRLEN(data) : 0); |
| 45995 | } |
| 45996 | |
| 45997 | DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) { |
| 45998 | DUK_ASSERT(thr != NULL); |
| 45999 | |
| 46000 | /* XXX: differentiate null pointer from empty string? */ |
| 46001 | duk_debug_write_string(thr, |
| 46002 | (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL), |
| 46003 | (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0)); |
| 46004 | } |
| 46005 | |
| 46006 | DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) { |
| 46007 | duk_debug_write_hstring(thr, duk_safe_to_hstring(thr, -1)); |
| 46008 | } |
| 46009 | |
| 46010 | DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) { |
| 46011 | duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4); |
| 46012 | } |
| 46013 | |
| 46014 | DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) { |
| 46015 | DUK_ASSERT(thr != NULL); |
| 46016 | |
| 46017 | duk_debug_write_buffer(thr, |
| 46018 | (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL), |
| 46019 | (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0)); |
| 46020 | } |
| 46021 | |
| 46022 | DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) { |
| 46023 | duk_uint8_t buf[2]; |
| 46024 | duk__ptr_union pu; |
| 46025 | |
| 46026 | DUK_ASSERT(thr != NULL); |
| 46027 | DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16); |
| 46028 | /* ptr may be NULL */ |
| 46029 | |
| 46030 | buf[0] = ibyte; |
| 46031 | buf[1] = sizeof(pu); |
| 46032 | duk_debug_write_bytes(thr, buf, 2); |
| 46033 | pu.p = (void *) ptr; |
| 46034 | #if defined(DUK_USE_INTEGER_LE) |
| 46035 | duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu)); |
| 46036 | #endif |
| 46037 | duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu)); |
| 46038 | } |
| 46039 | |
| 46040 | DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) { |
| 46041 | duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER); |
| 46042 | } |
| 46043 | |
| 46044 | #if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT) |
| 46045 | DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) { |
| 46046 | duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR); |
| 46047 | } |
| 46048 | #endif /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */ |
| 46049 | |
| 46050 | DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) { |
| 46051 | duk_uint8_t buf[3]; |
| 46052 | duk__ptr_union pu; |
| 46053 | |
| 46054 | DUK_ASSERT(thr != NULL); |
| 46055 | DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16); |
| 46056 | DUK_ASSERT(obj != NULL); |
| 46057 | |
| 46058 | buf[0] = DUK_DBG_IB_OBJECT; |
| 46059 | buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj); |
| 46060 | buf[2] = sizeof(pu); |
| 46061 | duk_debug_write_bytes(thr, buf, 3); |
| 46062 | pu.p = (void *) obj; |
| 46063 | #if defined(DUK_USE_INTEGER_LE) |
| 46064 | duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu)); |
| 46065 | #endif |
| 46066 | duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu)); |
| 46067 | } |
| 46068 | |
| 46069 | DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) { |
| 46070 | duk_c_function lf_func; |
| 46071 | duk_small_uint_t lf_flags; |
| 46072 | duk_uint8_t buf[4]; |
| 46073 | duk_double_union du1; |
| 46074 | duk_double_union du2; |
| 46075 | duk_int32_t i32; |
| 46076 | |
| 46077 | DUK_ASSERT(thr != NULL); |
| 46078 | DUK_ASSERT(tv != NULL); |
| 46079 | |
| 46080 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 46081 | case DUK_TAG_UNDEFINED: |
| 46082 | duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED); |
| 46083 | break; |
| 46084 | case DUK_TAG_UNUSED: |
| 46085 | duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED); |
| 46086 | break; |
| 46087 | case DUK_TAG_NULL: |
| 46088 | duk_debug_write_byte(thr, DUK_DBG_IB_NULL); |
| 46089 | break; |
| 46090 | case DUK_TAG_BOOLEAN: |
| 46091 | DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || |
| 46092 | DUK_TVAL_GET_BOOLEAN(tv) == 1); |
| 46093 | duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv)); |
| 46094 | break; |
| 46095 | case DUK_TAG_POINTER: |
| 46096 | duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv)); |
| 46097 | break; |
| 46098 | case DUK_TAG_LIGHTFUNC: |
| 46099 | DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags); |
| 46100 | buf[0] = DUK_DBG_IB_LIGHTFUNC; |
| 46101 | buf[1] = (duk_uint8_t) (lf_flags >> 8); |
| 46102 | buf[2] = (duk_uint8_t) (lf_flags & 0xff); |
| 46103 | buf[3] = sizeof(lf_func); |
| 46104 | duk_debug_write_bytes(thr, buf, 4); |
| 46105 | duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func)); |
| 46106 | break; |
| 46107 | case DUK_TAG_STRING: |
| 46108 | duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv)); |
| 46109 | break; |
| 46110 | case DUK_TAG_OBJECT: |
| 46111 | duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv)); |
| 46112 | break; |
| 46113 | case DUK_TAG_BUFFER: |
| 46114 | duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv)); |
| 46115 | break; |
| 46116 | #if defined(DUK_USE_FASTINT) |
| 46117 | case DUK_TAG_FASTINT: |
| 46118 | #endif |
| 46119 | default: |
| 46120 | /* Numbers are normalized to big (network) endian. We can |
| 46121 | * (but are not required) to use integer dvalues when there's |
| 46122 | * no loss of precision. |
| 46123 | * |
| 46124 | * XXX: share check with other code; this check is slow but |
| 46125 | * reliable and doesn't require careful exponent/mantissa |
| 46126 | * mask tricks as in the fastint downgrade code. |
| 46127 | */ |
| 46128 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 46129 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 46130 | du1.d = DUK_TVAL_GET_NUMBER(tv); |
| 46131 | i32 = (duk_int32_t) du1.d; |
| 46132 | du2.d = (duk_double_t) i32; |
| 46133 | |
| 46134 | DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x " |
| 46135 | "du2=%02x%02x%02x%02x%02x%02x%02x%02x" , |
| 46136 | (long) i32, |
| 46137 | (unsigned int) du1.uc[0], (unsigned int) du1.uc[1], |
| 46138 | (unsigned int) du1.uc[2], (unsigned int) du1.uc[3], |
| 46139 | (unsigned int) du1.uc[4], (unsigned int) du1.uc[5], |
| 46140 | (unsigned int) du1.uc[6], (unsigned int) du1.uc[7], |
| 46141 | (unsigned int) du2.uc[0], (unsigned int) du2.uc[1], |
| 46142 | (unsigned int) du2.uc[2], (unsigned int) du2.uc[3], |
| 46143 | (unsigned int) du2.uc[4], (unsigned int) du2.uc[5], |
| 46144 | (unsigned int) du2.uc[6], (unsigned int) du2.uc[7])); |
| 46145 | |
| 46146 | if (duk_memcmp((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) { |
| 46147 | duk_debug_write_int(thr, i32); |
| 46148 | } else { |
| 46149 | DUK_DBLUNION_DOUBLE_HTON(&du1); |
| 46150 | duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER); |
| 46151 | duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc)); |
| 46152 | } |
| 46153 | } |
| 46154 | } |
| 46155 | |
| 46156 | #if defined(DUK_USE_DEBUGGER_DUMPHEAP) |
| 46157 | /* Variant for writing duk_tvals so that any heap allocated values are |
| 46158 | * written out as tagged heap pointers. |
| 46159 | */ |
| 46160 | DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) { |
| 46161 | if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { |
| 46162 | duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); |
| 46163 | duk_debug_write_heapptr(thr, h); |
| 46164 | } else { |
| 46165 | duk_debug_write_tval(thr, tv); |
| 46166 | } |
| 46167 | } |
| 46168 | #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ |
| 46169 | |
| 46170 | /* |
| 46171 | * Debug connection message write helpers |
| 46172 | */ |
| 46173 | |
| 46174 | #if 0 /* unused */ |
| 46175 | DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) { |
| 46176 | duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST); |
| 46177 | duk_debug_write_int(thr, command); |
| 46178 | } |
| 46179 | #endif |
| 46180 | |
| 46181 | DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) { |
| 46182 | duk_debug_write_byte(thr, DUK_DBG_IB_REPLY); |
| 46183 | } |
| 46184 | |
| 46185 | DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) { |
| 46186 | /* Allow NULL 'msg' */ |
| 46187 | duk_debug_write_byte(thr, DUK_DBG_IB_ERROR); |
| 46188 | duk_debug_write_int(thr, (duk_int32_t) err_code); |
| 46189 | duk_debug_write_cstring(thr, msg); |
| 46190 | duk_debug_write_eom(thr); |
| 46191 | } |
| 46192 | |
| 46193 | DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) { |
| 46194 | duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY); |
| 46195 | duk_debug_write_int(thr, (duk_int32_t) command); |
| 46196 | } |
| 46197 | |
| 46198 | DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) { |
| 46199 | duk_debug_write_byte(thr, DUK_DBG_IB_EOM); |
| 46200 | |
| 46201 | /* As an initial implementation, write flush after every EOM (and the |
| 46202 | * version identifier). A better implementation would flush only when |
| 46203 | * Duktape is finished processing messages so that a flush only happens |
| 46204 | * after all outbound messages are finished on that occasion. |
| 46205 | */ |
| 46206 | duk_debug_write_flush(thr); |
| 46207 | } |
| 46208 | |
| 46209 | /* |
| 46210 | * Status message and helpers |
| 46211 | */ |
| 46212 | |
| 46213 | DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) { |
| 46214 | duk_activation *act; |
| 46215 | duk_uint_fast32_t line; |
| 46216 | duk_uint_fast32_t pc; |
| 46217 | |
| 46218 | act = thr->callstack_curr; |
| 46219 | if (act == NULL) { |
| 46220 | return 0; |
| 46221 | } |
| 46222 | |
| 46223 | /* We're conceptually between two opcodes; act->pc indicates the next |
| 46224 | * instruction to be executed. This is usually the correct pc/line to |
| 46225 | * indicate in Status. (For the 'debugger' statement this now reports |
| 46226 | * the pc/line after the debugger statement because the debugger opcode |
| 46227 | * has already been executed.) |
| 46228 | */ |
| 46229 | |
| 46230 | pc = duk_hthread_get_act_curr_pc(thr, act); |
| 46231 | |
| 46232 | /* XXX: this should be optimized to be a raw query and avoid valstack |
| 46233 | * operations if possible. |
| 46234 | */ |
| 46235 | duk_push_tval(thr, &act->tv_func); |
| 46236 | line = duk_hobject_pc2line_query(thr, -1, pc); |
| 46237 | duk_pop(thr); |
| 46238 | return line; |
| 46239 | } |
| 46240 | |
| 46241 | DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) { |
| 46242 | duk_activation *act; |
| 46243 | |
| 46244 | duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS); |
| 46245 | duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0)); |
| 46246 | |
| 46247 | act = thr->callstack_curr; |
| 46248 | if (act == NULL) { |
| 46249 | duk_debug_write_undefined(thr); |
| 46250 | duk_debug_write_undefined(thr); |
| 46251 | duk_debug_write_int(thr, 0); |
| 46252 | duk_debug_write_int(thr, 0); |
| 46253 | } else { |
| 46254 | duk_push_tval(thr, &act->tv_func); |
| 46255 | duk_get_prop_literal(thr, -1, "fileName" ); |
| 46256 | duk__debug_write_hstring_safe_top(thr); |
| 46257 | duk_get_prop_literal(thr, -2, "name" ); |
| 46258 | duk__debug_write_hstring_safe_top(thr); |
| 46259 | duk_pop_3(thr); |
| 46260 | /* Report next pc/line to be executed. */ |
| 46261 | duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr)); |
| 46262 | duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act)); |
| 46263 | } |
| 46264 | |
| 46265 | duk_debug_write_eom(thr); |
| 46266 | } |
| 46267 | |
| 46268 | #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) |
| 46269 | DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) { |
| 46270 | /* |
| 46271 | * NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM |
| 46272 | */ |
| 46273 | |
| 46274 | duk_activation *act; |
| 46275 | duk_uint32_t pc; |
| 46276 | |
| 46277 | DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */ |
| 46278 | |
| 46279 | duk_debug_write_notify(thr, DUK_DBG_CMD_THROW); |
| 46280 | duk_debug_write_int(thr, (duk_int32_t) fatal); |
| 46281 | |
| 46282 | /* Report thrown value to client coerced to string */ |
| 46283 | duk_dup_top(thr); |
| 46284 | duk__debug_write_hstring_safe_top(thr); |
| 46285 | duk_pop(thr); |
| 46286 | |
| 46287 | if (duk_is_error(thr, -1)) { |
| 46288 | /* Error instance, use augmented error data directly */ |
| 46289 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME); |
| 46290 | duk__debug_write_hstring_safe_top(thr); |
| 46291 | duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER); |
| 46292 | duk_debug_write_uint(thr, duk_get_uint(thr, -1)); |
| 46293 | duk_pop_2(thr); |
| 46294 | } else { |
| 46295 | /* For anything other than an Error instance, we calculate the |
| 46296 | * error location directly from the current activation if one |
| 46297 | * exists. |
| 46298 | */ |
| 46299 | act = thr->callstack_curr; |
| 46300 | if (act != NULL) { |
| 46301 | duk_push_tval(thr, &act->tv_func); |
| 46302 | duk_get_prop_literal(thr, -1, "fileName" ); |
| 46303 | duk__debug_write_hstring_safe_top(thr); |
| 46304 | pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act); |
| 46305 | duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc)); |
| 46306 | duk_pop_2(thr); |
| 46307 | } else { |
| 46308 | /* Can happen if duk_throw() is called on an empty |
| 46309 | * callstack. |
| 46310 | */ |
| 46311 | duk_debug_write_cstring(thr, "" ); |
| 46312 | duk_debug_write_uint(thr, 0); |
| 46313 | } |
| 46314 | } |
| 46315 | |
| 46316 | duk_debug_write_eom(thr); |
| 46317 | } |
| 46318 | #endif /* DUK_USE_DEBUGGER_THROW_NOTIFY */ |
| 46319 | |
| 46320 | /* |
| 46321 | * Debug message processing |
| 46322 | */ |
| 46323 | |
| 46324 | /* Skip dvalue. */ |
| 46325 | DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) { |
| 46326 | duk_uint8_t x; |
| 46327 | duk_uint32_t len; |
| 46328 | |
| 46329 | x = duk_debug_read_byte(thr); |
| 46330 | |
| 46331 | if (x >= 0xc0) { |
| 46332 | duk_debug_skip_byte(thr); |
| 46333 | return 0; |
| 46334 | } |
| 46335 | if (x >= 0x80) { |
| 46336 | return 0; |
| 46337 | } |
| 46338 | if (x >= 0x60) { |
| 46339 | duk_debug_skip_bytes(thr, (duk_size_t) (x - 0x60)); |
| 46340 | return 0; |
| 46341 | } |
| 46342 | switch(x) { |
| 46343 | case DUK_DBG_IB_EOM: |
| 46344 | return 1; /* Return 1: got EOM */ |
| 46345 | case DUK_DBG_IB_REQUEST: |
| 46346 | case DUK_DBG_IB_REPLY: |
| 46347 | case DUK_DBG_IB_ERROR: |
| 46348 | case DUK_DBG_IB_NOTIFY: |
| 46349 | break; |
| 46350 | case DUK_DBG_IB_INT4: |
| 46351 | (void) duk__debug_read_uint32_raw(thr); |
| 46352 | break; |
| 46353 | case DUK_DBG_IB_STR4: |
| 46354 | case DUK_DBG_IB_BUF4: |
| 46355 | len = duk__debug_read_uint32_raw(thr); |
| 46356 | duk_debug_skip_bytes(thr, len); |
| 46357 | break; |
| 46358 | case DUK_DBG_IB_STR2: |
| 46359 | case DUK_DBG_IB_BUF2: |
| 46360 | len = duk__debug_read_uint16_raw(thr); |
| 46361 | duk_debug_skip_bytes(thr, len); |
| 46362 | break; |
| 46363 | case DUK_DBG_IB_UNUSED: |
| 46364 | case DUK_DBG_IB_UNDEFINED: |
| 46365 | case DUK_DBG_IB_NULL: |
| 46366 | case DUK_DBG_IB_TRUE: |
| 46367 | case DUK_DBG_IB_FALSE: |
| 46368 | break; |
| 46369 | case DUK_DBG_IB_NUMBER: |
| 46370 | duk_debug_skip_bytes(thr, 8); |
| 46371 | break; |
| 46372 | case DUK_DBG_IB_OBJECT: |
| 46373 | duk_debug_skip_byte(thr); |
| 46374 | len = duk_debug_read_byte(thr); |
| 46375 | duk_debug_skip_bytes(thr, len); |
| 46376 | break; |
| 46377 | case DUK_DBG_IB_POINTER: |
| 46378 | case DUK_DBG_IB_HEAPPTR: |
| 46379 | len = duk_debug_read_byte(thr); |
| 46380 | duk_debug_skip_bytes(thr, len); |
| 46381 | break; |
| 46382 | case DUK_DBG_IB_LIGHTFUNC: |
| 46383 | duk_debug_skip_bytes(thr, 2); |
| 46384 | len = duk_debug_read_byte(thr); |
| 46385 | duk_debug_skip_bytes(thr, len); |
| 46386 | break; |
| 46387 | default: |
| 46388 | goto fail; |
| 46389 | } |
| 46390 | |
| 46391 | return 0; |
| 46392 | |
| 46393 | fail: |
| 46394 | DUK__SET_CONN_BROKEN(thr, 1); |
| 46395 | return 1; /* Pretend like we got EOM */ |
| 46396 | } |
| 46397 | |
| 46398 | /* Skip dvalues to EOM. */ |
| 46399 | DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) { |
| 46400 | for (;;) { |
| 46401 | if (duk__debug_skip_dvalue(thr)) { |
| 46402 | break; |
| 46403 | } |
| 46404 | } |
| 46405 | } |
| 46406 | |
| 46407 | /* Read and validate a call stack index. If index is invalid, write out an |
| 46408 | * error message and return zero. |
| 46409 | */ |
| 46410 | DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) { |
| 46411 | duk_int32_t level; |
| 46412 | level = duk_debug_read_int(thr); |
| 46413 | if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) { |
| 46414 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index" ); |
| 46415 | return 0; /* zero indicates failure */ |
| 46416 | } |
| 46417 | return level; |
| 46418 | } |
| 46419 | |
| 46420 | /* Read a call stack index and lookup the corresponding duk_activation. |
| 46421 | * If index is invalid, write out an error message and return NULL. |
| 46422 | */ |
| 46423 | DUK_LOCAL duk_activation *duk__debug_read_level_get_activation(duk_hthread *thr) { |
| 46424 | duk_activation *act; |
| 46425 | duk_int32_t level; |
| 46426 | |
| 46427 | level = duk_debug_read_int(thr); |
| 46428 | act = duk_hthread_get_activation_for_level(thr, level); |
| 46429 | if (act == NULL) { |
| 46430 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index" ); |
| 46431 | } |
| 46432 | return act; |
| 46433 | } |
| 46434 | |
| 46435 | /* |
| 46436 | * Simple commands |
| 46437 | */ |
| 46438 | |
| 46439 | DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) { |
| 46440 | DUK_UNREF(heap); |
| 46441 | DUK_D(DUK_DPRINT("debug command Version" )); |
| 46442 | |
| 46443 | duk_debug_write_reply(thr); |
| 46444 | duk_debug_write_int(thr, DUK_VERSION); |
| 46445 | duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE); |
| 46446 | duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO); |
| 46447 | #if defined(DUK_USE_DOUBLE_LE) |
| 46448 | duk_debug_write_int(thr, 1); |
| 46449 | #elif defined(DUK_USE_DOUBLE_ME) |
| 46450 | duk_debug_write_int(thr, 2); |
| 46451 | #elif defined(DUK_USE_DOUBLE_BE) |
| 46452 | duk_debug_write_int(thr, 3); |
| 46453 | #else |
| 46454 | duk_debug_write_int(thr, 0); |
| 46455 | #endif |
| 46456 | duk_debug_write_int(thr, (duk_int_t) sizeof(void *)); |
| 46457 | duk_debug_write_eom(thr); |
| 46458 | } |
| 46459 | |
| 46460 | DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) { |
| 46461 | DUK_UNREF(heap); |
| 46462 | DUK_D(DUK_DPRINT("debug command TriggerStatus" )); |
| 46463 | |
| 46464 | duk_debug_write_reply(thr); |
| 46465 | duk_debug_write_eom(thr); |
| 46466 | heap->dbg_state_dirty = 1; |
| 46467 | } |
| 46468 | |
| 46469 | DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) { |
| 46470 | DUK_D(DUK_DPRINT("debug command Pause" )); |
| 46471 | duk_debug_set_paused(heap); |
| 46472 | duk_debug_write_reply(thr); |
| 46473 | duk_debug_write_eom(thr); |
| 46474 | } |
| 46475 | |
| 46476 | DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) { |
| 46477 | duk_small_uint_t pause_flags; |
| 46478 | |
| 46479 | DUK_D(DUK_DPRINT("debug command Resume" )); |
| 46480 | |
| 46481 | duk_debug_clear_paused(heap); |
| 46482 | |
| 46483 | pause_flags = 0; |
| 46484 | #if 0 /* manual testing */ |
| 46485 | pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE; |
| 46486 | pause_flags |= DUK_PAUSE_FLAG_CAUGHT_ERROR; |
| 46487 | pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR; |
| 46488 | #endif |
| 46489 | #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) |
| 46490 | pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR; |
| 46491 | #endif |
| 46492 | |
| 46493 | duk__debug_set_pause_state(thr, heap, pause_flags); |
| 46494 | |
| 46495 | duk_debug_write_reply(thr); |
| 46496 | duk_debug_write_eom(thr); |
| 46497 | } |
| 46498 | |
| 46499 | DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) { |
| 46500 | duk_small_uint_t pause_flags; |
| 46501 | |
| 46502 | DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d" , (int) cmd)); |
| 46503 | |
| 46504 | if (cmd == DUK_DBG_CMD_STEPINTO) { |
| 46505 | pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE | |
| 46506 | DUK_PAUSE_FLAG_FUNC_ENTRY | |
| 46507 | DUK_PAUSE_FLAG_FUNC_EXIT; |
| 46508 | } else if (cmd == DUK_DBG_CMD_STEPOVER) { |
| 46509 | pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE | |
| 46510 | DUK_PAUSE_FLAG_FUNC_EXIT; |
| 46511 | } else { |
| 46512 | DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT); |
| 46513 | pause_flags = DUK_PAUSE_FLAG_FUNC_EXIT; |
| 46514 | } |
| 46515 | #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) |
| 46516 | pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR; |
| 46517 | #endif |
| 46518 | |
| 46519 | /* If current activation doesn't have line information, line-based |
| 46520 | * pause flags are automatically disabled. As a result, e.g. |
| 46521 | * StepInto will then pause on (native) function entry or exit. |
| 46522 | */ |
| 46523 | duk_debug_clear_paused(heap); |
| 46524 | duk__debug_set_pause_state(thr, heap, pause_flags); |
| 46525 | |
| 46526 | duk_debug_write_reply(thr); |
| 46527 | duk_debug_write_eom(thr); |
| 46528 | } |
| 46529 | |
| 46530 | DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) { |
| 46531 | duk_small_int_t i; |
| 46532 | |
| 46533 | DUK_D(DUK_DPRINT("debug command ListBreak" )); |
| 46534 | duk_debug_write_reply(thr); |
| 46535 | for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) { |
| 46536 | duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename); |
| 46537 | duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line); |
| 46538 | } |
| 46539 | duk_debug_write_eom(thr); |
| 46540 | } |
| 46541 | |
| 46542 | DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) { |
| 46543 | duk_hstring *filename; |
| 46544 | duk_uint32_t linenumber; |
| 46545 | duk_small_int_t idx; |
| 46546 | |
| 46547 | DUK_UNREF(heap); |
| 46548 | |
| 46549 | filename = duk_debug_read_hstring(thr); |
| 46550 | linenumber = (duk_uint32_t) duk_debug_read_int(thr); |
| 46551 | DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld" , (duk_hobject *) filename, (long) linenumber)); |
| 46552 | idx = duk_debug_add_breakpoint(thr, filename, linenumber); |
| 46553 | if (idx >= 0) { |
| 46554 | duk_debug_write_reply(thr); |
| 46555 | duk_debug_write_int(thr, (duk_int32_t) idx); |
| 46556 | duk_debug_write_eom(thr); |
| 46557 | } else { |
| 46558 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint" ); |
| 46559 | } |
| 46560 | } |
| 46561 | |
| 46562 | DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) { |
| 46563 | duk_small_uint_t idx; |
| 46564 | |
| 46565 | DUK_UNREF(heap); |
| 46566 | |
| 46567 | DUK_D(DUK_DPRINT("debug command DelBreak" )); |
| 46568 | idx = (duk_small_uint_t) duk_debug_read_int(thr); |
| 46569 | if (duk_debug_remove_breakpoint(thr, idx)) { |
| 46570 | duk_debug_write_reply(thr); |
| 46571 | duk_debug_write_eom(thr); |
| 46572 | } else { |
| 46573 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index" ); |
| 46574 | } |
| 46575 | } |
| 46576 | |
| 46577 | DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) { |
| 46578 | duk_activation *act; |
| 46579 | duk_hstring *str; |
| 46580 | duk_bool_t rc; |
| 46581 | |
| 46582 | DUK_UNREF(heap); |
| 46583 | DUK_D(DUK_DPRINT("debug command GetVar" )); |
| 46584 | |
| 46585 | act = duk__debug_read_level_get_activation(thr); |
| 46586 | if (act == NULL) { |
| 46587 | return; |
| 46588 | } |
| 46589 | str = duk_debug_read_hstring(thr); /* push to stack */ |
| 46590 | DUK_ASSERT(str != NULL); |
| 46591 | |
| 46592 | rc = duk_js_getvar_activation(thr, act, str, 0); |
| 46593 | |
| 46594 | duk_debug_write_reply(thr); |
| 46595 | if (rc) { |
| 46596 | duk_debug_write_int(thr, 1); |
| 46597 | DUK_ASSERT(duk_get_tval(thr, -2) != NULL); |
| 46598 | duk_debug_write_tval(thr, duk_get_tval(thr, -2)); |
| 46599 | } else { |
| 46600 | duk_debug_write_int(thr, 0); |
| 46601 | duk_debug_write_unused(thr); |
| 46602 | } |
| 46603 | duk_debug_write_eom(thr); |
| 46604 | } |
| 46605 | |
| 46606 | DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) { |
| 46607 | duk_activation *act; |
| 46608 | duk_hstring *str; |
| 46609 | duk_tval *tv; |
| 46610 | |
| 46611 | DUK_UNREF(heap); |
| 46612 | DUK_D(DUK_DPRINT("debug command PutVar" )); |
| 46613 | |
| 46614 | act = duk__debug_read_level_get_activation(thr); |
| 46615 | if (act == NULL) { |
| 46616 | return; |
| 46617 | } |
| 46618 | str = duk_debug_read_hstring(thr); /* push to stack */ |
| 46619 | DUK_ASSERT(str != NULL); |
| 46620 | tv = duk_debug_read_tval(thr); |
| 46621 | if (tv == NULL) { |
| 46622 | /* detached */ |
| 46623 | return; |
| 46624 | } |
| 46625 | |
| 46626 | duk_js_putvar_activation(thr, act, str, tv, 0); |
| 46627 | |
| 46628 | /* XXX: Current putvar implementation doesn't have a success flag, |
| 46629 | * add one and send to debug client? |
| 46630 | */ |
| 46631 | duk_debug_write_reply(thr); |
| 46632 | duk_debug_write_eom(thr); |
| 46633 | } |
| 46634 | |
| 46635 | DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) { |
| 46636 | duk_hthread *curr_thr = thr; |
| 46637 | duk_activation *curr_act; |
| 46638 | duk_uint_fast32_t pc; |
| 46639 | duk_uint_fast32_t line; |
| 46640 | |
| 46641 | DUK_ASSERT(thr != NULL); |
| 46642 | DUK_UNREF(heap); |
| 46643 | |
| 46644 | duk_debug_write_reply(thr); |
| 46645 | while (curr_thr != NULL) { |
| 46646 | for (curr_act = curr_thr->callstack_curr; curr_act != NULL; curr_act = curr_act->parent) { |
| 46647 | /* PC/line semantics here are: |
| 46648 | * - For callstack top we're conceptually between two |
| 46649 | * opcodes and current PC indicates next line to |
| 46650 | * execute, so report that (matches Status). |
| 46651 | * - For other activations we're conceptually still |
| 46652 | * executing the instruction at PC-1, so report that |
| 46653 | * (matches error stacktrace behavior). |
| 46654 | * - See: https://github.com/svaarala/duktape/issues/281 |
| 46655 | */ |
| 46656 | |
| 46657 | /* XXX: optimize to use direct reads, i.e. avoid |
| 46658 | * value stack operations. |
| 46659 | */ |
| 46660 | duk_push_tval(thr, &curr_act->tv_func); |
| 46661 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME); |
| 46662 | duk__debug_write_hstring_safe_top(thr); |
| 46663 | duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME); |
| 46664 | duk__debug_write_hstring_safe_top(thr); |
| 46665 | pc = duk_hthread_get_act_curr_pc(thr, curr_act); |
| 46666 | if (curr_act != curr_thr->callstack_curr && pc > 0) { |
| 46667 | pc--; |
| 46668 | } |
| 46669 | line = duk_hobject_pc2line_query(thr, -3, pc); |
| 46670 | duk_debug_write_uint(thr, (duk_uint32_t) line); |
| 46671 | duk_debug_write_uint(thr, (duk_uint32_t) pc); |
| 46672 | duk_pop_3(thr); |
| 46673 | } |
| 46674 | curr_thr = curr_thr->resumer; |
| 46675 | } |
| 46676 | /* SCANBUILD: warning about 'thr' potentially being NULL here, |
| 46677 | * warning is incorrect because thr != NULL always here. |
| 46678 | */ |
| 46679 | duk_debug_write_eom(thr); |
| 46680 | } |
| 46681 | |
| 46682 | DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) { |
| 46683 | duk_activation *act; |
| 46684 | duk_hstring *varname; |
| 46685 | |
| 46686 | DUK_UNREF(heap); |
| 46687 | |
| 46688 | act = duk__debug_read_level_get_activation(thr); |
| 46689 | if (act == NULL) { |
| 46690 | return; |
| 46691 | } |
| 46692 | |
| 46693 | duk_debug_write_reply(thr); |
| 46694 | |
| 46695 | /* XXX: several nice-to-have improvements here: |
| 46696 | * - Use direct reads avoiding value stack operations |
| 46697 | * - Avoid triggering getters, indicate getter values to debug client |
| 46698 | * - If side effects are possible, add error catching |
| 46699 | */ |
| 46700 | |
| 46701 | if (DUK_TVAL_IS_OBJECT(&act->tv_func)) { |
| 46702 | duk_hobject *h_func = DUK_TVAL_GET_OBJECT(&act->tv_func); |
| 46703 | duk_hobject *h_varmap; |
| 46704 | |
| 46705 | h_varmap = duk_hobject_get_varmap(thr, h_func); |
| 46706 | if (h_varmap != NULL) { |
| 46707 | duk_push_hobject(thr, h_varmap); |
| 46708 | duk_enum(thr, -1, 0 /*enum_flags*/); |
| 46709 | while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) { |
| 46710 | varname = duk_known_hstring(thr, -1); |
| 46711 | |
| 46712 | duk_js_getvar_activation(thr, act, varname, 0 /*throw_flag*/); |
| 46713 | /* [ ... func varmap enum key value this ] */ |
| 46714 | duk_debug_write_hstring(thr, duk_get_hstring(thr, -3)); |
| 46715 | duk_debug_write_tval(thr, duk_get_tval(thr, -2)); |
| 46716 | duk_pop_3(thr); /* -> [ ... func varmap enum ] */ |
| 46717 | } |
| 46718 | } else { |
| 46719 | DUK_D(DUK_DPRINT("varmap missing in GetLocals, ignore" )); |
| 46720 | } |
| 46721 | } else { |
| 46722 | DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore" )); |
| 46723 | } |
| 46724 | |
| 46725 | duk_debug_write_eom(thr); |
| 46726 | } |
| 46727 | |
| 46728 | DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) { |
| 46729 | duk_small_uint_t call_flags; |
| 46730 | duk_int_t call_ret; |
| 46731 | duk_small_int_t eval_err; |
| 46732 | duk_bool_t direct_eval; |
| 46733 | duk_int32_t level; |
| 46734 | duk_idx_t idx_func; |
| 46735 | |
| 46736 | DUK_UNREF(heap); |
| 46737 | |
| 46738 | DUK_D(DUK_DPRINT("debug command Eval" )); |
| 46739 | |
| 46740 | /* The eval code is executed within the lexical environment of a specified |
| 46741 | * activation. For now, use global object eval() function, with the eval |
| 46742 | * considered a 'direct call to eval'. |
| 46743 | * |
| 46744 | * Callstack index for debug commands only affects scope -- the callstack |
| 46745 | * as seen by, e.g. Duktape.act() will be the same regardless. |
| 46746 | */ |
| 46747 | |
| 46748 | /* nargs == 2 so we can pass a callstack index to eval(). */ |
| 46749 | idx_func = duk_get_top(thr); |
| 46750 | duk_push_c_function(thr, duk_bi_global_object_eval, 2 /*nargs*/); |
| 46751 | duk_push_undefined(thr); /* 'this' binding shouldn't matter here */ |
| 46752 | |
| 46753 | /* Read callstack index, if non-null. */ |
| 46754 | if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) { |
| 46755 | direct_eval = 0; |
| 46756 | level = -1; /* Not needed, but silences warning. */ |
| 46757 | (void) duk_debug_read_byte(thr); |
| 46758 | } else { |
| 46759 | direct_eval = 1; |
| 46760 | level = duk__debug_read_validate_csindex(thr); |
| 46761 | if (level == 0) { |
| 46762 | return; |
| 46763 | } |
| 46764 | } |
| 46765 | |
| 46766 | DUK_ASSERT(!direct_eval || |
| 46767 | (level < 0 && -level <= (duk_int32_t) thr->callstack_top)); |
| 46768 | |
| 46769 | (void) duk_debug_read_hstring(thr); |
| 46770 | if (direct_eval) { |
| 46771 | duk_push_int(thr, level - 1); /* compensate for eval() call */ |
| 46772 | } |
| 46773 | |
| 46774 | /* [ ... eval "eval" eval_input level? ] */ |
| 46775 | |
| 46776 | call_flags = 0; |
| 46777 | if (direct_eval) { |
| 46778 | duk_activation *act; |
| 46779 | duk_hobject *fun; |
| 46780 | |
| 46781 | act = duk_hthread_get_activation_for_level(thr, level); |
| 46782 | if (act != NULL) { |
| 46783 | fun = DUK_ACT_GET_FUNC(act); |
| 46784 | if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) { |
| 46785 | /* Direct eval requires that there's a current |
| 46786 | * activation and it is an ECMAScript function. |
| 46787 | * When Eval is executed from e.g. cooperate API |
| 46788 | * call we'll need to do an indirect eval instead. |
| 46789 | */ |
| 46790 | call_flags |= DUK_CALL_FLAG_DIRECT_EVAL; |
| 46791 | } |
| 46792 | } |
| 46793 | } |
| 46794 | |
| 46795 | call_ret = duk_pcall_method_flags(thr, duk_get_top(thr) - (idx_func + 2), call_flags); |
| 46796 | |
| 46797 | if (call_ret == DUK_EXEC_SUCCESS) { |
| 46798 | eval_err = 0; |
| 46799 | /* Use result value as is. */ |
| 46800 | } else { |
| 46801 | /* For errors a string coerced result is most informative |
| 46802 | * right now, as the debug client doesn't have the capability |
| 46803 | * to traverse the error object. |
| 46804 | */ |
| 46805 | eval_err = 1; |
| 46806 | duk_safe_to_string(thr, -1); |
| 46807 | } |
| 46808 | |
| 46809 | /* [ ... result ] */ |
| 46810 | |
| 46811 | duk_debug_write_reply(thr); |
| 46812 | duk_debug_write_int(thr, (duk_int32_t) eval_err); |
| 46813 | DUK_ASSERT(duk_get_tval(thr, -1) != NULL); |
| 46814 | duk_debug_write_tval(thr, duk_get_tval(thr, -1)); |
| 46815 | duk_debug_write_eom(thr); |
| 46816 | } |
| 46817 | |
| 46818 | DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) { |
| 46819 | DUK_UNREF(heap); |
| 46820 | DUK_D(DUK_DPRINT("debug command Detach" )); |
| 46821 | |
| 46822 | duk_debug_write_reply(thr); |
| 46823 | duk_debug_write_eom(thr); |
| 46824 | |
| 46825 | DUK_D(DUK_DPRINT("debug connection detached, mark broken" )); |
| 46826 | DUK__SET_CONN_BROKEN(thr, 0); /* not an error */ |
| 46827 | } |
| 46828 | |
| 46829 | DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) { |
| 46830 | duk_idx_t old_top; |
| 46831 | |
| 46832 | DUK_D(DUK_DPRINT("debug command AppRequest" )); |
| 46833 | |
| 46834 | old_top = duk_get_top(thr); /* save stack top */ |
| 46835 | |
| 46836 | if (heap->dbg_request_cb != NULL) { |
| 46837 | duk_idx_t nrets; |
| 46838 | duk_idx_t nvalues = 0; |
| 46839 | duk_idx_t top, idx; |
| 46840 | |
| 46841 | /* Read tvals from the message and push them onto the valstack, |
| 46842 | * then call the request callback to process the request. |
| 46843 | */ |
| 46844 | while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) { |
| 46845 | duk_tval *tv; |
| 46846 | if (!duk_check_stack(thr, 1)) { |
| 46847 | DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)" )); |
| 46848 | goto fail; |
| 46849 | } |
| 46850 | tv = duk_debug_read_tval(thr); /* push to stack */ |
| 46851 | if (tv == NULL) { |
| 46852 | /* detached */ |
| 46853 | return; |
| 46854 | } |
| 46855 | nvalues++; |
| 46856 | } |
| 46857 | DUK_ASSERT(duk_get_top(thr) == old_top + nvalues); |
| 46858 | |
| 46859 | /* Request callback should push values for reply to client onto valstack */ |
| 46860 | DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld" , |
| 46861 | (long) nvalues, (long) old_top, (long) duk_get_top(thr))); |
| 46862 | nrets = heap->dbg_request_cb(thr, heap->dbg_udata, nvalues); |
| 46863 | DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld" , |
| 46864 | (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(thr))); |
| 46865 | if (nrets >= 0) { |
| 46866 | DUK_ASSERT(duk_get_top(thr) >= old_top + nrets); |
| 46867 | if (duk_get_top(thr) < old_top + nrets) { |
| 46868 | DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, " |
| 46869 | "top=%ld < old_top=%ld + nrets=%ld; " |
| 46870 | "this might mean it's unsafe to continue!" , |
| 46871 | (long) duk_get_top(thr), (long) old_top, (long) nrets)); |
| 46872 | goto fail; |
| 46873 | } |
| 46874 | |
| 46875 | /* Reply with tvals pushed by request callback */ |
| 46876 | duk_debug_write_byte(thr, DUK_DBG_IB_REPLY); |
| 46877 | top = duk_get_top(thr); |
| 46878 | for (idx = top - nrets; idx < top; idx++) { |
| 46879 | duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(thr, idx)); |
| 46880 | } |
| 46881 | duk_debug_write_eom(thr); |
| 46882 | } else { |
| 46883 | DUK_ASSERT(duk_get_top(thr) >= old_top + 1); |
| 46884 | if (duk_get_top(thr) < old_top + 1) { |
| 46885 | DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration" )); |
| 46886 | goto fail; |
| 46887 | } |
| 46888 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(thr, -1)); |
| 46889 | } |
| 46890 | |
| 46891 | duk_set_top(thr, old_top); /* restore stack top */ |
| 46892 | } else { |
| 46893 | DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported" )); |
| 46894 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target" ); |
| 46895 | } |
| 46896 | |
| 46897 | return; |
| 46898 | |
| 46899 | fail: |
| 46900 | duk_set_top(thr, old_top); /* restore stack top */ |
| 46901 | DUK__SET_CONN_BROKEN(thr, 1); |
| 46902 | } |
| 46903 | |
| 46904 | /* |
| 46905 | * DumpHeap command |
| 46906 | */ |
| 46907 | |
| 46908 | #if defined(DUK_USE_DEBUGGER_DUMPHEAP) |
| 46909 | /* XXX: this has some overlap with object inspection; remove this and make |
| 46910 | * DumpHeap return lists of heapptrs instead? |
| 46911 | */ |
| 46912 | DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) { |
| 46913 | DUK_UNREF(heap); |
| 46914 | |
| 46915 | duk_debug_write_heapptr(thr, hdr); |
| 46916 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr)); |
| 46917 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr)); |
| 46918 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 46919 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr)); |
| 46920 | #else |
| 46921 | duk_debug_write_int(thr, (duk_int32_t) -1); |
| 46922 | #endif |
| 46923 | |
| 46924 | switch (DUK_HEAPHDR_GET_TYPE(hdr)) { |
| 46925 | case DUK_HTYPE_STRING: { |
| 46926 | duk_hstring *h = (duk_hstring *) hdr; |
| 46927 | |
| 46928 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_BYTELEN(h)); |
| 46929 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_CHARLEN(h)); |
| 46930 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); |
| 46931 | duk_debug_write_hstring(thr, h); |
| 46932 | break; |
| 46933 | } |
| 46934 | case DUK_HTYPE_OBJECT: { |
| 46935 | duk_hobject *h = (duk_hobject *) hdr; |
| 46936 | duk_hstring *k; |
| 46937 | duk_uint_fast32_t i; |
| 46938 | |
| 46939 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h)); |
| 46940 | duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); |
| 46941 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h)); |
| 46942 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h)); |
| 46943 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h)); |
| 46944 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h)); |
| 46945 | |
| 46946 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { |
| 46947 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i)); |
| 46948 | k = DUK_HOBJECT_E_GET_KEY(heap, h, i); |
| 46949 | duk_debug_write_heapptr(thr, (duk_heaphdr *) k); |
| 46950 | if (k == NULL) { |
| 46951 | duk_debug_write_int(thr, 0); /* isAccessor */ |
| 46952 | duk_debug_write_unused(thr); |
| 46953 | continue; |
| 46954 | } |
| 46955 | if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) { |
| 46956 | duk_debug_write_int(thr, 1); /* isAccessor */ |
| 46957 | duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get); |
| 46958 | duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set); |
| 46959 | } else { |
| 46960 | duk_debug_write_int(thr, 0); /* isAccessor */ |
| 46961 | |
| 46962 | duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v); |
| 46963 | } |
| 46964 | } |
| 46965 | |
| 46966 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { |
| 46967 | /* Note: array dump will include elements beyond |
| 46968 | * 'length'. |
| 46969 | */ |
| 46970 | duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); |
| 46971 | } |
| 46972 | break; |
| 46973 | } |
| 46974 | case DUK_HTYPE_BUFFER: { |
| 46975 | duk_hbuffer *h = (duk_hbuffer *) hdr; |
| 46976 | |
| 46977 | duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h)); |
| 46978 | duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h)); |
| 46979 | break; |
| 46980 | } |
| 46981 | default: { |
| 46982 | DUK_D(DUK_DPRINT("invalid htype: %d" , (int) DUK_HEAPHDR_GET_TYPE(hdr))); |
| 46983 | } |
| 46984 | } |
| 46985 | } |
| 46986 | |
| 46987 | DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) { |
| 46988 | duk_heaphdr *hdr; |
| 46989 | |
| 46990 | hdr = heap->heap_allocated; |
| 46991 | while (hdr != NULL) { |
| 46992 | duk__debug_dump_heaphdr(thr, heap, hdr); |
| 46993 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 46994 | } |
| 46995 | } |
| 46996 | |
| 46997 | DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) { |
| 46998 | duk_uint32_t i; |
| 46999 | duk_hstring *h; |
| 47000 | |
| 47001 | for (i = 0; i < heap->st_size; i++) { |
| 47002 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 47003 | h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]); |
| 47004 | #else |
| 47005 | h = heap->strtable[i]; |
| 47006 | #endif |
| 47007 | while (h != NULL) { |
| 47008 | duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h); |
| 47009 | h = h->hdr.h_next; |
| 47010 | } |
| 47011 | } |
| 47012 | } |
| 47013 | |
| 47014 | DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) { |
| 47015 | DUK_D(DUK_DPRINT("debug command DumpHeap" )); |
| 47016 | |
| 47017 | duk_debug_write_reply(thr); |
| 47018 | duk__debug_dump_heap_allocated(thr, heap); |
| 47019 | duk__debug_dump_strtab(thr, heap); |
| 47020 | duk_debug_write_eom(thr); |
| 47021 | } |
| 47022 | #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ |
| 47023 | |
| 47024 | DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) { |
| 47025 | duk_activation *act; |
| 47026 | duk_hcompfunc *fun = NULL; |
| 47027 | duk_size_t i, n; |
| 47028 | duk_tval *tv; |
| 47029 | duk_hobject **fn; |
| 47030 | duk_int32_t level = -1; |
| 47031 | duk_uint8_t ibyte; |
| 47032 | |
| 47033 | DUK_UNREF(heap); |
| 47034 | |
| 47035 | DUK_D(DUK_DPRINT("debug command GetBytecode" )); |
| 47036 | |
| 47037 | ibyte = duk_debug_peek_byte(thr); |
| 47038 | if (ibyte != DUK_DBG_IB_EOM) { |
| 47039 | tv = duk_debug_read_tval(thr); |
| 47040 | if (tv == NULL) { |
| 47041 | /* detached */ |
| 47042 | return; |
| 47043 | } |
| 47044 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 47045 | /* tentative, checked later */ |
| 47046 | fun = (duk_hcompfunc *) DUK_TVAL_GET_OBJECT(tv); |
| 47047 | DUK_ASSERT(fun != NULL); |
| 47048 | } else if (DUK_TVAL_IS_NUMBER(tv)) { |
| 47049 | level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv); |
| 47050 | } else { |
| 47051 | DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T" , tv)); |
| 47052 | goto fail_args; |
| 47053 | } |
| 47054 | } |
| 47055 | |
| 47056 | if (fun == NULL) { |
| 47057 | act = duk_hthread_get_activation_for_level(thr, level); |
| 47058 | if (act == NULL) { |
| 47059 | goto fail_index; |
| 47060 | } |
| 47061 | fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); |
| 47062 | } |
| 47063 | |
| 47064 | if (fun == NULL || !DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)) { |
| 47065 | DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O" , fun)); |
| 47066 | goto fail_args; |
| 47067 | } |
| 47068 | DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)); |
| 47069 | |
| 47070 | duk_debug_write_reply(thr); |
| 47071 | n = DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap, fun); |
| 47072 | duk_debug_write_int(thr, (duk_int32_t) n); |
| 47073 | tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, fun); |
| 47074 | for (i = 0; i < n; i++) { |
| 47075 | duk_debug_write_tval(thr, tv); |
| 47076 | tv++; |
| 47077 | } |
| 47078 | n = DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap, fun); |
| 47079 | duk_debug_write_int(thr, (duk_int32_t) n); |
| 47080 | fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, fun); |
| 47081 | for (i = 0; i < n; i++) { |
| 47082 | duk_debug_write_hobject(thr, *fn); |
| 47083 | fn++; |
| 47084 | } |
| 47085 | duk_debug_write_string(thr, |
| 47086 | (const char *) DUK_HCOMPFUNC_GET_CODE_BASE(heap, fun), |
| 47087 | (duk_size_t) DUK_HCOMPFUNC_GET_CODE_SIZE(heap, fun)); |
| 47088 | duk_debug_write_eom(thr); |
| 47089 | return; |
| 47090 | |
| 47091 | fail_args: |
| 47092 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument" ); |
| 47093 | return; |
| 47094 | |
| 47095 | fail_index: |
| 47096 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index" ); |
| 47097 | return; |
| 47098 | } |
| 47099 | |
| 47100 | /* |
| 47101 | * Object inspection commands: GetHeapObjInfo, GetObjPropDesc, |
| 47102 | * GetObjPropDescRange |
| 47103 | */ |
| 47104 | |
| 47105 | #if defined(DUK_USE_DEBUGGER_INSPECT) |
| 47106 | |
| 47107 | #if 0 /* pruned */ |
| 47108 | DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = { |
| 47109 | "reachable" , |
| 47110 | "temproot" , |
| 47111 | "finalizable" , |
| 47112 | "finalized" , |
| 47113 | "readonly" |
| 47114 | /* NULL not needed here */ |
| 47115 | }; |
| 47116 | DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = { |
| 47117 | DUK_HEAPHDR_FLAG_REACHABLE, |
| 47118 | DUK_HEAPHDR_FLAG_TEMPROOT, |
| 47119 | DUK_HEAPHDR_FLAG_FINALIZABLE, |
| 47120 | DUK_HEAPHDR_FLAG_FINALIZED, |
| 47121 | DUK_HEAPHDR_FLAG_READONLY, |
| 47122 | 0 /* terminator */ |
| 47123 | }; |
| 47124 | #endif |
| 47125 | DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = { |
| 47126 | #if 0 |
| 47127 | "arridx" , |
| 47128 | "symbol" , |
| 47129 | "hidden" , |
| 47130 | "reserved_word" , |
| 47131 | "strict_reserved_word" , |
| 47132 | "eval_or_arguments" , |
| 47133 | #endif |
| 47134 | "extdata" |
| 47135 | /* NULL not needed here */ |
| 47136 | }; |
| 47137 | DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = { |
| 47138 | #if 0 |
| 47139 | DUK_HSTRING_FLAG_ARRIDX, |
| 47140 | DUK_HSTRING_FLAG_SYMBOL, |
| 47141 | DUK_HSTRING_FLAG_HIDDEN, |
| 47142 | DUK_HSTRING_FLAG_RESERVED_WORD, |
| 47143 | DUK_HSTRING_FLAG_STRICT_RESERVED_WORD, |
| 47144 | DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS, |
| 47145 | #endif |
| 47146 | DUK_HSTRING_FLAG_EXTDATA, |
| 47147 | 0 /* terminator */ |
| 47148 | }; |
| 47149 | DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = { |
| 47150 | "extensible" , |
| 47151 | "constructable" , |
| 47152 | "callable" , |
| 47153 | "boundfunc" , |
| 47154 | "compfunc" , |
| 47155 | "natfunc" , |
| 47156 | "bufobj" , |
| 47157 | "fastrefs" , |
| 47158 | "array_part" , |
| 47159 | "strict" , |
| 47160 | "notail" , |
| 47161 | "newenv" , |
| 47162 | "namebinding" , |
| 47163 | "createargs" , |
| 47164 | "have_finalizer" , |
| 47165 | "exotic_array" , |
| 47166 | "exotic_stringobj" , |
| 47167 | "exotic_arguments" , |
| 47168 | "exotic_proxyobj" , |
| 47169 | "special_call" |
| 47170 | /* NULL not needed here */ |
| 47171 | }; |
| 47172 | DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = { |
| 47173 | DUK_HOBJECT_FLAG_EXTENSIBLE, |
| 47174 | DUK_HOBJECT_FLAG_CONSTRUCTABLE, |
| 47175 | DUK_HOBJECT_FLAG_CALLABLE, |
| 47176 | DUK_HOBJECT_FLAG_BOUNDFUNC, |
| 47177 | DUK_HOBJECT_FLAG_COMPFUNC, |
| 47178 | DUK_HOBJECT_FLAG_NATFUNC, |
| 47179 | DUK_HOBJECT_FLAG_BUFOBJ, |
| 47180 | DUK_HOBJECT_FLAG_FASTREFS, |
| 47181 | DUK_HOBJECT_FLAG_ARRAY_PART, |
| 47182 | DUK_HOBJECT_FLAG_STRICT, |
| 47183 | DUK_HOBJECT_FLAG_NOTAIL, |
| 47184 | DUK_HOBJECT_FLAG_NEWENV, |
| 47185 | DUK_HOBJECT_FLAG_NAMEBINDING, |
| 47186 | DUK_HOBJECT_FLAG_CREATEARGS, |
| 47187 | DUK_HOBJECT_FLAG_HAVE_FINALIZER, |
| 47188 | DUK_HOBJECT_FLAG_EXOTIC_ARRAY, |
| 47189 | DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ, |
| 47190 | DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS, |
| 47191 | DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ, |
| 47192 | DUK_HOBJECT_FLAG_SPECIAL_CALL, |
| 47193 | 0 /* terminator */ |
| 47194 | }; |
| 47195 | DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = { |
| 47196 | "dynamic" , |
| 47197 | "external" |
| 47198 | /* NULL not needed here */ |
| 47199 | }; |
| 47200 | DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = { |
| 47201 | DUK_HBUFFER_FLAG_DYNAMIC, |
| 47202 | DUK_HBUFFER_FLAG_EXTERNAL, |
| 47203 | 0 /* terminator */ |
| 47204 | }; |
| 47205 | |
| 47206 | DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) { |
| 47207 | duk_debug_write_uint(thr, 0); |
| 47208 | duk_debug_write_cstring(thr, key); |
| 47209 | } |
| 47210 | |
| 47211 | DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) { |
| 47212 | duk_debug_write_uint(thr, 0); |
| 47213 | duk_debug_write_cstring(thr, key); |
| 47214 | duk_debug_write_uint(thr, val); |
| 47215 | } |
| 47216 | |
| 47217 | DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) { |
| 47218 | duk_debug_write_uint(thr, 0); |
| 47219 | duk_debug_write_cstring(thr, key); |
| 47220 | duk_debug_write_int(thr, val); |
| 47221 | } |
| 47222 | |
| 47223 | DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) { |
| 47224 | duk_debug_write_uint(thr, 0); |
| 47225 | duk_debug_write_cstring(thr, key); |
| 47226 | duk_debug_write_boolean(thr, val); |
| 47227 | } |
| 47228 | |
| 47229 | DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) { |
| 47230 | const char *key; |
| 47231 | duk_uint_t mask; |
| 47232 | |
| 47233 | for (;;) { |
| 47234 | mask = *masks++; |
| 47235 | if (mask == 0) { |
| 47236 | break; |
| 47237 | } |
| 47238 | key = *keys++; |
| 47239 | DUK_ASSERT(key != NULL); |
| 47240 | |
| 47241 | DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx" , key, (unsigned long) mask, (unsigned long) flags)); |
| 47242 | duk__debug_getinfo_prop_bool(thr, key, flags & mask); |
| 47243 | } |
| 47244 | } |
| 47245 | |
| 47246 | /* Inspect a property using a virtual index into a conceptual property list |
| 47247 | * consisting of (1) all array part items from [0,a_size[ (even when above |
| 47248 | * .length) and (2) all entry part items from [0,e_next[. Unused slots are |
| 47249 | * indicated using dvalue 'unused'. |
| 47250 | */ |
| 47251 | DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) { |
| 47252 | duk_uint_t a_size; |
| 47253 | duk_tval *tv; |
| 47254 | duk_hstring *h_key; |
| 47255 | duk_hobject *h_getset; |
| 47256 | duk_uint_t flags; |
| 47257 | |
| 47258 | DUK_UNREF(heap); |
| 47259 | |
| 47260 | a_size = DUK_HOBJECT_GET_ASIZE(h_obj); |
| 47261 | if (idx < a_size) { |
| 47262 | duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC); |
| 47263 | duk_debug_write_uint(thr, idx); |
| 47264 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx); |
| 47265 | duk_debug_write_tval(thr, tv); |
| 47266 | return 1; |
| 47267 | } |
| 47268 | |
| 47269 | idx -= a_size; |
| 47270 | if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) { |
| 47271 | return 0; |
| 47272 | } |
| 47273 | |
| 47274 | h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx); |
| 47275 | if (h_key == NULL) { |
| 47276 | duk_debug_write_uint(thr, 0); |
| 47277 | duk_debug_write_null(thr); |
| 47278 | duk_debug_write_unused(thr); |
| 47279 | return 1; |
| 47280 | } |
| 47281 | |
| 47282 | flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx); |
| 47283 | if (DUK_HSTRING_HAS_SYMBOL(h_key)) { |
| 47284 | flags |= DUK_DBG_PROPFLAG_SYMBOL; |
| 47285 | } |
| 47286 | if (DUK_HSTRING_HAS_HIDDEN(h_key)) { |
| 47287 | flags |= DUK_DBG_PROPFLAG_HIDDEN; |
| 47288 | } |
| 47289 | duk_debug_write_uint(thr, flags); |
| 47290 | duk_debug_write_hstring(thr, h_key); |
| 47291 | if (flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 47292 | h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx); |
| 47293 | if (h_getset) { |
| 47294 | duk_debug_write_hobject(thr, h_getset); |
| 47295 | } else { |
| 47296 | duk_debug_write_null(thr); |
| 47297 | } |
| 47298 | h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx); |
| 47299 | if (h_getset) { |
| 47300 | duk_debug_write_hobject(thr, h_getset); |
| 47301 | } else { |
| 47302 | duk_debug_write_null(thr); |
| 47303 | } |
| 47304 | } else { |
| 47305 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx); |
| 47306 | duk_debug_write_tval(thr, tv); |
| 47307 | } |
| 47308 | return 1; |
| 47309 | } |
| 47310 | |
| 47311 | DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) { |
| 47312 | duk_heaphdr *h; |
| 47313 | |
| 47314 | DUK_D(DUK_DPRINT("debug command GetHeapObjInfo" )); |
| 47315 | DUK_UNREF(heap); |
| 47316 | |
| 47317 | DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1); |
| 47318 | DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1); |
| 47319 | DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1); |
| 47320 | |
| 47321 | h = duk_debug_read_any_ptr(thr); |
| 47322 | if (!h) { |
| 47323 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target" ); |
| 47324 | return; |
| 47325 | } |
| 47326 | |
| 47327 | duk_debug_write_reply(thr); |
| 47328 | |
| 47329 | /* As with all inspection code, we rely on the debug client providing |
| 47330 | * a valid, non-stale pointer: there's no portable way to safely |
| 47331 | * validate the pointer here. |
| 47332 | */ |
| 47333 | |
| 47334 | duk__debug_getinfo_flags_key(thr, "heapptr" ); |
| 47335 | duk_debug_write_heapptr(thr, h); |
| 47336 | |
| 47337 | /* XXX: comes out as signed now */ |
| 47338 | duk__debug_getinfo_prop_uint(thr, "heaphdr_flags" , (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h)); |
| 47339 | duk__debug_getinfo_prop_uint(thr, "heaphdr_type" , (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h)); |
| 47340 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 47341 | duk__debug_getinfo_prop_uint(thr, "refcount" , (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h)); |
| 47342 | #endif |
| 47343 | #if 0 /* pruned */ |
| 47344 | duk__debug_getinfo_bitmask(thr, |
| 47345 | duk__debug_getinfo_heaphdr_keys, |
| 47346 | duk__debug_getinfo_heaphdr_masks, |
| 47347 | DUK_HEAPHDR_GET_FLAGS_RAW(h)); |
| 47348 | #endif |
| 47349 | |
| 47350 | switch (DUK_HEAPHDR_GET_TYPE(h)) { |
| 47351 | case DUK_HTYPE_STRING: { |
| 47352 | duk_hstring *h_str; |
| 47353 | |
| 47354 | h_str = (duk_hstring *) h; |
| 47355 | duk__debug_getinfo_bitmask(thr, |
| 47356 | duk__debug_getinfo_hstring_keys, |
| 47357 | duk__debug_getinfo_hstring_masks, |
| 47358 | DUK_HEAPHDR_GET_FLAGS_RAW(h)); |
| 47359 | duk__debug_getinfo_prop_uint(thr, "bytelen" , (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str)); |
| 47360 | duk__debug_getinfo_prop_uint(thr, "charlen" , (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str)); |
| 47361 | duk__debug_getinfo_prop_uint(thr, "hash" , (duk_uint_t) DUK_HSTRING_GET_HASH(h_str)); |
| 47362 | duk__debug_getinfo_flags_key(thr, "data" ); |
| 47363 | duk_debug_write_hstring(thr, h_str); |
| 47364 | break; |
| 47365 | } |
| 47366 | case DUK_HTYPE_OBJECT: { |
| 47367 | duk_hobject *h_obj; |
| 47368 | duk_hobject *h_proto; |
| 47369 | |
| 47370 | h_obj = (duk_hobject *) h; |
| 47371 | h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj); |
| 47372 | |
| 47373 | /* duk_hobject specific fields. */ |
| 47374 | duk__debug_getinfo_bitmask(thr, |
| 47375 | duk__debug_getinfo_hobject_keys, |
| 47376 | duk__debug_getinfo_hobject_masks, |
| 47377 | DUK_HEAPHDR_GET_FLAGS_RAW(h)); |
| 47378 | duk__debug_getinfo_prop_uint(thr, "class_number" , DUK_HOBJECT_GET_CLASS_NUMBER(h_obj)); |
| 47379 | duk__debug_getinfo_flags_key(thr, "class_name" ); |
| 47380 | duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj)); |
| 47381 | duk__debug_getinfo_flags_key(thr, "prototype" ); |
| 47382 | if (h_proto != NULL) { |
| 47383 | duk_debug_write_hobject(thr, h_proto); |
| 47384 | } else { |
| 47385 | duk_debug_write_null(thr); |
| 47386 | } |
| 47387 | duk__debug_getinfo_flags_key(thr, "props" ); |
| 47388 | duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj)); |
| 47389 | duk__debug_getinfo_prop_uint(thr, "e_size" , (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj)); |
| 47390 | duk__debug_getinfo_prop_uint(thr, "e_next" , (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj)); |
| 47391 | duk__debug_getinfo_prop_uint(thr, "a_size" , (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj)); |
| 47392 | duk__debug_getinfo_prop_uint(thr, "h_size" , (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj)); |
| 47393 | |
| 47394 | if (DUK_HOBJECT_IS_ARRAY(h_obj)) { |
| 47395 | duk_harray *h_arr; |
| 47396 | h_arr = (duk_harray *) h_obj; |
| 47397 | |
| 47398 | duk__debug_getinfo_prop_uint(thr, "length" , (duk_uint_t) h_arr->length); |
| 47399 | duk__debug_getinfo_prop_bool(thr, "length_nonwritable" , h_arr->length_nonwritable); |
| 47400 | } |
| 47401 | |
| 47402 | if (DUK_HOBJECT_IS_NATFUNC(h_obj)) { |
| 47403 | duk_hnatfunc *h_fun; |
| 47404 | h_fun = (duk_hnatfunc *) h_obj; |
| 47405 | |
| 47406 | duk__debug_getinfo_prop_int(thr, "nargs" , h_fun->nargs); |
| 47407 | duk__debug_getinfo_prop_int(thr, "magic" , h_fun->magic); |
| 47408 | duk__debug_getinfo_prop_bool(thr, "varargs" , h_fun->magic == DUK_HNATFUNC_NARGS_VARARGS); |
| 47409 | /* Native function pointer may be different from a void pointer, |
| 47410 | * and we serialize it from memory directly now (no byte swapping etc). |
| 47411 | */ |
| 47412 | duk__debug_getinfo_flags_key(thr, "funcptr" ); |
| 47413 | duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func)); |
| 47414 | } |
| 47415 | |
| 47416 | if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { |
| 47417 | duk_hcompfunc *h_fun; |
| 47418 | duk_hbuffer *h_buf; |
| 47419 | duk_hobject *h_lexenv; |
| 47420 | duk_hobject *h_varenv; |
| 47421 | h_fun = (duk_hcompfunc *) h_obj; |
| 47422 | |
| 47423 | duk__debug_getinfo_prop_int(thr, "nregs" , h_fun->nregs); |
| 47424 | duk__debug_getinfo_prop_int(thr, "nargs" , h_fun->nargs); |
| 47425 | |
| 47426 | duk__debug_getinfo_flags_key(thr, "lex_env" ); |
| 47427 | h_lexenv = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, h_fun); |
| 47428 | if (h_lexenv != NULL) { |
| 47429 | duk_debug_write_hobject(thr, h_lexenv); |
| 47430 | } else { |
| 47431 | duk_debug_write_null(thr); |
| 47432 | } |
| 47433 | duk__debug_getinfo_flags_key(thr, "var_env" ); |
| 47434 | h_varenv = DUK_HCOMPFUNC_GET_VARENV(thr->heap, h_fun); |
| 47435 | if (h_varenv != NULL) { |
| 47436 | duk_debug_write_hobject(thr, h_varenv); |
| 47437 | } else { |
| 47438 | duk_debug_write_null(thr); |
| 47439 | } |
| 47440 | |
| 47441 | duk__debug_getinfo_prop_uint(thr, "start_line" , h_fun->start_line); |
| 47442 | duk__debug_getinfo_prop_uint(thr, "end_line" , h_fun->end_line); |
| 47443 | h_buf = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun); |
| 47444 | if (h_buf != NULL) { |
| 47445 | duk__debug_getinfo_flags_key(thr, "data" ); |
| 47446 | duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf); |
| 47447 | } |
| 47448 | } |
| 47449 | |
| 47450 | if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) { |
| 47451 | duk_hboundfunc *h_bfun; |
| 47452 | h_bfun = (duk_hboundfunc *) (void *) h_obj; |
| 47453 | |
| 47454 | duk__debug_getinfo_flags_key(thr, "target" ); |
| 47455 | duk_debug_write_tval(thr, &h_bfun->target); |
| 47456 | duk__debug_getinfo_flags_key(thr, "this_binding" ); |
| 47457 | duk_debug_write_tval(thr, &h_bfun->this_binding); |
| 47458 | duk__debug_getinfo_flags_key(thr, "nargs" ); |
| 47459 | duk_debug_write_int(thr, h_bfun->nargs); |
| 47460 | /* h_bfun->args not exposed now */ |
| 47461 | } |
| 47462 | |
| 47463 | if (DUK_HOBJECT_IS_THREAD(h_obj)) { |
| 47464 | /* XXX: Currently no inspection of threads, e.g. value stack, call |
| 47465 | * stack, catch stack, etc. |
| 47466 | */ |
| 47467 | duk_hthread *h_thr; |
| 47468 | h_thr = (duk_hthread *) h_obj; |
| 47469 | DUK_UNREF(h_thr); |
| 47470 | } |
| 47471 | |
| 47472 | if (DUK_HOBJECT_IS_DECENV(h_obj)) { |
| 47473 | duk_hdecenv *h_env; |
| 47474 | h_env = (duk_hdecenv *) h_obj; |
| 47475 | |
| 47476 | duk__debug_getinfo_flags_key(thr, "thread" ); |
| 47477 | duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread)); |
| 47478 | duk__debug_getinfo_flags_key(thr, "varmap" ); |
| 47479 | duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap)); |
| 47480 | duk__debug_getinfo_prop_uint(thr, "regbase" , (duk_uint_t) h_env->regbase_byteoff); |
| 47481 | } |
| 47482 | |
| 47483 | if (DUK_HOBJECT_IS_OBJENV(h_obj)) { |
| 47484 | duk_hobjenv *h_env; |
| 47485 | h_env = (duk_hobjenv *) h_obj; |
| 47486 | |
| 47487 | duk__debug_getinfo_flags_key(thr, "target" ); |
| 47488 | duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target)); |
| 47489 | duk__debug_getinfo_prop_bool(thr, "has_this" , h_env->has_this); |
| 47490 | } |
| 47491 | |
| 47492 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 47493 | if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { |
| 47494 | duk_hbufobj *h_bufobj; |
| 47495 | h_bufobj = (duk_hbufobj *) h_obj; |
| 47496 | |
| 47497 | duk__debug_getinfo_prop_uint(thr, "slice_offset" , h_bufobj->offset); |
| 47498 | duk__debug_getinfo_prop_uint(thr, "slice_length" , h_bufobj->length); |
| 47499 | duk__debug_getinfo_prop_uint(thr, "elem_shift" , (duk_uint_t) h_bufobj->shift); |
| 47500 | duk__debug_getinfo_prop_uint(thr, "elem_type" , (duk_uint_t) h_bufobj->elem_type); |
| 47501 | duk__debug_getinfo_prop_bool(thr, "is_typedarray" , (duk_uint_t) h_bufobj->is_typedarray); |
| 47502 | if (h_bufobj->buf != NULL) { |
| 47503 | duk__debug_getinfo_flags_key(thr, "buffer" ); |
| 47504 | duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf); |
| 47505 | } |
| 47506 | } |
| 47507 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 47508 | break; |
| 47509 | } |
| 47510 | case DUK_HTYPE_BUFFER: { |
| 47511 | duk_hbuffer *h_buf; |
| 47512 | |
| 47513 | h_buf = (duk_hbuffer *) h; |
| 47514 | duk__debug_getinfo_bitmask(thr, |
| 47515 | duk__debug_getinfo_hbuffer_keys, |
| 47516 | duk__debug_getinfo_hbuffer_masks, |
| 47517 | DUK_HEAPHDR_GET_FLAGS_RAW(h)); |
| 47518 | duk__debug_getinfo_prop_uint(thr, "size" , (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf)); |
| 47519 | duk__debug_getinfo_flags_key(thr, "dataptr" ); |
| 47520 | duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf)); |
| 47521 | duk__debug_getinfo_flags_key(thr, "data" ); |
| 47522 | duk_debug_write_hbuffer(thr, h_buf); /* tolerates NULL h_buf */ |
| 47523 | break; |
| 47524 | } |
| 47525 | default: { |
| 47526 | /* Since we already started writing the reply, just emit nothing. */ |
| 47527 | DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type" )); |
| 47528 | } |
| 47529 | } |
| 47530 | |
| 47531 | duk_debug_write_eom(thr); |
| 47532 | } |
| 47533 | |
| 47534 | DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) { |
| 47535 | duk_heaphdr *h; |
| 47536 | duk_hobject *h_obj; |
| 47537 | duk_hstring *h_key; |
| 47538 | duk_propdesc desc; |
| 47539 | |
| 47540 | DUK_D(DUK_DPRINT("debug command GetObjPropDesc" )); |
| 47541 | DUK_UNREF(heap); |
| 47542 | |
| 47543 | h = duk_debug_read_any_ptr(thr); |
| 47544 | if (!h) { |
| 47545 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target" ); |
| 47546 | return; |
| 47547 | } |
| 47548 | h_key = duk_debug_read_hstring(thr); |
| 47549 | if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) { |
| 47550 | goto fail_args; |
| 47551 | } |
| 47552 | h_obj = (duk_hobject *) h; |
| 47553 | |
| 47554 | if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) { |
| 47555 | duk_int_t virtual_idx; |
| 47556 | duk_bool_t rc; |
| 47557 | |
| 47558 | /* To use the shared helper need the virtual index. */ |
| 47559 | DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0); |
| 47560 | virtual_idx = (desc.a_idx >= 0 ? desc.a_idx : |
| 47561 | (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx); |
| 47562 | |
| 47563 | duk_debug_write_reply(thr); |
| 47564 | rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx); |
| 47565 | DUK_ASSERT(rc == 1); |
| 47566 | DUK_UNREF(rc); |
| 47567 | duk_debug_write_eom(thr); |
| 47568 | } else { |
| 47569 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found" ); |
| 47570 | } |
| 47571 | return; |
| 47572 | |
| 47573 | fail_args: |
| 47574 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args" ); |
| 47575 | } |
| 47576 | |
| 47577 | DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) { |
| 47578 | duk_heaphdr *h; |
| 47579 | duk_hobject *h_obj; |
| 47580 | duk_uint_t idx, idx_start, idx_end; |
| 47581 | |
| 47582 | DUK_D(DUK_DPRINT("debug command GetObjPropDescRange" )); |
| 47583 | DUK_UNREF(heap); |
| 47584 | |
| 47585 | h = duk_debug_read_any_ptr(thr); |
| 47586 | idx_start = (duk_uint_t) duk_debug_read_int(thr); |
| 47587 | idx_end = (duk_uint_t) duk_debug_read_int(thr); |
| 47588 | if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) { |
| 47589 | goto fail_args; |
| 47590 | } |
| 47591 | h_obj = (duk_hobject *) h; |
| 47592 | |
| 47593 | /* The index range space is conceptually the array part followed by the |
| 47594 | * entry part. Unlike normal enumeration all slots are exposed here as |
| 47595 | * is and return 'unused' if the slots are not in active use. In particular |
| 47596 | * the array part is included for the full a_size regardless of what the |
| 47597 | * array .length is. |
| 47598 | */ |
| 47599 | |
| 47600 | duk_debug_write_reply(thr); |
| 47601 | for (idx = idx_start; idx < idx_end; idx++) { |
| 47602 | if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) { |
| 47603 | break; |
| 47604 | } |
| 47605 | } |
| 47606 | duk_debug_write_eom(thr); |
| 47607 | return; |
| 47608 | |
| 47609 | fail_args: |
| 47610 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args" ); |
| 47611 | } |
| 47612 | |
| 47613 | #endif /* DUK_USE_DEBUGGER_INSPECT */ |
| 47614 | |
| 47615 | /* |
| 47616 | * Process incoming debug requests |
| 47617 | * |
| 47618 | * Individual request handlers can push temporaries on the value stack and |
| 47619 | * rely on duk__debug_process_message() to restore the value stack top |
| 47620 | * automatically. |
| 47621 | */ |
| 47622 | |
| 47623 | /* Process one debug message. Automatically restore value stack top to its |
| 47624 | * entry value, so that individual message handlers don't need exact value |
| 47625 | * stack handling which is convenient. |
| 47626 | */ |
| 47627 | DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) { |
| 47628 | duk_heap *heap; |
| 47629 | duk_uint8_t x; |
| 47630 | duk_int32_t cmd; |
| 47631 | duk_idx_t entry_top; |
| 47632 | |
| 47633 | DUK_ASSERT(thr != NULL); |
| 47634 | heap = thr->heap; |
| 47635 | DUK_ASSERT(heap != NULL); |
| 47636 | |
| 47637 | entry_top = duk_get_top(thr); |
| 47638 | |
| 47639 | x = duk_debug_read_byte(thr); |
| 47640 | switch (x) { |
| 47641 | case DUK_DBG_IB_REQUEST: { |
| 47642 | cmd = duk_debug_read_int(thr); |
| 47643 | switch (cmd) { |
| 47644 | case DUK_DBG_CMD_BASICINFO: { |
| 47645 | duk__debug_handle_basic_info(thr, heap); |
| 47646 | break; |
| 47647 | } |
| 47648 | case DUK_DBG_CMD_TRIGGERSTATUS: { |
| 47649 | duk__debug_handle_trigger_status(thr, heap); |
| 47650 | break; |
| 47651 | } |
| 47652 | case DUK_DBG_CMD_PAUSE: { |
| 47653 | duk__debug_handle_pause(thr, heap); |
| 47654 | break; |
| 47655 | } |
| 47656 | case DUK_DBG_CMD_RESUME: { |
| 47657 | duk__debug_handle_resume(thr, heap); |
| 47658 | break; |
| 47659 | } |
| 47660 | case DUK_DBG_CMD_STEPINTO: |
| 47661 | case DUK_DBG_CMD_STEPOVER: |
| 47662 | case DUK_DBG_CMD_STEPOUT: { |
| 47663 | duk__debug_handle_step(thr, heap, cmd); |
| 47664 | break; |
| 47665 | } |
| 47666 | case DUK_DBG_CMD_LISTBREAK: { |
| 47667 | duk__debug_handle_list_break(thr, heap); |
| 47668 | break; |
| 47669 | } |
| 47670 | case DUK_DBG_CMD_ADDBREAK: { |
| 47671 | duk__debug_handle_add_break(thr, heap); |
| 47672 | break; |
| 47673 | } |
| 47674 | case DUK_DBG_CMD_DELBREAK: { |
| 47675 | duk__debug_handle_del_break(thr, heap); |
| 47676 | break; |
| 47677 | } |
| 47678 | case DUK_DBG_CMD_GETVAR: { |
| 47679 | duk__debug_handle_get_var(thr, heap); |
| 47680 | break; |
| 47681 | } |
| 47682 | case DUK_DBG_CMD_PUTVAR: { |
| 47683 | duk__debug_handle_put_var(thr, heap); |
| 47684 | break; |
| 47685 | } |
| 47686 | case DUK_DBG_CMD_GETCALLSTACK: { |
| 47687 | duk__debug_handle_get_call_stack(thr, heap); |
| 47688 | break; |
| 47689 | } |
| 47690 | case DUK_DBG_CMD_GETLOCALS: { |
| 47691 | duk__debug_handle_get_locals(thr, heap); |
| 47692 | break; |
| 47693 | } |
| 47694 | case DUK_DBG_CMD_EVAL: { |
| 47695 | duk__debug_handle_eval(thr, heap); |
| 47696 | break; |
| 47697 | } |
| 47698 | case DUK_DBG_CMD_DETACH: { |
| 47699 | /* The actual detached_cb call is postponed to message loop so |
| 47700 | * we don't need any special precautions here (just skip to EOM |
| 47701 | * on the already closed connection). |
| 47702 | */ |
| 47703 | duk__debug_handle_detach(thr, heap); |
| 47704 | break; |
| 47705 | } |
| 47706 | #if defined(DUK_USE_DEBUGGER_DUMPHEAP) |
| 47707 | case DUK_DBG_CMD_DUMPHEAP: { |
| 47708 | duk__debug_handle_dump_heap(thr, heap); |
| 47709 | break; |
| 47710 | } |
| 47711 | #endif /* DUK_USE_DEBUGGER_DUMPHEAP */ |
| 47712 | case DUK_DBG_CMD_GETBYTECODE: { |
| 47713 | duk__debug_handle_get_bytecode(thr, heap); |
| 47714 | break; |
| 47715 | } |
| 47716 | case DUK_DBG_CMD_APPREQUEST: { |
| 47717 | duk__debug_handle_apprequest(thr, heap); |
| 47718 | break; |
| 47719 | } |
| 47720 | #if defined(DUK_USE_DEBUGGER_INSPECT) |
| 47721 | case DUK_DBG_CMD_GETHEAPOBJINFO: { |
| 47722 | duk__debug_handle_get_heap_obj_info(thr, heap); |
| 47723 | break; |
| 47724 | } |
| 47725 | case DUK_DBG_CMD_GETOBJPROPDESC: { |
| 47726 | duk__debug_handle_get_obj_prop_desc(thr, heap); |
| 47727 | break; |
| 47728 | } |
| 47729 | case DUK_DBG_CMD_GETOBJPROPDESCRANGE: { |
| 47730 | duk__debug_handle_get_obj_prop_desc_range(thr, heap); |
| 47731 | break; |
| 47732 | } |
| 47733 | #endif /* DUK_USE_DEBUGGER_INSPECT */ |
| 47734 | default: { |
| 47735 | DUK_D(DUK_DPRINT("debug command unsupported: %d" , (int) cmd)); |
| 47736 | duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command" ); |
| 47737 | } |
| 47738 | } /* switch cmd */ |
| 47739 | break; |
| 47740 | } |
| 47741 | case DUK_DBG_IB_REPLY: { |
| 47742 | DUK_D(DUK_DPRINT("debug reply, skipping" )); |
| 47743 | break; |
| 47744 | } |
| 47745 | case DUK_DBG_IB_ERROR: { |
| 47746 | DUK_D(DUK_DPRINT("debug error, skipping" )); |
| 47747 | break; |
| 47748 | } |
| 47749 | case DUK_DBG_IB_NOTIFY: { |
| 47750 | DUK_D(DUK_DPRINT("debug notify, skipping" )); |
| 47751 | break; |
| 47752 | } |
| 47753 | default: { |
| 47754 | DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d" , (int) x)); |
| 47755 | goto fail; |
| 47756 | } |
| 47757 | } /* switch initial byte */ |
| 47758 | |
| 47759 | DUK_ASSERT(duk_get_top(thr) >= entry_top); |
| 47760 | duk_set_top(thr, entry_top); |
| 47761 | duk__debug_skip_to_eom(thr); |
| 47762 | return; |
| 47763 | |
| 47764 | fail: |
| 47765 | DUK_ASSERT(duk_get_top(thr) >= entry_top); |
| 47766 | duk_set_top(thr, entry_top); |
| 47767 | DUK__SET_CONN_BROKEN(thr, 1); |
| 47768 | return; |
| 47769 | } |
| 47770 | |
| 47771 | DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) { |
| 47772 | if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) { |
| 47773 | duk_debug_send_status(thr); |
| 47774 | thr->heap->dbg_state_dirty = 0; |
| 47775 | } |
| 47776 | } |
| 47777 | |
| 47778 | DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) { |
| 47779 | #if defined(DUK_USE_ASSERTIONS) |
| 47780 | duk_idx_t entry_top; |
| 47781 | #endif |
| 47782 | duk_bool_t retval = 0; |
| 47783 | |
| 47784 | DUK_ASSERT(thr != NULL); |
| 47785 | DUK_ASSERT(thr->heap != NULL); |
| 47786 | #if defined(DUK_USE_ASSERTIONS) |
| 47787 | entry_top = duk_get_top(thr); |
| 47788 | #endif |
| 47789 | |
| 47790 | DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld" , |
| 47791 | thr->heap->dbg_read_cb ? "not NULL" : "NULL" , (long) no_block, |
| 47792 | (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing)); |
| 47793 | DUK_DD(DUK_DDPRINT("top at entry: %ld" , (long) duk_get_top(thr))); |
| 47794 | |
| 47795 | /* thr->heap->dbg_detaching may be != 0 if a debugger write outside |
| 47796 | * the message loop caused a transport error and detach1() to run. |
| 47797 | */ |
| 47798 | DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1); |
| 47799 | DUK_ASSERT(thr->heap->dbg_processing == 0); |
| 47800 | thr->heap->dbg_processing = 1; |
| 47801 | |
| 47802 | /* Ensure dirty state causes a Status even if never process any |
| 47803 | * messages. This is expected by the bytecode executor when in |
| 47804 | * the running state. |
| 47805 | */ |
| 47806 | duk__check_resend_status(thr); |
| 47807 | |
| 47808 | for (;;) { |
| 47809 | /* Process messages until we're no longer paused or we peek |
| 47810 | * and see there's nothing to read right now. |
| 47811 | */ |
| 47812 | DUK_DD(DUK_DDPRINT("top at loop top: %ld" , (long) duk_get_top(thr))); |
| 47813 | DUK_ASSERT(thr->heap->dbg_processing == 1); |
| 47814 | |
| 47815 | while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) { |
| 47816 | /* Detach is pending; can be triggered from outside the |
| 47817 | * debugger loop (e.g. Status notify write error) or by |
| 47818 | * previous message handling. Call detached callback |
| 47819 | * here, in a controlled state, to ensure a possible |
| 47820 | * reattach inside the detached_cb is handled correctly. |
| 47821 | * |
| 47822 | * Recheck for detach in a while loop: an immediate |
| 47823 | * reattach involves a call to duk_debugger_attach() |
| 47824 | * which writes a debugger handshake line immediately |
| 47825 | * inside the API call. If the transport write fails |
| 47826 | * for that handshake, we can immediately end up in a |
| 47827 | * "transport broken, detaching" case several times here. |
| 47828 | * Loop back until we're either cleanly attached or |
| 47829 | * fully detached. |
| 47830 | * |
| 47831 | * NOTE: Reset dbg_processing = 1 forcibly, in case we |
| 47832 | * re-attached; duk_debugger_attach() sets dbg_processing |
| 47833 | * to 0 at the moment. |
| 47834 | */ |
| 47835 | |
| 47836 | DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2" )); |
| 47837 | |
| 47838 | duk__debug_do_detach2(thr->heap); |
| 47839 | thr->heap->dbg_processing = 1; /* may be set to 0 by duk_debugger_attach() inside callback */ |
| 47840 | |
| 47841 | DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld" , |
| 47842 | thr->heap->dbg_read_cb ? "not NULL" : "NULL" , (long) thr->heap->dbg_detaching)); |
| 47843 | } |
| 47844 | DUK_ASSERT(thr->heap->dbg_detaching == 0); /* true even with reattach */ |
| 47845 | DUK_ASSERT(thr->heap->dbg_processing == 1); /* even after a detach and possible reattach */ |
| 47846 | |
| 47847 | if (thr->heap->dbg_read_cb == NULL) { |
| 47848 | DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages" )); |
| 47849 | break; |
| 47850 | } |
| 47851 | |
| 47852 | if (!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || no_block) { |
| 47853 | if (!duk_debug_read_peek(thr)) { |
| 47854 | /* Note: peek cannot currently trigger a detach |
| 47855 | * so the dbg_detaching == 0 assert outside the |
| 47856 | * loop is correct. |
| 47857 | */ |
| 47858 | DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages" )); |
| 47859 | break; |
| 47860 | } |
| 47861 | DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it" )); |
| 47862 | } else { |
| 47863 | DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary" )); |
| 47864 | } |
| 47865 | |
| 47866 | duk__check_resend_status(thr); |
| 47867 | duk__debug_process_message(thr); |
| 47868 | duk__check_resend_status(thr); |
| 47869 | |
| 47870 | retval = 1; /* processed one or more messages */ |
| 47871 | } |
| 47872 | |
| 47873 | DUK_ASSERT(thr->heap->dbg_detaching == 0); |
| 47874 | DUK_ASSERT(thr->heap->dbg_processing == 1); |
| 47875 | thr->heap->dbg_processing = 0; |
| 47876 | |
| 47877 | /* As an initial implementation, read flush after exiting the message |
| 47878 | * loop. If transport is broken, this is a no-op (with debug logs). |
| 47879 | */ |
| 47880 | duk_debug_read_flush(thr); /* this cannot initiate a detach */ |
| 47881 | DUK_ASSERT(thr->heap->dbg_detaching == 0); |
| 47882 | |
| 47883 | DUK_DD(DUK_DDPRINT("top at exit: %ld" , (long) duk_get_top(thr))); |
| 47884 | |
| 47885 | #if defined(DUK_USE_ASSERTIONS) |
| 47886 | /* Easy to get wrong, so assert for it. */ |
| 47887 | DUK_ASSERT(entry_top == duk_get_top(thr)); |
| 47888 | #endif |
| 47889 | |
| 47890 | return retval; |
| 47891 | } |
| 47892 | |
| 47893 | /* |
| 47894 | * Halt execution helper |
| 47895 | */ |
| 47896 | |
| 47897 | /* Halt execution and enter a debugger message loop until execution is resumed |
| 47898 | * by the client. PC for the current activation may be temporarily decremented |
| 47899 | * so that the "current" instruction will be shown by the client. This helper |
| 47900 | * is callable from anywhere, also outside bytecode executor. |
| 47901 | */ |
| 47902 | |
| 47903 | DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) { |
| 47904 | duk_activation *act; |
| 47905 | duk_hcompfunc *fun; |
| 47906 | duk_instr_t *old_pc = NULL; |
| 47907 | |
| 47908 | DUK_ASSERT(thr != NULL); |
| 47909 | DUK_ASSERT(thr->heap != NULL); |
| 47910 | DUK_ASSERT(duk_debug_is_attached(thr->heap)); |
| 47911 | DUK_ASSERT(thr->heap->dbg_processing == 0); |
| 47912 | DUK_ASSERT(!duk_debug_is_paused(thr->heap)); |
| 47913 | |
| 47914 | duk_debug_set_paused(thr->heap); |
| 47915 | |
| 47916 | act = thr->callstack_curr; |
| 47917 | |
| 47918 | /* NOTE: act may be NULL if an error is thrown outside of any activation, |
| 47919 | * which may happen in the case of, e.g. syntax errors. |
| 47920 | */ |
| 47921 | |
| 47922 | /* Decrement PC if that was requested, this requires a PC sync. */ |
| 47923 | if (act != NULL) { |
| 47924 | duk_hthread_sync_currpc(thr); |
| 47925 | old_pc = act->curr_pc; |
| 47926 | fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); |
| 47927 | |
| 47928 | /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is |
| 47929 | * guaranteed to be a non-NULL ECMAScript function. |
| 47930 | */ |
| 47931 | DUK_ASSERT(act->curr_pc == NULL || |
| 47932 | (fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun))); |
| 47933 | if (use_prev_pc && |
| 47934 | act->curr_pc != NULL && |
| 47935 | act->curr_pc > DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, fun)) { |
| 47936 | act->curr_pc--; |
| 47937 | } |
| 47938 | } |
| 47939 | |
| 47940 | /* Process debug messages until we are no longer paused. */ |
| 47941 | |
| 47942 | /* NOTE: This is a bit fragile. It's important to ensure that |
| 47943 | * duk_debug_process_messages() never throws an error or |
| 47944 | * act->curr_pc will never be reset. |
| 47945 | */ |
| 47946 | |
| 47947 | thr->heap->dbg_state_dirty = 1; |
| 47948 | while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { |
| 47949 | DUK_ASSERT(duk_debug_is_attached(thr->heap)); |
| 47950 | DUK_ASSERT(thr->heap->dbg_processing == 0); |
| 47951 | duk_debug_process_messages(thr, 0 /*no_block*/); |
| 47952 | } |
| 47953 | |
| 47954 | /* XXX: Decrementing and restoring act->curr_pc works now, but if the |
| 47955 | * debugger message loop gains the ability to adjust the current PC |
| 47956 | * (e.g. a forced jump) restoring the PC here will break. Another |
| 47957 | * approach would be to use a state flag for the "decrement 1 from |
| 47958 | * topmost activation's PC" and take it into account whenever dealing |
| 47959 | * with PC values. |
| 47960 | */ |
| 47961 | if (act != NULL) { |
| 47962 | act->curr_pc = old_pc; /* restore PC */ |
| 47963 | } |
| 47964 | } |
| 47965 | |
| 47966 | /* |
| 47967 | * Breakpoint management |
| 47968 | */ |
| 47969 | |
| 47970 | DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) { |
| 47971 | duk_heap *heap; |
| 47972 | duk_breakpoint *b; |
| 47973 | |
| 47974 | /* Caller must trigger recomputation of active breakpoint list. To |
| 47975 | * ensure stale values are not used if that doesn't happen, clear the |
| 47976 | * active breakpoint list here. |
| 47977 | */ |
| 47978 | |
| 47979 | DUK_ASSERT(thr != NULL); |
| 47980 | DUK_ASSERT(filename != NULL); |
| 47981 | heap = thr->heap; |
| 47982 | DUK_ASSERT(heap != NULL); |
| 47983 | |
| 47984 | if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) { |
| 47985 | DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used" , |
| 47986 | (duk_heaphdr *) filename, (long) line)); |
| 47987 | return -1; |
| 47988 | } |
| 47989 | heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; |
| 47990 | b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++); |
| 47991 | b->filename = filename; |
| 47992 | b->line = line; |
| 47993 | DUK_HSTRING_INCREF(thr, filename); |
| 47994 | |
| 47995 | return (duk_small_int_t) (heap->dbg_breakpoint_count - 1); /* index */ |
| 47996 | } |
| 47997 | |
| 47998 | DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) { |
| 47999 | duk_heap *heap; |
| 48000 | duk_hstring *h; |
| 48001 | duk_breakpoint *b; |
| 48002 | duk_size_t move_size; |
| 48003 | |
| 48004 | /* Caller must trigger recomputation of active breakpoint list. To |
| 48005 | * ensure stale values are not used if that doesn't happen, clear the |
| 48006 | * active breakpoint list here. |
| 48007 | */ |
| 48008 | |
| 48009 | DUK_ASSERT(thr != NULL); |
| 48010 | heap = thr->heap; |
| 48011 | DUK_ASSERT(heap != NULL); |
| 48012 | DUK_ASSERT(duk_debug_is_attached(thr->heap)); |
| 48013 | DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */ |
| 48014 | |
| 48015 | if (breakpoint_index >= heap->dbg_breakpoint_count) { |
| 48016 | DUK_D(DUK_DPRINT("invalid breakpoint index: %ld" , (long) breakpoint_index)); |
| 48017 | return 0; |
| 48018 | } |
| 48019 | b = heap->dbg_breakpoints + breakpoint_index; |
| 48020 | |
| 48021 | h = b->filename; |
| 48022 | DUK_ASSERT(h != NULL); |
| 48023 | |
| 48024 | move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1); |
| 48025 | duk_memmove((void *) b, |
| 48026 | (const void *) (b + 1), |
| 48027 | (size_t) move_size); |
| 48028 | |
| 48029 | heap->dbg_breakpoint_count--; |
| 48030 | heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL; |
| 48031 | |
| 48032 | DUK_HSTRING_DECREF(thr, h); /* side effects */ |
| 48033 | DUK_UNREF(h); /* w/o refcounting */ |
| 48034 | |
| 48035 | /* Breakpoint entries above the used area are left as garbage. */ |
| 48036 | |
| 48037 | return 1; |
| 48038 | } |
| 48039 | |
| 48040 | /* |
| 48041 | * Misc state management |
| 48042 | */ |
| 48043 | |
| 48044 | DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) { |
| 48045 | return (heap->dbg_read_cb != NULL); |
| 48046 | } |
| 48047 | |
| 48048 | DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) { |
| 48049 | return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0); |
| 48050 | } |
| 48051 | |
| 48052 | DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) { |
| 48053 | if (duk_debug_is_paused(heap)) { |
| 48054 | DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring" )); |
| 48055 | } else { |
| 48056 | DUK_HEAP_SET_DEBUGGER_PAUSED(heap); |
| 48057 | heap->dbg_state_dirty = 1; |
| 48058 | duk_debug_clear_pause_state(heap); |
| 48059 | DUK_ASSERT(heap->ms_running == 0); /* debugger can't be triggered within mark-and-sweep */ |
| 48060 | heap->ms_running = 2; /* prevent mark-and-sweep, prevent refzero queueing */ |
| 48061 | heap->ms_prevent_count++; |
| 48062 | DUK_ASSERT(heap->ms_prevent_count != 0); /* Wrap. */ |
| 48063 | DUK_ASSERT(heap->heap_thread != NULL); |
| 48064 | } |
| 48065 | } |
| 48066 | |
| 48067 | DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) { |
| 48068 | if (duk_debug_is_paused(heap)) { |
| 48069 | DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); |
| 48070 | heap->dbg_state_dirty = 1; |
| 48071 | duk_debug_clear_pause_state(heap); |
| 48072 | DUK_ASSERT(heap->ms_running == 2); |
| 48073 | DUK_ASSERT(heap->ms_prevent_count > 0); |
| 48074 | heap->ms_prevent_count--; |
| 48075 | heap->ms_running = 0; |
| 48076 | DUK_ASSERT(heap->heap_thread != NULL); |
| 48077 | } else { |
| 48078 | DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring" )); |
| 48079 | } |
| 48080 | } |
| 48081 | |
| 48082 | DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) { |
| 48083 | heap->dbg_pause_flags = 0; |
| 48084 | heap->dbg_pause_act = NULL; |
| 48085 | heap->dbg_pause_startline = 0; |
| 48086 | } |
| 48087 | |
| 48088 | #else /* DUK_USE_DEBUGGER_SUPPORT */ |
| 48089 | |
| 48090 | /* No debugger support. */ |
| 48091 | |
| 48092 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 48093 | |
| 48094 | /* automatic undefs */ |
| 48095 | #undef DUK__DBG_TPORT_ENTER |
| 48096 | #undef DUK__DBG_TPORT_EXIT |
| 48097 | #undef DUK__SET_CONN_BROKEN |
| 48098 | #line 1 "duk_error_augment.c" |
| 48099 | /* |
| 48100 | * Augmenting errors at their creation site and their throw site. |
| 48101 | * |
| 48102 | * When errors are created, traceback data is added by built-in code |
| 48103 | * and a user error handler (if defined) can process or replace the |
| 48104 | * error. Similarly, when errors are thrown, a user error handler |
| 48105 | * (if defined) can process or replace the error. |
| 48106 | * |
| 48107 | * Augmentation and other processing at error creation time is nice |
| 48108 | * because an error is only created once, but it may be thrown and |
| 48109 | * rethrown multiple times. User error handler registered for processing |
| 48110 | * an error at its throw site must be careful to handle rethrowing in |
| 48111 | * a useful manner. |
| 48112 | * |
| 48113 | * Error augmentation may throw an internal error (e.g. alloc error). |
| 48114 | * |
| 48115 | * ECMAScript allows throwing any values, so all values cannot be |
| 48116 | * augmented. Currently, the built-in augmentation at error creation |
| 48117 | * only augments error values which are Error instances (= have the |
| 48118 | * built-in Error.prototype in their prototype chain) and are also |
| 48119 | * extensible. User error handlers have no limitations in this respect. |
| 48120 | */ |
| 48121 | |
| 48122 | /* #include duk_internal.h -> already included */ |
| 48123 | |
| 48124 | /* |
| 48125 | * Helper for calling a user error handler. |
| 48126 | * |
| 48127 | * 'thr' must be the currently active thread; the error handler is called |
| 48128 | * in its context. The valstack of 'thr' must have the error value on |
| 48129 | * top, and will be replaced by another error value based on the return |
| 48130 | * value of the error handler. |
| 48131 | * |
| 48132 | * The helper calls duk_handle_call() recursively in protected mode. |
| 48133 | * Before that call happens, no longjmps should happen; as a consequence, |
| 48134 | * we must assume that the valstack contains enough temporary space for |
| 48135 | * arguments and such. |
| 48136 | * |
| 48137 | * While the error handler runs, any errors thrown will not trigger a |
| 48138 | * recursive error handler call (this is implemented using a heap level |
| 48139 | * flag which will "follow" through any coroutines resumed inside the |
| 48140 | * error handler). If the error handler is not callable or throws an |
| 48141 | * error, the resulting error replaces the original error (for Duktape |
| 48142 | * internal errors, duk_error_throw.c further substitutes this error with |
| 48143 | * a DoubleError which is not ideal). This would be easy to change and |
| 48144 | * even signal to the caller. |
| 48145 | * |
| 48146 | * The user error handler is stored in 'Duktape.errCreate' or |
| 48147 | * 'Duktape.errThrow' depending on whether we're augmenting the error at |
| 48148 | * creation or throw time. There are several alternatives to this approach, |
| 48149 | * see doc/error-objects.rst for discussion. |
| 48150 | * |
| 48151 | * Note: since further longjmp()s may occur while calling the error handler |
| 48152 | * (for many reasons, e.g. a labeled 'break' inside the handler), the |
| 48153 | * caller can make no assumptions on the thr->heap->lj state after the |
| 48154 | * call (this affects especially duk_error_throw.c). This is not an issue |
| 48155 | * as long as the caller writes to the lj state only after the error handler |
| 48156 | * finishes. |
| 48157 | */ |
| 48158 | |
| 48159 | #if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE) |
| 48160 | DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) { |
| 48161 | duk_tval *tv_hnd; |
| 48162 | duk_int_t rc; |
| 48163 | |
| 48164 | DUK_ASSERT(thr != NULL); |
| 48165 | DUK_ASSERT(thr->heap != NULL); |
| 48166 | DUK_ASSERT_STRIDX_VALID(stridx_cb); |
| 48167 | |
| 48168 | if (thr->heap->augmenting_error) { |
| 48169 | DUK_D(DUK_DPRINT("recursive call to error augmentation, ignore" )); |
| 48170 | return; |
| 48171 | } |
| 48172 | |
| 48173 | /* |
| 48174 | * Check whether or not we have an error handler. |
| 48175 | * |
| 48176 | * We must be careful of not triggering an error when looking up the |
| 48177 | * property. For instance, if the property is a getter, we don't want |
| 48178 | * to call it, only plain values are allowed. The value, if it exists, |
| 48179 | * is not checked. If the value is not a function, a TypeError happens |
| 48180 | * when it is called and that error replaces the original one. |
| 48181 | */ |
| 48182 | |
| 48183 | DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */ |
| 48184 | |
| 48185 | /* [ ... errval ] */ |
| 48186 | |
| 48187 | if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) { |
| 48188 | /* When creating built-ins, some of the built-ins may not be set |
| 48189 | * and we want to tolerate that when throwing errors. |
| 48190 | */ |
| 48191 | DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring" )); |
| 48192 | return; |
| 48193 | } |
| 48194 | tv_hnd = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, |
| 48195 | thr->builtins[DUK_BIDX_DUKTAPE], |
| 48196 | stridx_cb); |
| 48197 | if (tv_hnd == NULL) { |
| 48198 | DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T" , |
| 48199 | (duk_tval *) tv_hnd)); |
| 48200 | return; |
| 48201 | } |
| 48202 | DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T" , |
| 48203 | (duk_tval *) tv_hnd)); |
| 48204 | duk_push_tval(thr, tv_hnd); |
| 48205 | |
| 48206 | /* [ ... errval errhandler ] */ |
| 48207 | |
| 48208 | duk_insert(thr, -2); /* -> [ ... errhandler errval ] */ |
| 48209 | duk_push_undefined(thr); |
| 48210 | duk_insert(thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */ |
| 48211 | |
| 48212 | /* [ ... errhandler undefined errval ] */ |
| 48213 | |
| 48214 | /* |
| 48215 | * heap->augmenting_error prevents recursive re-entry and also causes |
| 48216 | * call handling to use a larger (but not unbounded) call stack limit |
| 48217 | * for the duration of error augmentation. |
| 48218 | * |
| 48219 | * We ignore errors now: a success return and an error value both |
| 48220 | * replace the original error value. (This would be easy to change.) |
| 48221 | */ |
| 48222 | |
| 48223 | DUK_ASSERT(thr->heap->augmenting_error == 0); |
| 48224 | thr->heap->augmenting_error = 1; |
| 48225 | |
| 48226 | rc = duk_pcall_method(thr, 1); |
| 48227 | DUK_UNREF(rc); /* no need to check now: both success and error are OK */ |
| 48228 | |
| 48229 | DUK_ASSERT(thr->heap->augmenting_error == 1); |
| 48230 | thr->heap->augmenting_error = 0; |
| 48231 | |
| 48232 | /* [ ... errval ] */ |
| 48233 | } |
| 48234 | #endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */ |
| 48235 | |
| 48236 | /* |
| 48237 | * Add ._Tracedata to an error on the stack top. |
| 48238 | */ |
| 48239 | |
| 48240 | #if defined(DUK_USE_TRACEBACKS) |
| 48241 | DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) { |
| 48242 | duk_activation *act; |
| 48243 | duk_int_t depth; |
| 48244 | duk_int_t arr_size; |
| 48245 | duk_tval *tv; |
| 48246 | duk_hstring *s; |
| 48247 | duk_uint32_t u32; |
| 48248 | duk_double_t d; |
| 48249 | |
| 48250 | DUK_ASSERT(thr != NULL); |
| 48251 | DUK_ASSERT(thr_callstack != NULL); |
| 48252 | |
| 48253 | /* [ ... error ] */ |
| 48254 | |
| 48255 | /* |
| 48256 | * The traceback format is pretty arcane in an attempt to keep it compact |
| 48257 | * and cheap to create. It may change arbitrarily from version to version. |
| 48258 | * It should be decoded/accessed through version specific accessors only. |
| 48259 | * |
| 48260 | * See doc/error-objects.rst. |
| 48261 | */ |
| 48262 | |
| 48263 | DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T" , |
| 48264 | (duk_tval *) duk_get_tval(thr, -1))); |
| 48265 | |
| 48266 | /* Preallocate array to correct size, so that we can just write out |
| 48267 | * the _Tracedata values into the array part. |
| 48268 | */ |
| 48269 | act = thr->callstack_curr; |
| 48270 | depth = DUK_USE_TRACEBACK_DEPTH; |
| 48271 | DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */ |
| 48272 | if (depth > (duk_int_t) thr_callstack->callstack_top) { |
| 48273 | depth = (duk_int_t) thr_callstack->callstack_top; |
| 48274 | } |
| 48275 | if (depth > 0) { |
| 48276 | if (flags & DUK_AUGMENT_FLAG_SKIP_ONE) { |
| 48277 | DUK_ASSERT(act != NULL); |
| 48278 | act = act->parent; |
| 48279 | depth--; |
| 48280 | } |
| 48281 | } |
| 48282 | arr_size = depth * 2; |
| 48283 | if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { |
| 48284 | arr_size += 2; |
| 48285 | } |
| 48286 | if (c_filename) { |
| 48287 | /* We need the C filename to be interned before getting the |
| 48288 | * array part pointer to avoid any GC interference while the |
| 48289 | * array part is populated. |
| 48290 | */ |
| 48291 | duk_push_string(thr, c_filename); |
| 48292 | arr_size += 2; |
| 48293 | } |
| 48294 | |
| 48295 | /* XXX: Uninitialized would be OK. Maybe add internal primitive to |
| 48296 | * push bare duk_harray with size? |
| 48297 | */ |
| 48298 | DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items" , (long) arr_size)); |
| 48299 | tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) arr_size); |
| 48300 | duk_clear_prototype(thr, -1); |
| 48301 | DUK_ASSERT(duk_is_bare_object(thr, -1)); |
| 48302 | DUK_ASSERT(arr_size == 0 || tv != NULL); |
| 48303 | |
| 48304 | /* Compiler SyntaxErrors (and other errors) come first, and are |
| 48305 | * blamed by default (not flagged "noblame"). |
| 48306 | */ |
| 48307 | if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { |
| 48308 | s = thr->compile_ctx->h_filename; |
| 48309 | DUK_TVAL_SET_STRING(tv, s); |
| 48310 | DUK_HSTRING_INCREF(thr, s); |
| 48311 | tv++; |
| 48312 | |
| 48313 | u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line; /* (flags<<32) + (line), flags = 0 */ |
| 48314 | DUK_TVAL_SET_U32(tv, u32); |
| 48315 | tv++; |
| 48316 | } |
| 48317 | |
| 48318 | /* Filename/line from C macros (__FILE__, __LINE__) are added as an |
| 48319 | * entry with a special format: (string, number). The number contains |
| 48320 | * the line and flags. |
| 48321 | */ |
| 48322 | |
| 48323 | /* [ ... error c_filename? arr ] */ |
| 48324 | |
| 48325 | if (c_filename) { |
| 48326 | DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2)); |
| 48327 | s = DUK_TVAL_GET_STRING(thr->valstack_top - 2); /* interned c_filename */ |
| 48328 | DUK_ASSERT(s != NULL); |
| 48329 | DUK_TVAL_SET_STRING(tv, s); |
| 48330 | DUK_HSTRING_INCREF(thr, s); |
| 48331 | tv++; |
| 48332 | |
| 48333 | d = ((flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) + |
| 48334 | (duk_double_t) c_line; |
| 48335 | DUK_TVAL_SET_DOUBLE(tv, d); |
| 48336 | tv++; |
| 48337 | } |
| 48338 | |
| 48339 | /* Traceback depth doesn't take into account the filename/line |
| 48340 | * special handling above (intentional). |
| 48341 | */ |
| 48342 | for (; depth-- > 0; act = act->parent) { |
| 48343 | duk_uint32_t pc; |
| 48344 | duk_tval *tv_src; |
| 48345 | |
| 48346 | /* [... arr] */ |
| 48347 | |
| 48348 | DUK_ASSERT(act != NULL); /* depth check above, assumes book-keeping is correct */ |
| 48349 | DUK_ASSERT_DISABLE(act->pc >= 0); /* unsigned */ |
| 48350 | |
| 48351 | /* Add function object. */ |
| 48352 | tv_src = &act->tv_func; /* object (function) or lightfunc */ |
| 48353 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src)); |
| 48354 | DUK_TVAL_SET_TVAL(tv, tv_src); |
| 48355 | DUK_TVAL_INCREF(thr, tv); |
| 48356 | tv++; |
| 48357 | |
| 48358 | /* Add a number containing: pc, activation flags. |
| 48359 | * |
| 48360 | * PC points to next instruction, find offending PC. Note that |
| 48361 | * PC == 0 for native code. |
| 48362 | */ |
| 48363 | pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr_callstack, act); |
| 48364 | DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ |
| 48365 | DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ |
| 48366 | d = ((duk_double_t) act->flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc; |
| 48367 | DUK_TVAL_SET_DOUBLE(tv, d); |
| 48368 | tv++; |
| 48369 | } |
| 48370 | |
| 48371 | #if defined(DUK_USE_ASSERTIONS) |
| 48372 | { |
| 48373 | duk_harray *a; |
| 48374 | a = (duk_harray *) duk_known_hobject(thr, -1); |
| 48375 | DUK_ASSERT(a != NULL); |
| 48376 | DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length); |
| 48377 | DUK_ASSERT(a->length == (duk_uint32_t) arr_size); |
| 48378 | DUK_ASSERT(duk_is_bare_object(thr, -1)); |
| 48379 | } |
| 48380 | #endif |
| 48381 | |
| 48382 | /* [ ... error c_filename? arr ] */ |
| 48383 | |
| 48384 | if (c_filename) { |
| 48385 | duk_remove_m2(thr); |
| 48386 | } |
| 48387 | |
| 48388 | /* [ ... error arr ] */ |
| 48389 | |
| 48390 | duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */ |
| 48391 | } |
| 48392 | #endif /* DUK_USE_TRACEBACKS */ |
| 48393 | |
| 48394 | /* |
| 48395 | * Add .fileName and .lineNumber to an error on the stack top. |
| 48396 | */ |
| 48397 | |
| 48398 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !defined(DUK_USE_TRACEBACKS) |
| 48399 | DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) { |
| 48400 | #if defined(DUK_USE_ASSERTIONS) |
| 48401 | duk_int_t entry_top; |
| 48402 | #endif |
| 48403 | |
| 48404 | #if defined(DUK_USE_ASSERTIONS) |
| 48405 | entry_top = duk_get_top(thr); |
| 48406 | #endif |
| 48407 | |
| 48408 | /* |
| 48409 | * If tracebacks are disabled, 'fileName' and 'lineNumber' are added |
| 48410 | * as plain own properties. Since Error.prototype has accessors of |
| 48411 | * the same name, we need to define own properties directly (cannot |
| 48412 | * just use e.g. duk_put_prop_stridx). Existing properties are not |
| 48413 | * overwritten in case they already exist. |
| 48414 | */ |
| 48415 | |
| 48416 | if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) { |
| 48417 | /* Compiler SyntaxError (or other error) gets the primary blame. |
| 48418 | * Currently no flag to prevent blaming. |
| 48419 | */ |
| 48420 | duk_push_uint(thr, (duk_uint_t) thr->compile_ctx->curr_token.start_line); |
| 48421 | duk_push_hstring(thr, thr->compile_ctx->h_filename); |
| 48422 | } else if (c_filename && (flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) == 0) { |
| 48423 | /* C call site gets blamed next, unless flagged not to do so. |
| 48424 | * XXX: file/line is disabled in minimal builds, so disable this |
| 48425 | * too when appropriate. |
| 48426 | */ |
| 48427 | duk_push_int(thr, c_line); |
| 48428 | duk_push_string(thr, c_filename); |
| 48429 | } else { |
| 48430 | /* Finally, blame the innermost callstack entry which has a |
| 48431 | * .fileName property. |
| 48432 | */ |
| 48433 | duk_small_uint_t depth; |
| 48434 | duk_uint32_t ecma_line; |
| 48435 | duk_activation *act; |
| 48436 | |
| 48437 | DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */ |
| 48438 | depth = DUK_USE_TRACEBACK_DEPTH; |
| 48439 | if (depth > thr_callstack->callstack_top) { |
| 48440 | depth = thr_callstack->callstack_top; |
| 48441 | } |
| 48442 | for (act = thr_callstack->callstack_curr; depth-- > 0; act = act->parent) { |
| 48443 | duk_hobject *func; |
| 48444 | duk_uint32_t pc; |
| 48445 | |
| 48446 | DUK_ASSERT(act != NULL); |
| 48447 | func = DUK_ACT_GET_FUNC(act); |
| 48448 | if (func == NULL) { |
| 48449 | /* Lightfunc, not blamed now. */ |
| 48450 | continue; |
| 48451 | } |
| 48452 | |
| 48453 | /* PC points to next instruction, find offending PC, |
| 48454 | * PC == 0 for native code. |
| 48455 | */ |
| 48456 | pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */ |
| 48457 | DUK_UNREF(pc); |
| 48458 | DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ |
| 48459 | DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ |
| 48460 | |
| 48461 | duk_push_hobject(thr, func); |
| 48462 | |
| 48463 | /* [ ... error func ] */ |
| 48464 | |
| 48465 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME); |
| 48466 | if (!duk_is_string_notsymbol(thr, -1)) { |
| 48467 | duk_pop_2(thr); |
| 48468 | continue; |
| 48469 | } |
| 48470 | |
| 48471 | /* [ ... error func fileName ] */ |
| 48472 | |
| 48473 | ecma_line = 0; |
| 48474 | #if defined(DUK_USE_PC2LINE) |
| 48475 | if (DUK_HOBJECT_IS_COMPFUNC(func)) { |
| 48476 | ecma_line = duk_hobject_pc2line_query(thr, -2, (duk_uint_fast32_t) pc); |
| 48477 | } else { |
| 48478 | /* Native function, no relevant lineNumber. */ |
| 48479 | } |
| 48480 | #endif /* DUK_USE_PC2LINE */ |
| 48481 | duk_push_u32(thr, ecma_line); |
| 48482 | |
| 48483 | /* [ ... error func fileName lineNumber ] */ |
| 48484 | |
| 48485 | duk_replace(thr, -3); |
| 48486 | |
| 48487 | /* [ ... error lineNumber fileName ] */ |
| 48488 | goto define_props; |
| 48489 | } |
| 48490 | |
| 48491 | /* No activation matches, use undefined for both .fileName and |
| 48492 | * .lineNumber (matches what we do with a _Tracedata based |
| 48493 | * no-match lookup. |
| 48494 | */ |
| 48495 | duk_push_undefined(thr); |
| 48496 | duk_push_undefined(thr); |
| 48497 | } |
| 48498 | |
| 48499 | define_props: |
| 48500 | /* [ ... error lineNumber fileName ] */ |
| 48501 | #if defined(DUK_USE_ASSERTIONS) |
| 48502 | DUK_ASSERT(duk_get_top(thr) == entry_top + 2); |
| 48503 | #endif |
| 48504 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE); |
| 48505 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE); |
| 48506 | } |
| 48507 | #endif /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */ |
| 48508 | |
| 48509 | /* |
| 48510 | * Add line number to a compiler error. |
| 48511 | */ |
| 48512 | |
| 48513 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 48514 | DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) { |
| 48515 | |
| 48516 | /* Append a "(line NNN)" to the "message" property of any error |
| 48517 | * thrown during compilation. Usually compilation errors are |
| 48518 | * SyntaxErrors but they can also be out-of-memory errors and |
| 48519 | * the like. |
| 48520 | */ |
| 48521 | |
| 48522 | /* [ ... error ] */ |
| 48523 | |
| 48524 | DUK_ASSERT(duk_is_object(thr, -1)); |
| 48525 | |
| 48526 | if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) { |
| 48527 | return; |
| 48528 | } |
| 48529 | |
| 48530 | DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T" , |
| 48531 | (duk_tval *) duk_get_tval(thr, -1))); |
| 48532 | |
| 48533 | if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_MESSAGE)) { |
| 48534 | duk_bool_t at_end; |
| 48535 | |
| 48536 | /* Best guesstimate that error occurred at end of input, token |
| 48537 | * truncated by end of input, etc. |
| 48538 | */ |
| 48539 | #if 0 |
| 48540 | at_end = (thr->compile_ctx->curr_token.start_offset + 1 >= thr->compile_ctx->lex.input_length); |
| 48541 | at_end = (thr->compile_ctx->lex.window[0].codepoint < 0 || thr->compile_ctx->lex.window[1].codepoint < 0); |
| 48542 | #endif |
| 48543 | at_end = (thr->compile_ctx->lex.window[0].codepoint < 0); |
| 48544 | |
| 48545 | DUK_D(DUK_DPRINT("syntax error, determined at_end=%ld; curr_token.start_offset=%ld, " |
| 48546 | "lex.input_length=%ld, window[0].codepoint=%ld, window[1].codepoint=%ld" , |
| 48547 | (long) at_end, |
| 48548 | (long) thr->compile_ctx->curr_token.start_offset, |
| 48549 | (long) thr->compile_ctx->lex.input_length, |
| 48550 | (long) thr->compile_ctx->lex.window[0].codepoint, |
| 48551 | (long) thr->compile_ctx->lex.window[1].codepoint)); |
| 48552 | |
| 48553 | duk_push_sprintf(thr, " (line %ld%s)" , |
| 48554 | (long) thr->compile_ctx->curr_token.start_line, |
| 48555 | at_end ? ", end of input" : "" ); |
| 48556 | duk_concat(thr, 2); |
| 48557 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE); |
| 48558 | } else { |
| 48559 | duk_pop(thr); |
| 48560 | } |
| 48561 | |
| 48562 | DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T" , |
| 48563 | (duk_tval *) duk_get_tval(thr, -1))); |
| 48564 | } |
| 48565 | #endif /* DUK_USE_AUGMENT_ERROR_CREATE */ |
| 48566 | |
| 48567 | /* |
| 48568 | * Augment an error being created using Duktape specific properties |
| 48569 | * like _Tracedata or .fileName/.lineNumber. |
| 48570 | */ |
| 48571 | |
| 48572 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 48573 | DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_hobject *obj, duk_small_uint_t flags) { |
| 48574 | #if defined(DUK_USE_ASSERTIONS) |
| 48575 | duk_int_t entry_top; |
| 48576 | #endif |
| 48577 | |
| 48578 | #if defined(DUK_USE_ASSERTIONS) |
| 48579 | entry_top = duk_get_top(thr); |
| 48580 | #endif |
| 48581 | DUK_ASSERT(obj != NULL); |
| 48582 | |
| 48583 | DUK_UNREF(obj); /* unreferenced w/o tracebacks */ |
| 48584 | |
| 48585 | duk__add_compiler_error_line(thr); |
| 48586 | |
| 48587 | #if defined(DUK_USE_TRACEBACKS) |
| 48588 | /* If tracebacks are enabled, the '_Tracedata' property is the only |
| 48589 | * thing we need: 'fileName' and 'lineNumber' are virtual properties |
| 48590 | * which use '_Tracedata'. (Check _Tracedata only as own property.) |
| 48591 | */ |
| 48592 | if (duk_hobject_find_entry_tval_ptr_stridx(thr->heap, obj, DUK_STRIDX_INT_TRACEDATA) != NULL) { |
| 48593 | DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it" )); |
| 48594 | } else { |
| 48595 | duk__add_traceback(thr, thr_callstack, c_filename, c_line, flags); |
| 48596 | } |
| 48597 | #else |
| 48598 | /* Without tracebacks the concrete .fileName and .lineNumber need |
| 48599 | * to be added directly. |
| 48600 | */ |
| 48601 | duk__add_fileline(thr, thr_callstack, c_filename, c_line, flags); |
| 48602 | #endif |
| 48603 | |
| 48604 | #if defined(DUK_USE_ASSERTIONS) |
| 48605 | DUK_ASSERT(duk_get_top(thr) == entry_top); |
| 48606 | #endif |
| 48607 | } |
| 48608 | #endif /* DUK_USE_AUGMENT_ERROR_CREATE */ |
| 48609 | |
| 48610 | /* |
| 48611 | * Augment an error at creation time with _Tracedata/fileName/lineNumber |
| 48612 | * and allow a user error handler (if defined) to process/replace the error. |
| 48613 | * The error to be augmented is at the stack top. |
| 48614 | * |
| 48615 | * thr: thread containing the error value |
| 48616 | * thr_callstack: thread which should be used for generating callstack etc. |
| 48617 | * c_filename: C __FILE__ related to the error |
| 48618 | * c_line: C __LINE__ related to the error |
| 48619 | * flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE: |
| 48620 | * if true, don't fileName/line as error source, otherwise use traceback |
| 48621 | * (needed because user code filename/line are reported but internal ones |
| 48622 | * are not) |
| 48623 | */ |
| 48624 | |
| 48625 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 48626 | DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_uint_t flags) { |
| 48627 | duk_hobject *obj; |
| 48628 | |
| 48629 | DUK_ASSERT(thr != NULL); |
| 48630 | DUK_ASSERT(thr_callstack != NULL); |
| 48631 | |
| 48632 | /* [ ... error ] */ |
| 48633 | |
| 48634 | /* |
| 48635 | * Criteria for augmenting: |
| 48636 | * |
| 48637 | * - augmentation enabled in build (naturally) |
| 48638 | * - error value internal prototype chain contains the built-in |
| 48639 | * Error prototype object (i.e. 'val instanceof Error') |
| 48640 | * |
| 48641 | * Additional criteria for built-in augmenting: |
| 48642 | * |
| 48643 | * - error value is an extensible object |
| 48644 | */ |
| 48645 | |
| 48646 | obj = duk_get_hobject(thr, -1); |
| 48647 | if (!obj) { |
| 48648 | DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment" )); |
| 48649 | return; |
| 48650 | } |
| 48651 | if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) { |
| 48652 | /* If the value has a prototype loop, it's critical not to |
| 48653 | * throw here. Instead, assume the value is not to be |
| 48654 | * augmented. |
| 48655 | */ |
| 48656 | DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment" )); |
| 48657 | return; |
| 48658 | } |
| 48659 | if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) { |
| 48660 | DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment" )); |
| 48661 | duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, obj, flags); |
| 48662 | } else { |
| 48663 | DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment" )); |
| 48664 | } |
| 48665 | |
| 48666 | /* [ ... error ] */ |
| 48667 | |
| 48668 | #if defined(DUK_USE_ERRCREATE) |
| 48669 | duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE); |
| 48670 | #endif |
| 48671 | } |
| 48672 | #endif /* DUK_USE_AUGMENT_ERROR_CREATE */ |
| 48673 | |
| 48674 | /* |
| 48675 | * Augment an error at throw time; allow a user error handler (if defined) |
| 48676 | * to process/replace the error. The error to be augmented is at the |
| 48677 | * stack top. |
| 48678 | */ |
| 48679 | |
| 48680 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) |
| 48681 | DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) { |
| 48682 | #if defined(DUK_USE_ERRTHROW) |
| 48683 | duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW); |
| 48684 | #endif /* DUK_USE_ERRTHROW */ |
| 48685 | } |
| 48686 | #endif /* DUK_USE_AUGMENT_ERROR_THROW */ |
| 48687 | #line 1 "duk_error_longjmp.c" |
| 48688 | /* |
| 48689 | * Do a longjmp call, calling the fatal error handler if no |
| 48690 | * catchpoint exists. |
| 48691 | */ |
| 48692 | |
| 48693 | /* #include duk_internal.h -> already included */ |
| 48694 | |
| 48695 | #if defined(DUK_USE_PREFER_SIZE) |
| 48696 | DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_minimal(duk_hthread *thr)); |
| 48697 | DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) { |
| 48698 | (void) duk_fatal(thr, "uncaught error" ); |
| 48699 | DUK_WO_NORETURN(return;); |
| 48700 | } |
| 48701 | #endif |
| 48702 | |
| 48703 | #if 0 |
| 48704 | DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_readable(duk_hthread *thr)); |
| 48705 | DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) { |
| 48706 | const char *summary; |
| 48707 | char buf[DUK_USE_FATAL_MAXLEN]; |
| 48708 | |
| 48709 | summary = duk_push_string_tval_readable(thr, &thr->heap->lj.value1); |
| 48710 | DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s" , summary); |
| 48711 | buf[sizeof(buf) - 1] = (char) 0; |
| 48712 | (void) duk_fatal(thr, (const char *) buf); |
| 48713 | DUK_WO_NORETURN(return;); |
| 48714 | } |
| 48715 | #endif |
| 48716 | |
| 48717 | #if !defined(DUK_USE_PREFER_SIZE) |
| 48718 | DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_error_aware(duk_hthread *thr)); |
| 48719 | DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) { |
| 48720 | const char *summary; |
| 48721 | char buf[DUK_USE_FATAL_MAXLEN]; |
| 48722 | |
| 48723 | summary = duk_push_string_tval_readable_error(thr, &thr->heap->lj.value1); |
| 48724 | DUK_ASSERT(summary != NULL); |
| 48725 | DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s" , summary); |
| 48726 | buf[sizeof(buf) - 1] = (char) 0; |
| 48727 | (void) duk_fatal(thr, (const char *) buf); |
| 48728 | DUK_WO_NORETURN(return;); |
| 48729 | } |
| 48730 | #endif |
| 48731 | |
| 48732 | DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) { |
| 48733 | DUK_ASSERT(thr != NULL); |
| 48734 | DUK_ASSERT(thr->heap != NULL); |
| 48735 | |
| 48736 | DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T" , |
| 48737 | (int) thr->heap->lj.type, (int) thr->heap->lj.iserror, |
| 48738 | &thr->heap->lj.value1, &thr->heap->lj.value2)); |
| 48739 | |
| 48740 | /* Prevent finalizer execution during error handling. All error |
| 48741 | * handling sites will process pending finalizers once error handling |
| 48742 | * is complete and we're ready for the side effects. Does not prevent |
| 48743 | * refzero freeing or mark-and-sweep during error handling. |
| 48744 | * |
| 48745 | * NOTE: when we come here some calling code may have used DECREF |
| 48746 | * NORZ macros without an explicit DUK_REFZERO_CHECK_xxx() call. |
| 48747 | * We don't want to do it here because it would just check for |
| 48748 | * pending finalizers and we prevent that explicitly. Instead, |
| 48749 | * the error catcher will run the finalizers once error handling |
| 48750 | * is complete. |
| 48751 | */ |
| 48752 | |
| 48753 | DUK_ASSERT_LJSTATE_SET(thr->heap); |
| 48754 | |
| 48755 | thr->heap->pf_prevent_count++; |
| 48756 | DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ |
| 48757 | |
| 48758 | #if defined(DUK_USE_ASSERTIONS) |
| 48759 | /* XXX: set this immediately when longjmp state is set */ |
| 48760 | DUK_ASSERT(thr->heap->error_not_allowed == 0); /* Detect error within critical section. */ |
| 48761 | thr->heap->error_not_allowed = 1; |
| 48762 | #endif |
| 48763 | |
| 48764 | DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld" , (long) thr->heap->pf_prevent_count)); |
| 48765 | |
| 48766 | /* If we don't have a jmpbuf_ptr, there is little we can do except |
| 48767 | * cause a fatal error. The caller's expectation is that we never |
| 48768 | * return. |
| 48769 | */ |
| 48770 | if (!thr->heap->lj.jmpbuf_ptr) { |
| 48771 | DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T" , |
| 48772 | (int) thr->heap->lj.type, (int) thr->heap->lj.iserror, |
| 48773 | &thr->heap->lj.value1, &thr->heap->lj.value2)); |
| 48774 | |
| 48775 | #if defined(DUK_USE_PREFER_SIZE) |
| 48776 | duk__uncaught_minimal(thr); |
| 48777 | #else |
| 48778 | duk__uncaught_error_aware(thr); |
| 48779 | #endif |
| 48780 | DUK_UNREACHABLE(); |
| 48781 | } |
| 48782 | |
| 48783 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 48784 | throw duk_internal_exception(); /* dummy */ |
| 48785 | #else |
| 48786 | DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb); |
| 48787 | #endif |
| 48788 | |
| 48789 | DUK_UNREACHABLE(); |
| 48790 | } |
| 48791 | #line 1 "duk_error_misc.c" |
| 48792 | /* |
| 48793 | * Error helpers |
| 48794 | */ |
| 48795 | |
| 48796 | /* #include duk_internal.h -> already included */ |
| 48797 | |
| 48798 | /* |
| 48799 | * Helper to walk the thread chain and see if there is an active error |
| 48800 | * catcher. Protected calls or finally blocks aren't considered catching. |
| 48801 | */ |
| 48802 | |
| 48803 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 48804 | DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) { |
| 48805 | /* As noted above, a protected API call won't be counted as a |
| 48806 | * catcher. This is usually convenient, e.g. in the case of a top- |
| 48807 | * level duk_pcall(), but may not always be desirable. Perhaps add |
| 48808 | * an argument to treat them as catchers? |
| 48809 | */ |
| 48810 | |
| 48811 | duk_activation *act; |
| 48812 | duk_catcher *cat; |
| 48813 | |
| 48814 | DUK_ASSERT(thr != NULL); |
| 48815 | |
| 48816 | for (; thr != NULL; thr = thr->resumer) { |
| 48817 | for (act = thr->callstack_curr; act != NULL; act = act->parent) { |
| 48818 | for (cat = act->cat; cat != NULL; cat = cat->parent) { |
| 48819 | if (DUK_CAT_HAS_CATCH_ENABLED(cat)) { |
| 48820 | return 1; /* all we need to know */ |
| 48821 | } |
| 48822 | } |
| 48823 | } |
| 48824 | } |
| 48825 | return 0; |
| 48826 | } |
| 48827 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 48828 | |
| 48829 | /* |
| 48830 | * Get prototype object for an integer error code. |
| 48831 | */ |
| 48832 | |
| 48833 | DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) { |
| 48834 | switch (code) { |
| 48835 | case DUK_ERR_EVAL_ERROR: |
| 48836 | return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]; |
| 48837 | case DUK_ERR_RANGE_ERROR: |
| 48838 | return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]; |
| 48839 | case DUK_ERR_REFERENCE_ERROR: |
| 48840 | return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]; |
| 48841 | case DUK_ERR_SYNTAX_ERROR: |
| 48842 | return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]; |
| 48843 | case DUK_ERR_TYPE_ERROR: |
| 48844 | return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]; |
| 48845 | case DUK_ERR_URI_ERROR: |
| 48846 | return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]; |
| 48847 | case DUK_ERR_ERROR: |
| 48848 | default: |
| 48849 | return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]; |
| 48850 | } |
| 48851 | } |
| 48852 | |
| 48853 | /* |
| 48854 | * Helper for debugger throw notify and pause-on-uncaught integration. |
| 48855 | */ |
| 48856 | |
| 48857 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 48858 | DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) { |
| 48859 | duk_bool_t uncaught; |
| 48860 | duk_tval *tv_obj; |
| 48861 | |
| 48862 | /* If something is thrown with the debugger attached and nobody will |
| 48863 | * catch it, execution is paused before the longjmp, turning over |
| 48864 | * control to the debug client. This allows local state to be examined |
| 48865 | * before the stack is unwound. Errors are not intercepted when debug |
| 48866 | * message loop is active (e.g. for Eval). |
| 48867 | */ |
| 48868 | |
| 48869 | DUK_ASSERT(thr != NULL); |
| 48870 | DUK_ASSERT(thr->heap != NULL); |
| 48871 | |
| 48872 | /* XXX: Allow customizing the pause and notify behavior at runtime |
| 48873 | * using debugger runtime flags. For now the behavior is fixed using |
| 48874 | * config options. |
| 48875 | */ |
| 48876 | |
| 48877 | if (!duk_debug_is_attached(thr->heap) || |
| 48878 | thr->heap->dbg_processing || |
| 48879 | thr->heap->lj.type != DUK_LJ_TYPE_THROW || |
| 48880 | thr->heap->creating_error) { |
| 48881 | DUK_D(DUK_DPRINT("skip debugger error integration; not attached, debugger processing, not THROW, or error thrown while creating error" )); |
| 48882 | return; |
| 48883 | } |
| 48884 | |
| 48885 | /* Don't intercept a DoubleError, we may have caused the initial double |
| 48886 | * fault and attempting to intercept it will cause us to be called |
| 48887 | * recursively and exhaust the C stack. (This should no longer happen |
| 48888 | * for the initial throw because DoubleError path doesn't do a debugger |
| 48889 | * integration check, but it might happen for rethrows.) |
| 48890 | */ |
| 48891 | tv_obj = &thr->heap->lj.value1; |
| 48892 | if (DUK_TVAL_IS_OBJECT(tv_obj) && DUK_TVAL_GET_OBJECT(tv_obj) == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) { |
| 48893 | DUK_D(DUK_DPRINT("built-in DoubleError instance (re)thrown, not intercepting" )); |
| 48894 | return; |
| 48895 | } |
| 48896 | |
| 48897 | uncaught = !duk__have_active_catcher(thr); |
| 48898 | |
| 48899 | /* Debugger code expects the value at stack top. This also serves |
| 48900 | * as a backup: we need to store/restore the longjmp state because |
| 48901 | * when the debugger is paused Eval commands may be executed and |
| 48902 | * they can arbitrarily clobber the longjmp state. |
| 48903 | */ |
| 48904 | duk_push_tval(thr, tv_obj); |
| 48905 | |
| 48906 | /* Store and reset longjmp state. */ |
| 48907 | DUK_ASSERT_LJSTATE_SET(thr->heap); |
| 48908 | DUK_TVAL_DECREF_NORZ(thr, tv_obj); |
| 48909 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); /* Always for THROW type. */ |
| 48910 | DUK_TVAL_SET_UNDEFINED(tv_obj); |
| 48911 | thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN; |
| 48912 | DUK_ASSERT_LJSTATE_UNSET(thr->heap); |
| 48913 | |
| 48914 | #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) |
| 48915 | /* Report it to the debug client */ |
| 48916 | DUK_D(DUK_DPRINT("throw with debugger attached, report to client" )); |
| 48917 | duk_debug_send_throw(thr, uncaught); |
| 48918 | #endif |
| 48919 | |
| 48920 | if (uncaught) { |
| 48921 | if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_UNCAUGHT_ERROR) { |
| 48922 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by uncaught error" )); |
| 48923 | duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); |
| 48924 | } |
| 48925 | } else { |
| 48926 | if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_CAUGHT_ERROR) { |
| 48927 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by caught error" )); |
| 48928 | duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); |
| 48929 | } |
| 48930 | } |
| 48931 | |
| 48932 | /* Restore longjmp state. */ |
| 48933 | DUK_ASSERT_LJSTATE_UNSET(thr->heap); |
| 48934 | thr->heap->lj.type = DUK_LJ_TYPE_THROW; |
| 48935 | tv_obj = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 48936 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1)); |
| 48937 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); |
| 48938 | DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, tv_obj); |
| 48939 | DUK_TVAL_INCREF(thr, tv_obj); |
| 48940 | DUK_ASSERT_LJSTATE_SET(thr->heap); |
| 48941 | |
| 48942 | duk_pop(thr); |
| 48943 | } |
| 48944 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 48945 | |
| 48946 | /* |
| 48947 | * Helpers for setting up heap longjmp state. |
| 48948 | */ |
| 48949 | |
| 48950 | DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) { |
| 48951 | duk_heap *heap; |
| 48952 | |
| 48953 | DUK_ASSERT(thr != NULL); |
| 48954 | heap = thr->heap; |
| 48955 | DUK_ASSERT(heap != NULL); |
| 48956 | DUK_ASSERT(tv_val != NULL); |
| 48957 | |
| 48958 | DUK_ASSERT_LJSTATE_UNSET(heap); |
| 48959 | |
| 48960 | heap->lj.type = lj_type; |
| 48961 | DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val); |
| 48962 | DUK_TVAL_INCREF(thr, tv_val); |
| 48963 | |
| 48964 | DUK_ASSERT_LJSTATE_SET(heap); |
| 48965 | } |
| 48966 | #line 1 "duk_error_throw.c" |
| 48967 | /* |
| 48968 | * Create and throw an ECMAScript error object based on a code and a message. |
| 48969 | * |
| 48970 | * Used when we throw errors internally. ECMAScript generated error objects |
| 48971 | * are created by ECMAScript code, and the throwing is handled by the bytecode |
| 48972 | * executor. |
| 48973 | */ |
| 48974 | |
| 48975 | /* #include duk_internal.h -> already included */ |
| 48976 | |
| 48977 | /* |
| 48978 | * Create and throw an error (originating from Duktape internally) |
| 48979 | * |
| 48980 | * Push an error object on top of the stack, possibly throw augmenting |
| 48981 | * the error, and finally longjmp. |
| 48982 | * |
| 48983 | * If an error occurs while we're dealing with the current error, we might |
| 48984 | * enter an infinite recursion loop. This is prevented by detecting a |
| 48985 | * "double fault" through the heap->creating_error flag; the recursion |
| 48986 | * then stops at the second level. |
| 48987 | */ |
| 48988 | |
| 48989 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 48990 | DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) { |
| 48991 | #else |
| 48992 | DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) { |
| 48993 | #endif |
| 48994 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 48995 | DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld" , |
| 48996 | (long) code, (const char *) msg, |
| 48997 | (const char *) filename, (long) line)); |
| 48998 | #else |
| 48999 | DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld" , (long) code)); |
| 49000 | #endif |
| 49001 | |
| 49002 | DUK_ASSERT(thr != NULL); |
| 49003 | |
| 49004 | /* Even though nested call is possible because we throw an error when |
| 49005 | * trying to create an error, the potential errors must happen before |
| 49006 | * the longjmp state is configured. |
| 49007 | */ |
| 49008 | DUK_ASSERT_LJSTATE_UNSET(thr->heap); |
| 49009 | |
| 49010 | /* Sync so that augmentation sees up-to-date activations, NULL |
| 49011 | * thr->ptr_curr_pc so that it's not used if side effects occur |
| 49012 | * in augmentation or longjmp handling. |
| 49013 | */ |
| 49014 | duk_hthread_sync_and_null_currpc(thr); |
| 49015 | |
| 49016 | /* |
| 49017 | * Create and push an error object onto the top of stack. |
| 49018 | * The error is potentially augmented before throwing. |
| 49019 | * |
| 49020 | * If a "double error" occurs, use a fixed error instance |
| 49021 | * to avoid further trouble. |
| 49022 | */ |
| 49023 | |
| 49024 | if (thr->heap->creating_error) { |
| 49025 | duk_tval tv_val; |
| 49026 | duk_hobject *h_err; |
| 49027 | |
| 49028 | thr->heap->creating_error = 0; |
| 49029 | |
| 49030 | h_err = thr->builtins[DUK_BIDX_DOUBLE_ERROR]; |
| 49031 | if (h_err != NULL) { |
| 49032 | DUK_D(DUK_DPRINT("double fault detected -> use built-in fixed 'double error' instance" )); |
| 49033 | DUK_TVAL_SET_OBJECT(&tv_val, h_err); |
| 49034 | } else { |
| 49035 | DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance " |
| 49036 | "-> use the error code as a number" )); |
| 49037 | DUK_TVAL_SET_I32(&tv_val, (duk_int32_t) code); |
| 49038 | } |
| 49039 | |
| 49040 | duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, &tv_val); |
| 49041 | |
| 49042 | /* No augmentation to avoid any allocations or side effects. */ |
| 49043 | } else { |
| 49044 | /* Prevent infinite recursion. Extra call stack and C |
| 49045 | * recursion headroom (see GH-191) is added for augmentation. |
| 49046 | * That is now signalled by heap->augmenting error and taken |
| 49047 | * into account in call handling without an explicit limit bump. |
| 49048 | */ |
| 49049 | thr->heap->creating_error = 1; |
| 49050 | |
| 49051 | duk_require_stack(thr, 1); |
| 49052 | |
| 49053 | /* XXX: usually unnecessary '%s' formatting here, but cannot |
| 49054 | * use 'msg' as a format string directly. |
| 49055 | */ |
| 49056 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 49057 | duk_push_error_object_raw(thr, |
| 49058 | code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, |
| 49059 | filename, |
| 49060 | line, |
| 49061 | "%s" , |
| 49062 | (const char *) msg); |
| 49063 | #else |
| 49064 | duk_push_error_object_raw(thr, |
| 49065 | code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, |
| 49066 | NULL, |
| 49067 | 0, |
| 49068 | NULL); |
| 49069 | #endif |
| 49070 | |
| 49071 | /* Note that an alloc error may happen during error augmentation. |
| 49072 | * This may happen both when the original error is an alloc error |
| 49073 | * and when it's something else. Because any error in augmentation |
| 49074 | * must be handled correctly anyway, there's no special check for |
| 49075 | * avoiding it for alloc errors (this differs from Duktape 1.x). |
| 49076 | */ |
| 49077 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) |
| 49078 | DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)" , |
| 49079 | (duk_tval *) duk_get_tval(thr, -1))); |
| 49080 | duk_err_augment_error_throw(thr); |
| 49081 | #endif |
| 49082 | |
| 49083 | duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1)); |
| 49084 | thr->heap->creating_error = 0; |
| 49085 | |
| 49086 | /* Error is now created and we assume no errors can occur any |
| 49087 | * more. Check for debugger Throw integration only when the |
| 49088 | * error is complete. If we enter debugger message loop, |
| 49089 | * creating_error must be 0 so that errors can be thrown in |
| 49090 | * the paused state, e.g. in Eval commands. |
| 49091 | */ |
| 49092 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 49093 | duk_err_check_debugger_integration(thr); |
| 49094 | #endif |
| 49095 | } |
| 49096 | |
| 49097 | /* |
| 49098 | * Finally, longjmp |
| 49099 | */ |
| 49100 | |
| 49101 | DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)" , |
| 49102 | (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2)); |
| 49103 | |
| 49104 | duk_err_longjmp(thr); |
| 49105 | DUK_UNREACHABLE(); |
| 49106 | } |
| 49107 | |
| 49108 | /* |
| 49109 | * Helper for C function call negative return values. |
| 49110 | */ |
| 49111 | |
| 49112 | DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) { |
| 49113 | DUK_ASSERT(thr != NULL); |
| 49114 | DUK_ASSERT(rc < 0); |
| 49115 | |
| 49116 | /* |
| 49117 | * The __FILE__ and __LINE__ information is intentionally not used in the |
| 49118 | * creation of the error object, as it isn't useful in the tracedata. The |
| 49119 | * tracedata still contains the function which returned the negative return |
| 49120 | * code, and having the file/line of this function isn't very useful. |
| 49121 | * |
| 49122 | * The error messages for DUK_RET_xxx shorthand are intentionally very |
| 49123 | * minimal: they're only really useful for low memory targets. |
| 49124 | */ |
| 49125 | |
| 49126 | duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)" , (long) rc); |
| 49127 | DUK_WO_NORETURN(return;); |
| 49128 | } |
| 49129 | #line 1 "duk_hbuffer_alloc.c" |
| 49130 | /* |
| 49131 | * duk_hbuffer allocation and freeing. |
| 49132 | */ |
| 49133 | |
| 49134 | /* #include duk_internal.h -> already included */ |
| 49135 | |
| 49136 | /* Allocate a new duk_hbuffer of a certain type and return a pointer to it |
| 49137 | * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if |
| 49138 | * allocation successful). |
| 49139 | */ |
| 49140 | DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) { |
| 49141 | duk_hbuffer *res = NULL; |
| 49142 | duk_size_t ; |
| 49143 | duk_size_t alloc_size; |
| 49144 | |
| 49145 | DUK_ASSERT(heap != NULL); |
| 49146 | DUK_ASSERT(out_bufdata != NULL); |
| 49147 | |
| 49148 | DUK_DDD(DUK_DDDPRINT("allocate hbuffer" )); |
| 49149 | |
| 49150 | /* Size sanity check. Should not be necessary because caller is |
| 49151 | * required to check this, but we don't want to cause a segfault |
| 49152 | * if the size wraps either in duk_size_t computation or when |
| 49153 | * storing the size in a 16-bit field. |
| 49154 | */ |
| 49155 | if (size > DUK_HBUFFER_MAX_BYTELEN) { |
| 49156 | DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld" , (long) size)); |
| 49157 | return NULL; /* no need to write 'out_bufdata' */ |
| 49158 | } |
| 49159 | |
| 49160 | if (flags & DUK_BUF_FLAG_EXTERNAL) { |
| 49161 | header_size = sizeof(duk_hbuffer_external); |
| 49162 | alloc_size = sizeof(duk_hbuffer_external); |
| 49163 | } else if (flags & DUK_BUF_FLAG_DYNAMIC) { |
| 49164 | header_size = sizeof(duk_hbuffer_dynamic); |
| 49165 | alloc_size = sizeof(duk_hbuffer_dynamic); |
| 49166 | } else { |
| 49167 | header_size = sizeof(duk_hbuffer_fixed); |
| 49168 | alloc_size = sizeof(duk_hbuffer_fixed) + size; |
| 49169 | DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */ |
| 49170 | } |
| 49171 | |
| 49172 | res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size); |
| 49173 | if (DUK_UNLIKELY(res == NULL)) { |
| 49174 | goto alloc_error; |
| 49175 | } |
| 49176 | |
| 49177 | /* zero everything unless requested not to do so */ |
| 49178 | #if defined(DUK_USE_ZERO_BUFFER_DATA) |
| 49179 | duk_memzero((void *) res, |
| 49180 | (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size); |
| 49181 | #else |
| 49182 | duk_memzero((void *) res, header_size); |
| 49183 | #endif |
| 49184 | |
| 49185 | if (flags & DUK_BUF_FLAG_EXTERNAL) { |
| 49186 | duk_hbuffer_external *h; |
| 49187 | h = (duk_hbuffer_external *) res; |
| 49188 | DUK_UNREF(h); |
| 49189 | *out_bufdata = NULL; |
| 49190 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 49191 | #if defined(DUK_USE_HEAPPTR16) |
| 49192 | /* the compressed pointer is zeroed which maps to NULL, so nothing to do. */ |
| 49193 | #else |
| 49194 | DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL); |
| 49195 | #endif |
| 49196 | #endif |
| 49197 | DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL); |
| 49198 | } else if (flags & DUK_BUF_FLAG_DYNAMIC) { |
| 49199 | duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res; |
| 49200 | void *ptr; |
| 49201 | |
| 49202 | if (size > 0) { |
| 49203 | DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */ |
| 49204 | DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer" )); |
| 49205 | #if defined(DUK_USE_ZERO_BUFFER_DATA) |
| 49206 | ptr = DUK_ALLOC_ZEROED(heap, size); |
| 49207 | #else |
| 49208 | ptr = DUK_ALLOC(heap, size); |
| 49209 | #endif |
| 49210 | if (DUK_UNLIKELY(ptr == NULL)) { |
| 49211 | /* Because size > 0, NULL check is correct */ |
| 49212 | goto alloc_error; |
| 49213 | } |
| 49214 | *out_bufdata = ptr; |
| 49215 | |
| 49216 | DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr); |
| 49217 | } else { |
| 49218 | *out_bufdata = NULL; |
| 49219 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 49220 | #if defined(DUK_USE_HEAPPTR16) |
| 49221 | /* the compressed pointer is zeroed which maps to NULL, so nothing to do. */ |
| 49222 | #else |
| 49223 | DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL); |
| 49224 | #endif |
| 49225 | #endif |
| 49226 | DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL); |
| 49227 | } |
| 49228 | } else { |
| 49229 | *out_bufdata = (void *) ((duk_hbuffer_fixed *) (void *) res + 1); |
| 49230 | } |
| 49231 | |
| 49232 | DUK_HBUFFER_SET_SIZE(res, size); |
| 49233 | |
| 49234 | DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER); |
| 49235 | if (flags & DUK_BUF_FLAG_DYNAMIC) { |
| 49236 | DUK_HBUFFER_SET_DYNAMIC(res); |
| 49237 | if (flags & DUK_BUF_FLAG_EXTERNAL) { |
| 49238 | DUK_HBUFFER_SET_EXTERNAL(res); |
| 49239 | } |
| 49240 | } else { |
| 49241 | DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); |
| 49242 | } |
| 49243 | DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr); |
| 49244 | |
| 49245 | DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p" , (void *) res)); |
| 49246 | return res; |
| 49247 | |
| 49248 | alloc_error: |
| 49249 | DUK_DD(DUK_DDPRINT("hbuffer allocation failed" )); |
| 49250 | |
| 49251 | DUK_FREE(heap, res); |
| 49252 | return NULL; /* no need to write 'out_bufdata' */ |
| 49253 | } |
| 49254 | |
| 49255 | /* For indirect allocs. */ |
| 49256 | |
| 49257 | DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) { |
| 49258 | duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud; |
| 49259 | DUK_UNREF(heap); |
| 49260 | return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf); |
| 49261 | } |
| 49262 | #line 1 "duk_hbuffer_assert.c" |
| 49263 | /* |
| 49264 | * duk_hbuffer assertion helpers |
| 49265 | */ |
| 49266 | |
| 49267 | /* #include duk_internal.h -> already included */ |
| 49268 | |
| 49269 | #if defined(DUK_USE_ASSERTIONS) |
| 49270 | |
| 49271 | DUK_INTERNAL void duk_hbuffer_assert_valid(duk_hbuffer *h) { |
| 49272 | DUK_ASSERT(h != NULL); |
| 49273 | } |
| 49274 | |
| 49275 | #endif /* DUK_USE_ASSERTIONS */ |
| 49276 | #line 1 "duk_hbuffer_ops.c" |
| 49277 | /* |
| 49278 | * duk_hbuffer operations such as resizing and inserting/appending data to |
| 49279 | * a dynamic buffer. |
| 49280 | */ |
| 49281 | |
| 49282 | /* #include duk_internal.h -> already included */ |
| 49283 | |
| 49284 | /* |
| 49285 | * Resizing |
| 49286 | */ |
| 49287 | |
| 49288 | DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) { |
| 49289 | void *res; |
| 49290 | duk_size_t prev_size; |
| 49291 | |
| 49292 | DUK_ASSERT(thr != NULL); |
| 49293 | DUK_ASSERT(buf != NULL); |
| 49294 | DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf)); |
| 49295 | DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf)); |
| 49296 | |
| 49297 | /* |
| 49298 | * Maximum size check |
| 49299 | */ |
| 49300 | |
| 49301 | if (new_size > DUK_HBUFFER_MAX_BYTELEN) { |
| 49302 | DUK_ERROR_RANGE(thr, "buffer too long" ); |
| 49303 | DUK_WO_NORETURN(return;); |
| 49304 | } |
| 49305 | |
| 49306 | /* |
| 49307 | * Note: use indirect realloc variant just in case mark-and-sweep |
| 49308 | * (finalizers) might resize this same buffer during garbage |
| 49309 | * collection. |
| 49310 | */ |
| 49311 | |
| 49312 | res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size); |
| 49313 | if (DUK_LIKELY(res != NULL || new_size == 0)) { |
| 49314 | /* 'res' may be NULL if new allocation size is 0. */ |
| 49315 | |
| 49316 | DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld" , |
| 49317 | (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf), |
| 49318 | (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf), |
| 49319 | (void *) res, |
| 49320 | (long) new_size)); |
| 49321 | |
| 49322 | /* |
| 49323 | * The entire allocated buffer area, regardless of actual used |
| 49324 | * size, is kept zeroed in resizes for simplicity. If the buffer |
| 49325 | * is grown, zero the new part. |
| 49326 | */ |
| 49327 | |
| 49328 | prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf); |
| 49329 | if (new_size > prev_size) { |
| 49330 | DUK_ASSERT(new_size - prev_size > 0); |
| 49331 | #if defined(DUK_USE_ZERO_BUFFER_DATA) |
| 49332 | duk_memzero((void *) ((char *) res + prev_size), |
| 49333 | (duk_size_t) (new_size - prev_size)); |
| 49334 | #endif |
| 49335 | } |
| 49336 | |
| 49337 | DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size); |
| 49338 | DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res); |
| 49339 | } else { |
| 49340 | DUK_ERROR_ALLOC_FAILED(thr); |
| 49341 | DUK_WO_NORETURN(return;); |
| 49342 | } |
| 49343 | |
| 49344 | DUK_ASSERT(res != NULL || new_size == 0); |
| 49345 | } |
| 49346 | |
| 49347 | DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) { |
| 49348 | DUK_ASSERT(thr != NULL); |
| 49349 | DUK_ASSERT(buf != NULL); |
| 49350 | DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf)); |
| 49351 | DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf)); |
| 49352 | |
| 49353 | duk_hbuffer_resize(thr, buf, 0); |
| 49354 | } |
| 49355 | /* #include duk_internal.h -> already included */ |
| 49356 | #line 2 "duk_hbufobj_misc.c" |
| 49357 | |
| 49358 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 49359 | DUK_INTERNAL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len) { |
| 49360 | duk_uint_t buf_size; |
| 49361 | duk_uint_t buf_avail; |
| 49362 | |
| 49363 | DUK_ASSERT(h_bufobj != NULL); |
| 49364 | DUK_ASSERT(h_bufobj->buf != NULL); |
| 49365 | |
| 49366 | buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf); |
| 49367 | if (h_bufobj->offset > buf_size) { |
| 49368 | /* Slice starting point is beyond current length. */ |
| 49369 | return 0; |
| 49370 | } |
| 49371 | buf_avail = buf_size - h_bufobj->offset; |
| 49372 | |
| 49373 | return buf_avail >= len ? len : buf_avail; |
| 49374 | } |
| 49375 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 49376 | #line 1 "duk_heap_alloc.c" |
| 49377 | /* |
| 49378 | * duk_heap allocation and freeing. |
| 49379 | */ |
| 49380 | |
| 49381 | /* #include duk_internal.h -> already included */ |
| 49382 | |
| 49383 | #if defined(DUK_USE_ROM_STRINGS) |
| 49384 | /* Fixed seed value used with ROM strings. */ |
| 49385 | #define DUK__FIXED_HASH_SEED 0xabcd1234 |
| 49386 | #endif |
| 49387 | |
| 49388 | /* |
| 49389 | * Free a heap object. |
| 49390 | * |
| 49391 | * Free heap object and its internal (non-heap) pointers. Assumes that |
| 49392 | * caller has removed the object from heap allocated list or the string |
| 49393 | * intern table, and any weak references (which strings may have) have |
| 49394 | * been already dealt with. |
| 49395 | */ |
| 49396 | |
| 49397 | DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) { |
| 49398 | DUK_ASSERT(heap != NULL); |
| 49399 | DUK_ASSERT(h != NULL); |
| 49400 | |
| 49401 | DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h)); |
| 49402 | |
| 49403 | if (DUK_HOBJECT_IS_COMPFUNC(h)) { |
| 49404 | duk_hcompfunc *f = (duk_hcompfunc *) h; |
| 49405 | DUK_UNREF(f); |
| 49406 | /* Currently nothing to free; 'data' is a heap object */ |
| 49407 | } else if (DUK_HOBJECT_IS_NATFUNC(h)) { |
| 49408 | duk_hnatfunc *f = (duk_hnatfunc *) h; |
| 49409 | DUK_UNREF(f); |
| 49410 | /* Currently nothing to free */ |
| 49411 | } else if (DUK_HOBJECT_IS_THREAD(h)) { |
| 49412 | duk_hthread *t = (duk_hthread *) h; |
| 49413 | duk_activation *act; |
| 49414 | |
| 49415 | DUK_FREE(heap, t->valstack); |
| 49416 | |
| 49417 | /* Don't free h->resumer because it exists in the heap. |
| 49418 | * Callstack entries also contain function pointers which |
| 49419 | * are not freed for the same reason. They are decref |
| 49420 | * finalized and the targets are freed if necessary based |
| 49421 | * on their refcount (or reachability). |
| 49422 | */ |
| 49423 | for (act = t->callstack_curr; act != NULL;) { |
| 49424 | duk_activation *act_next; |
| 49425 | duk_catcher *cat; |
| 49426 | |
| 49427 | for (cat = act->cat; cat != NULL;) { |
| 49428 | duk_catcher *cat_next; |
| 49429 | |
| 49430 | cat_next = cat->parent; |
| 49431 | DUK_FREE(heap, (void *) cat); |
| 49432 | cat = cat_next; |
| 49433 | } |
| 49434 | |
| 49435 | act_next = act->parent; |
| 49436 | DUK_FREE(heap, (void *) act); |
| 49437 | act = act_next; |
| 49438 | } |
| 49439 | |
| 49440 | /* XXX: with 'caller' property the callstack would need |
| 49441 | * to be unwound to update the 'caller' properties of |
| 49442 | * functions in the callstack. |
| 49443 | */ |
| 49444 | } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { |
| 49445 | duk_hboundfunc *f = (duk_hboundfunc *) (void *) h; |
| 49446 | |
| 49447 | DUK_FREE(heap, f->args); |
| 49448 | } |
| 49449 | |
| 49450 | DUK_FREE(heap, (void *) h); |
| 49451 | } |
| 49452 | |
| 49453 | DUK_INTERNAL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h) { |
| 49454 | DUK_ASSERT(heap != NULL); |
| 49455 | DUK_ASSERT(h != NULL); |
| 49456 | |
| 49457 | if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) { |
| 49458 | duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h; |
| 49459 | DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p" , (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g))); |
| 49460 | DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)); |
| 49461 | } |
| 49462 | DUK_FREE(heap, (void *) h); |
| 49463 | } |
| 49464 | |
| 49465 | DUK_INTERNAL void duk_free_hstring(duk_heap *heap, duk_hstring *h) { |
| 49466 | DUK_ASSERT(heap != NULL); |
| 49467 | DUK_ASSERT(h != NULL); |
| 49468 | |
| 49469 | DUK_UNREF(heap); |
| 49470 | DUK_UNREF(h); |
| 49471 | |
| 49472 | #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE) |
| 49473 | if (DUK_HSTRING_HAS_EXTDATA(h)) { |
| 49474 | DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p" , |
| 49475 | h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h))); |
| 49476 | DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)); |
| 49477 | } |
| 49478 | #endif |
| 49479 | DUK_FREE(heap, (void *) h); |
| 49480 | } |
| 49481 | |
| 49482 | DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) { |
| 49483 | DUK_ASSERT(heap); |
| 49484 | DUK_ASSERT(hdr); |
| 49485 | |
| 49486 | DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld" , (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr))); |
| 49487 | |
| 49488 | switch (DUK_HEAPHDR_GET_TYPE(hdr)) { |
| 49489 | case DUK_HTYPE_STRING: |
| 49490 | duk_free_hstring(heap, (duk_hstring *) hdr); |
| 49491 | break; |
| 49492 | case DUK_HTYPE_OBJECT: |
| 49493 | duk_free_hobject(heap, (duk_hobject *) hdr); |
| 49494 | break; |
| 49495 | default: |
| 49496 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER); |
| 49497 | duk_free_hbuffer(heap, (duk_hbuffer *) hdr); |
| 49498 | } |
| 49499 | |
| 49500 | } |
| 49501 | |
| 49502 | /* |
| 49503 | * Free the heap. |
| 49504 | * |
| 49505 | * Frees heap-related non-heap-tracked allocations such as the |
| 49506 | * string intern table; then frees the heap allocated objects; |
| 49507 | * and finally frees the heap structure itself. Reference counts |
| 49508 | * and GC markers are ignored (and not updated) in this process, |
| 49509 | * and finalizers won't be called. |
| 49510 | * |
| 49511 | * The heap pointer and heap object pointers must not be used |
| 49512 | * after this call. |
| 49513 | */ |
| 49514 | |
| 49515 | #if defined(DUK_USE_CACHE_ACTIVATION) |
| 49516 | DUK_LOCAL duk_size_t duk__heap_free_activation_freelist(duk_heap *heap) { |
| 49517 | duk_activation *act; |
| 49518 | duk_activation *act_next; |
| 49519 | duk_size_t count_act = 0; |
| 49520 | |
| 49521 | for (act = heap->activation_free; act != NULL;) { |
| 49522 | act_next = act->parent; |
| 49523 | DUK_FREE(heap, (void *) act); |
| 49524 | act = act_next; |
| 49525 | #if defined(DUK_USE_DEBUG) |
| 49526 | count_act++; |
| 49527 | #endif |
| 49528 | } |
| 49529 | heap->activation_free = NULL; /* needed when called from mark-and-sweep */ |
| 49530 | return count_act; |
| 49531 | } |
| 49532 | #endif /* DUK_USE_CACHE_ACTIVATION */ |
| 49533 | |
| 49534 | #if defined(DUK_USE_CACHE_CATCHER) |
| 49535 | DUK_LOCAL duk_size_t duk__heap_free_catcher_freelist(duk_heap *heap) { |
| 49536 | duk_catcher *cat; |
| 49537 | duk_catcher *cat_next; |
| 49538 | duk_size_t count_cat = 0; |
| 49539 | |
| 49540 | for (cat = heap->catcher_free; cat != NULL;) { |
| 49541 | cat_next = cat->parent; |
| 49542 | DUK_FREE(heap, (void *) cat); |
| 49543 | cat = cat_next; |
| 49544 | #if defined(DUK_USE_DEBUG) |
| 49545 | count_cat++; |
| 49546 | #endif |
| 49547 | } |
| 49548 | heap->catcher_free = NULL; /* needed when called from mark-and-sweep */ |
| 49549 | |
| 49550 | return count_cat; |
| 49551 | } |
| 49552 | #endif /* DUK_USE_CACHE_CATCHER */ |
| 49553 | |
| 49554 | DUK_INTERNAL void duk_heap_free_freelists(duk_heap *heap) { |
| 49555 | duk_size_t count_act = 0; |
| 49556 | duk_size_t count_cat = 0; |
| 49557 | |
| 49558 | #if defined(DUK_USE_CACHE_ACTIVATION) |
| 49559 | count_act = duk__heap_free_activation_freelist(heap); |
| 49560 | #endif |
| 49561 | #if defined(DUK_USE_CACHE_CATCHER) |
| 49562 | count_cat = duk__heap_free_catcher_freelist(heap); |
| 49563 | #endif |
| 49564 | DUK_UNREF(heap); |
| 49565 | DUK_UNREF(count_act); |
| 49566 | DUK_UNREF(count_cat); |
| 49567 | |
| 49568 | DUK_D(DUK_DPRINT("freed %ld activation freelist entries, %ld catcher freelist entries" , |
| 49569 | (long) count_act, (long) count_cat)); |
| 49570 | } |
| 49571 | |
| 49572 | DUK_LOCAL void duk__free_allocated(duk_heap *heap) { |
| 49573 | duk_heaphdr *curr; |
| 49574 | duk_heaphdr *next; |
| 49575 | |
| 49576 | curr = heap->heap_allocated; |
| 49577 | while (curr) { |
| 49578 | /* We don't log or warn about freeing zero refcount objects |
| 49579 | * because they may happen with finalizer processing. |
| 49580 | */ |
| 49581 | |
| 49582 | DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO" , |
| 49583 | (duk_heaphdr *) curr)); |
| 49584 | next = DUK_HEAPHDR_GET_NEXT(heap, curr); |
| 49585 | duk_heap_free_heaphdr_raw(heap, curr); |
| 49586 | curr = next; |
| 49587 | } |
| 49588 | } |
| 49589 | |
| 49590 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 49591 | DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) { |
| 49592 | duk_heaphdr *curr; |
| 49593 | duk_heaphdr *next; |
| 49594 | |
| 49595 | curr = heap->finalize_list; |
| 49596 | while (curr) { |
| 49597 | DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO" , |
| 49598 | (duk_heaphdr *) curr)); |
| 49599 | next = DUK_HEAPHDR_GET_NEXT(heap, curr); |
| 49600 | duk_heap_free_heaphdr_raw(heap, curr); |
| 49601 | curr = next; |
| 49602 | } |
| 49603 | } |
| 49604 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 49605 | |
| 49606 | DUK_LOCAL void duk__free_stringtable(duk_heap *heap) { |
| 49607 | /* strings are only tracked by stringtable */ |
| 49608 | duk_heap_strtable_free(heap); |
| 49609 | } |
| 49610 | |
| 49611 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 49612 | DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) { |
| 49613 | duk_heaphdr *curr; |
| 49614 | duk_uint_t round_no; |
| 49615 | duk_size_t count_all; |
| 49616 | duk_size_t count_finalized; |
| 49617 | duk_size_t curr_limit; |
| 49618 | |
| 49619 | DUK_ASSERT(heap != NULL); |
| 49620 | |
| 49621 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 49622 | DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */ |
| 49623 | #endif |
| 49624 | DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep last pass */ |
| 49625 | |
| 49626 | if (heap->heap_thread == NULL) { |
| 49627 | /* May happen when heap allocation fails right off. There |
| 49628 | * cannot be any finalizable objects in this case. |
| 49629 | */ |
| 49630 | DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects" )); |
| 49631 | return; |
| 49632 | } |
| 49633 | |
| 49634 | /* Prevent finalize_list processing and mark-and-sweep entirely. |
| 49635 | * Setting ms_running != 0 also prevents refzero handling from moving |
| 49636 | * objects away from the heap_allocated list. The flag name is a bit |
| 49637 | * misleading here. |
| 49638 | * |
| 49639 | * Use a distinct value for ms_running here (== 2) so that assertions |
| 49640 | * can detect this situation separate from the normal runtime |
| 49641 | * mark-and-sweep case. This allows better assertions (GH-2030). |
| 49642 | */ |
| 49643 | DUK_ASSERT(heap->pf_prevent_count == 0); |
| 49644 | DUK_ASSERT(heap->ms_running == 0); |
| 49645 | DUK_ASSERT(heap->ms_prevent_count == 0); |
| 49646 | heap->pf_prevent_count = 1; |
| 49647 | heap->ms_running = 2; /* Use distinguishable value. */ |
| 49648 | heap->ms_prevent_count = 1; /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */ |
| 49649 | |
| 49650 | curr_limit = 0; /* suppress warning, not used */ |
| 49651 | for (round_no = 0; ; round_no++) { |
| 49652 | curr = heap->heap_allocated; |
| 49653 | count_all = 0; |
| 49654 | count_finalized = 0; |
| 49655 | while (curr) { |
| 49656 | count_all++; |
| 49657 | if (DUK_HEAPHDR_IS_OBJECT(curr)) { |
| 49658 | /* Only objects in heap_allocated may have finalizers. Check that |
| 49659 | * the object itself has a _Finalizer property (own or inherited) |
| 49660 | * so that we don't execute finalizers for e.g. Proxy objects. |
| 49661 | */ |
| 49662 | DUK_ASSERT(curr != NULL); |
| 49663 | |
| 49664 | if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) { |
| 49665 | if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) { |
| 49666 | DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */ |
| 49667 | duk_heap_run_finalizer(heap, (duk_hobject *) curr); |
| 49668 | count_finalized++; |
| 49669 | } |
| 49670 | } |
| 49671 | } |
| 49672 | curr = DUK_HEAPHDR_GET_NEXT(heap, curr); |
| 49673 | } |
| 49674 | |
| 49675 | /* Each round of finalizer execution may spawn new finalizable objects |
| 49676 | * which is normal behavior for some applications. Allow multiple |
| 49677 | * rounds of finalization, but use a shrinking limit based on the |
| 49678 | * first round to detect the case where a runaway finalizer creates |
| 49679 | * an unbounded amount of new finalizable objects. Finalizer rescue |
| 49680 | * is not supported: the semantics are unclear because most of the |
| 49681 | * objects being finalized here are already reachable. The finalizer |
| 49682 | * is given a boolean to indicate that rescue is not possible. |
| 49683 | * |
| 49684 | * See discussion in: https://github.com/svaarala/duktape/pull/473 |
| 49685 | */ |
| 49686 | |
| 49687 | if (round_no == 0) { |
| 49688 | /* Cannot wrap: each object is at least 8 bytes so count is |
| 49689 | * at most 1/8 of that. |
| 49690 | */ |
| 49691 | curr_limit = count_all * 2; |
| 49692 | } else { |
| 49693 | curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */ |
| 49694 | } |
| 49695 | DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld" , |
| 49696 | (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit)); |
| 49697 | |
| 49698 | if (count_finalized == 0) { |
| 49699 | DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished" )); |
| 49700 | break; |
| 49701 | } |
| 49702 | if (count_finalized >= curr_limit) { |
| 49703 | DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers" )); |
| 49704 | break; |
| 49705 | } |
| 49706 | } |
| 49707 | |
| 49708 | DUK_ASSERT(heap->ms_running == 2); |
| 49709 | DUK_ASSERT(heap->pf_prevent_count == 1); |
| 49710 | heap->ms_running = 0; |
| 49711 | heap->pf_prevent_count = 0; |
| 49712 | } |
| 49713 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 49714 | |
| 49715 | DUK_INTERNAL void duk_heap_free(duk_heap *heap) { |
| 49716 | DUK_D(DUK_DPRINT("free heap: %p" , (void *) heap)); |
| 49717 | |
| 49718 | #if defined(DUK_USE_DEBUG) |
| 49719 | duk_heap_strtable_dump(heap); |
| 49720 | #endif |
| 49721 | |
| 49722 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 49723 | /* Detach a debugger if attached (can be called multiple times) |
| 49724 | * safely. |
| 49725 | */ |
| 49726 | /* XXX: Add a flag to reject an attempt to re-attach? Otherwise |
| 49727 | * the detached callback may immediately reattach. |
| 49728 | */ |
| 49729 | duk_debug_do_detach(heap); |
| 49730 | #endif |
| 49731 | |
| 49732 | /* Execute finalizers before freeing the heap, even for reachable |
| 49733 | * objects. This gives finalizers the chance to free any native |
| 49734 | * resources like file handles, allocations made outside Duktape, |
| 49735 | * etc. This is quite tricky to get right, so that all finalizer |
| 49736 | * guarantees are honored. |
| 49737 | * |
| 49738 | * Run mark-and-sweep a few times just in case (unreachable object |
| 49739 | * finalizers run already here). The last round must rescue objects |
| 49740 | * from the previous round without running any more finalizers. This |
| 49741 | * ensures rescued objects get their FINALIZED flag cleared so that |
| 49742 | * their finalizer is called once more in forced finalization to |
| 49743 | * satisfy finalizer guarantees. However, we don't want to run any |
| 49744 | * more finalizers because that'd required one more loop, and so on. |
| 49745 | * |
| 49746 | * XXX: this perhaps requires an execution time limit. |
| 49747 | */ |
| 49748 | DUK_D(DUK_DPRINT("execute finalizers before freeing heap" )); |
| 49749 | DUK_ASSERT(heap->pf_skip_finalizers == 0); |
| 49750 | DUK_D(DUK_DPRINT("forced gc #1 in heap destruction" )); |
| 49751 | duk_heap_mark_and_sweep(heap, 0); |
| 49752 | DUK_D(DUK_DPRINT("forced gc #2 in heap destruction" )); |
| 49753 | duk_heap_mark_and_sweep(heap, 0); |
| 49754 | DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)" )); |
| 49755 | heap->pf_skip_finalizers = 1; |
| 49756 | duk_heap_mark_and_sweep(heap, 0); /* Skip finalizers; queue finalizable objects to heap_allocated. */ |
| 49757 | |
| 49758 | /* There are never objects in refzero_list at this point, or at any |
| 49759 | * point beyond a DECREF (even a DECREF_NORZ). Since Duktape 2.1 |
| 49760 | * refzero_list processing is side effect free, so it is always |
| 49761 | * processed to completion by a DECREF initially triggering a zero |
| 49762 | * refcount. |
| 49763 | */ |
| 49764 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 49765 | DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ |
| 49766 | #endif |
| 49767 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 49768 | DUK_ASSERT(heap->finalize_list == NULL); /* Last mark-and-sweep with skip_finalizers. */ |
| 49769 | #endif |
| 49770 | |
| 49771 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 49772 | DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects" )); |
| 49773 | DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* Rescue no longer supported. */ |
| 49774 | duk__free_run_finalizers(heap); |
| 49775 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 49776 | |
| 49777 | /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object |
| 49778 | * are on the heap allocated list. |
| 49779 | */ |
| 49780 | |
| 49781 | DUK_D(DUK_DPRINT("freeing temporary freelists" )); |
| 49782 | duk_heap_free_freelists(heap); |
| 49783 | |
| 49784 | DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p" , (void *) heap)); |
| 49785 | duk__free_allocated(heap); |
| 49786 | |
| 49787 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 49788 | DUK_ASSERT(heap->refzero_list == NULL); /* Always processed to completion inline. */ |
| 49789 | #endif |
| 49790 | |
| 49791 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 49792 | DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p" , (void *) heap)); |
| 49793 | duk__free_finalize_list(heap); |
| 49794 | #endif |
| 49795 | |
| 49796 | DUK_D(DUK_DPRINT("freeing string table of heap: %p" , (void *) heap)); |
| 49797 | duk__free_stringtable(heap); |
| 49798 | |
| 49799 | DUK_D(DUK_DPRINT("freeing heap structure: %p" , (void *) heap)); |
| 49800 | heap->free_func(heap->heap_udata, heap); |
| 49801 | } |
| 49802 | |
| 49803 | /* |
| 49804 | * Allocate a heap. |
| 49805 | * |
| 49806 | * String table is initialized with built-in strings from genbuiltins.py, |
| 49807 | * either by dynamically creating the strings or by referring to ROM strings. |
| 49808 | */ |
| 49809 | |
| 49810 | #if defined(DUK_USE_ROM_STRINGS) |
| 49811 | DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) { |
| 49812 | #if defined(DUK_USE_ASSERTIONS) |
| 49813 | duk_small_uint_t i; |
| 49814 | #endif |
| 49815 | |
| 49816 | DUK_UNREF(heap); |
| 49817 | |
| 49818 | /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted |
| 49819 | * so nothing to initialize for strs[]. |
| 49820 | */ |
| 49821 | |
| 49822 | #if defined(DUK_USE_ASSERTIONS) |
| 49823 | for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) { |
| 49824 | const duk_hstring *h; |
| 49825 | duk_uint32_t hash; |
| 49826 | |
| 49827 | h = duk_rom_strings_lookup[i]; |
| 49828 | while (h != NULL) { |
| 49829 | hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); |
| 49830 | DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx" , |
| 49831 | (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash)); |
| 49832 | DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h)); |
| 49833 | |
| 49834 | h = (const duk_hstring *) h->hdr.h_next; |
| 49835 | } |
| 49836 | } |
| 49837 | #endif |
| 49838 | return 1; |
| 49839 | } |
| 49840 | #else /* DUK_USE_ROM_STRINGS */ |
| 49841 | |
| 49842 | DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) { |
| 49843 | duk_bitdecoder_ctx bd_ctx; |
| 49844 | duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ |
| 49845 | duk_small_uint_t i; |
| 49846 | |
| 49847 | duk_memzero(&bd_ctx, sizeof(bd_ctx)); |
| 49848 | bd->data = (const duk_uint8_t *) duk_strings_data; |
| 49849 | bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH; |
| 49850 | |
| 49851 | for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { |
| 49852 | duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN]; |
| 49853 | duk_small_uint_t len; |
| 49854 | duk_hstring *h; |
| 49855 | |
| 49856 | len = duk_bd_decode_bitpacked_string(bd, tmp); |
| 49857 | |
| 49858 | /* No need to length check string: it will never exceed even |
| 49859 | * the 16-bit length maximum. |
| 49860 | */ |
| 49861 | DUK_ASSERT(len <= 0xffffUL); |
| 49862 | DUK_DDD(DUK_DDDPRINT("intern built-in string %ld" , (long) i)); |
| 49863 | h = duk_heap_strtable_intern(heap, tmp, len); |
| 49864 | if (!h) { |
| 49865 | goto failed; |
| 49866 | } |
| 49867 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); |
| 49868 | |
| 49869 | /* Special flags checks. Since these strings are always |
| 49870 | * reachable and a string cannot appear twice in the string |
| 49871 | * table, there's no need to check/set these flags elsewhere. |
| 49872 | * The 'internal' flag is set by string intern code. |
| 49873 | */ |
| 49874 | if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) { |
| 49875 | DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h); |
| 49876 | } |
| 49877 | if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) { |
| 49878 | DUK_HSTRING_SET_RESERVED_WORD(h); |
| 49879 | if (i >= DUK_STRIDX_START_STRICT_RESERVED) { |
| 49880 | DUK_HSTRING_SET_STRICT_RESERVED_WORD(h); |
| 49881 | } |
| 49882 | } |
| 49883 | |
| 49884 | DUK_DDD(DUK_DDDPRINT("interned: %!O" , (duk_heaphdr *) h)); |
| 49885 | |
| 49886 | /* XXX: The incref macro takes a thread pointer but doesn't |
| 49887 | * use it right now. |
| 49888 | */ |
| 49889 | DUK_HSTRING_INCREF(_never_referenced_, h); |
| 49890 | |
| 49891 | #if defined(DUK_USE_HEAPPTR16) |
| 49892 | heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h); |
| 49893 | #else |
| 49894 | heap->strs[i] = h; |
| 49895 | #endif |
| 49896 | } |
| 49897 | |
| 49898 | return 1; |
| 49899 | |
| 49900 | failed: |
| 49901 | return 0; |
| 49902 | } |
| 49903 | #endif /* DUK_USE_ROM_STRINGS */ |
| 49904 | |
| 49905 | DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) { |
| 49906 | duk_hthread *thr; |
| 49907 | |
| 49908 | DUK_D(DUK_DPRINT("heap init: alloc heap thread" )); |
| 49909 | thr = duk_hthread_alloc_unchecked(heap, |
| 49910 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 49911 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD)); |
| 49912 | if (thr == NULL) { |
| 49913 | DUK_D(DUK_DPRINT("failed to alloc heap_thread" )); |
| 49914 | return 0; |
| 49915 | } |
| 49916 | thr->state = DUK_HTHREAD_STATE_INACTIVE; |
| 49917 | #if defined(DUK_USE_ROM_STRINGS) |
| 49918 | /* No strs[] pointer. */ |
| 49919 | #else /* DUK_USE_ROM_STRINGS */ |
| 49920 | #if defined(DUK_USE_HEAPPTR16) |
| 49921 | thr->strs16 = heap->strs16; |
| 49922 | #else |
| 49923 | thr->strs = heap->strs; |
| 49924 | #endif |
| 49925 | #endif /* DUK_USE_ROM_STRINGS */ |
| 49926 | |
| 49927 | heap->heap_thread = thr; |
| 49928 | DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */ |
| 49929 | |
| 49930 | /* 'thr' is now reachable */ |
| 49931 | |
| 49932 | DUK_D(DUK_DPRINT("heap init: init heap thread stacks" )); |
| 49933 | if (!duk_hthread_init_stacks(heap, thr)) { |
| 49934 | return 0; |
| 49935 | } |
| 49936 | |
| 49937 | /* XXX: this may now fail, and is not handled correctly */ |
| 49938 | duk_hthread_create_builtin_objects(thr); |
| 49939 | |
| 49940 | /* default prototype */ |
| 49941 | DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]); |
| 49942 | |
| 49943 | return 1; |
| 49944 | } |
| 49945 | |
| 49946 | #if defined(DUK_USE_DEBUG) |
| 49947 | #define DUK__DUMPSZ(t) do { \ |
| 49948 | DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \ |
| 49949 | } while (0) |
| 49950 | |
| 49951 | /* These is not 100% because format would need to be non-portable "long long". |
| 49952 | * Also print out as doubles to catch cases where the "long" type is not wide |
| 49953 | * enough; the limits will then not be printed accurately but the magnitude |
| 49954 | * will be correct. |
| 49955 | */ |
| 49956 | #define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \ |
| 49957 | DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \ |
| 49958 | (long) (a), (long) (b), \ |
| 49959 | (double) (a), (double) (b))); \ |
| 49960 | } while (0) |
| 49961 | #define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \ |
| 49962 | DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \ |
| 49963 | (unsigned long) (a), (unsigned long) (b), \ |
| 49964 | (double) (a), (double) (b))); \ |
| 49965 | } while (0) |
| 49966 | #define DUK__DUMPLM_SIGNED(t) do { \ |
| 49967 | DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \ |
| 49968 | } while (0) |
| 49969 | #define DUK__DUMPLM_UNSIGNED(t) do { \ |
| 49970 | DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \ |
| 49971 | } while (0) |
| 49972 | |
| 49973 | DUK_LOCAL void duk__dump_type_sizes(void) { |
| 49974 | DUK_D(DUK_DPRINT("sizeof()" )); |
| 49975 | |
| 49976 | /* basic platform types */ |
| 49977 | DUK__DUMPSZ(char); |
| 49978 | DUK__DUMPSZ(short); |
| 49979 | DUK__DUMPSZ(int); |
| 49980 | DUK__DUMPSZ(long); |
| 49981 | DUK__DUMPSZ(double); |
| 49982 | DUK__DUMPSZ(void *); |
| 49983 | DUK__DUMPSZ(size_t); |
| 49984 | |
| 49985 | /* basic types from duk_features.h */ |
| 49986 | DUK__DUMPSZ(duk_uint8_t); |
| 49987 | DUK__DUMPSZ(duk_int8_t); |
| 49988 | DUK__DUMPSZ(duk_uint16_t); |
| 49989 | DUK__DUMPSZ(duk_int16_t); |
| 49990 | DUK__DUMPSZ(duk_uint32_t); |
| 49991 | DUK__DUMPSZ(duk_int32_t); |
| 49992 | DUK__DUMPSZ(duk_uint64_t); |
| 49993 | DUK__DUMPSZ(duk_int64_t); |
| 49994 | DUK__DUMPSZ(duk_uint_least8_t); |
| 49995 | DUK__DUMPSZ(duk_int_least8_t); |
| 49996 | DUK__DUMPSZ(duk_uint_least16_t); |
| 49997 | DUK__DUMPSZ(duk_int_least16_t); |
| 49998 | DUK__DUMPSZ(duk_uint_least32_t); |
| 49999 | DUK__DUMPSZ(duk_int_least32_t); |
| 50000 | #if defined(DUK_USE_64BIT_OPS) |
| 50001 | DUK__DUMPSZ(duk_uint_least64_t); |
| 50002 | DUK__DUMPSZ(duk_int_least64_t); |
| 50003 | #endif |
| 50004 | DUK__DUMPSZ(duk_uint_fast8_t); |
| 50005 | DUK__DUMPSZ(duk_int_fast8_t); |
| 50006 | DUK__DUMPSZ(duk_uint_fast16_t); |
| 50007 | DUK__DUMPSZ(duk_int_fast16_t); |
| 50008 | DUK__DUMPSZ(duk_uint_fast32_t); |
| 50009 | DUK__DUMPSZ(duk_int_fast32_t); |
| 50010 | #if defined(DUK_USE_64BIT_OPS) |
| 50011 | DUK__DUMPSZ(duk_uint_fast64_t); |
| 50012 | DUK__DUMPSZ(duk_int_fast64_t); |
| 50013 | #endif |
| 50014 | DUK__DUMPSZ(duk_uintptr_t); |
| 50015 | DUK__DUMPSZ(duk_intptr_t); |
| 50016 | DUK__DUMPSZ(duk_uintmax_t); |
| 50017 | DUK__DUMPSZ(duk_intmax_t); |
| 50018 | DUK__DUMPSZ(duk_double_t); |
| 50019 | |
| 50020 | /* important chosen base types */ |
| 50021 | DUK__DUMPSZ(duk_int_t); |
| 50022 | DUK__DUMPSZ(duk_uint_t); |
| 50023 | DUK__DUMPSZ(duk_int_fast_t); |
| 50024 | DUK__DUMPSZ(duk_uint_fast_t); |
| 50025 | DUK__DUMPSZ(duk_small_int_t); |
| 50026 | DUK__DUMPSZ(duk_small_uint_t); |
| 50027 | DUK__DUMPSZ(duk_small_int_fast_t); |
| 50028 | DUK__DUMPSZ(duk_small_uint_fast_t); |
| 50029 | |
| 50030 | /* some derived types */ |
| 50031 | DUK__DUMPSZ(duk_codepoint_t); |
| 50032 | DUK__DUMPSZ(duk_ucodepoint_t); |
| 50033 | DUK__DUMPSZ(duk_idx_t); |
| 50034 | DUK__DUMPSZ(duk_errcode_t); |
| 50035 | DUK__DUMPSZ(duk_uarridx_t); |
| 50036 | |
| 50037 | /* tval */ |
| 50038 | DUK__DUMPSZ(duk_double_union); |
| 50039 | DUK__DUMPSZ(duk_tval); |
| 50040 | |
| 50041 | /* structs from duk_forwdecl.h */ |
| 50042 | DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */ |
| 50043 | DUK__DUMPSZ(duk_heaphdr); |
| 50044 | DUK__DUMPSZ(duk_heaphdr_string); |
| 50045 | DUK__DUMPSZ(duk_hstring); |
| 50046 | DUK__DUMPSZ(duk_hstring_external); |
| 50047 | DUK__DUMPSZ(duk_hobject); |
| 50048 | DUK__DUMPSZ(duk_harray); |
| 50049 | DUK__DUMPSZ(duk_hcompfunc); |
| 50050 | DUK__DUMPSZ(duk_hnatfunc); |
| 50051 | DUK__DUMPSZ(duk_hdecenv); |
| 50052 | DUK__DUMPSZ(duk_hobjenv); |
| 50053 | DUK__DUMPSZ(duk_hthread); |
| 50054 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 50055 | DUK__DUMPSZ(duk_hbufobj); |
| 50056 | #endif |
| 50057 | DUK__DUMPSZ(duk_hproxy); |
| 50058 | DUK__DUMPSZ(duk_hbuffer); |
| 50059 | DUK__DUMPSZ(duk_hbuffer_fixed); |
| 50060 | DUK__DUMPSZ(duk_hbuffer_dynamic); |
| 50061 | DUK__DUMPSZ(duk_hbuffer_external); |
| 50062 | DUK__DUMPSZ(duk_propaccessor); |
| 50063 | DUK__DUMPSZ(duk_propvalue); |
| 50064 | DUK__DUMPSZ(duk_propdesc); |
| 50065 | DUK__DUMPSZ(duk_heap); |
| 50066 | DUK__DUMPSZ(duk_activation); |
| 50067 | DUK__DUMPSZ(duk_catcher); |
| 50068 | DUK__DUMPSZ(duk_strcache_entry); |
| 50069 | DUK__DUMPSZ(duk_litcache_entry); |
| 50070 | DUK__DUMPSZ(duk_ljstate); |
| 50071 | DUK__DUMPSZ(duk_fixedbuffer); |
| 50072 | DUK__DUMPSZ(duk_bitdecoder_ctx); |
| 50073 | DUK__DUMPSZ(duk_bitencoder_ctx); |
| 50074 | DUK__DUMPSZ(duk_token); |
| 50075 | DUK__DUMPSZ(duk_re_token); |
| 50076 | DUK__DUMPSZ(duk_lexer_point); |
| 50077 | DUK__DUMPSZ(duk_lexer_ctx); |
| 50078 | DUK__DUMPSZ(duk_compiler_instr); |
| 50079 | DUK__DUMPSZ(duk_compiler_func); |
| 50080 | DUK__DUMPSZ(duk_compiler_ctx); |
| 50081 | DUK__DUMPSZ(duk_re_matcher_ctx); |
| 50082 | DUK__DUMPSZ(duk_re_compiler_ctx); |
| 50083 | } |
| 50084 | DUK_LOCAL void duk__dump_type_limits(void) { |
| 50085 | DUK_D(DUK_DPRINT("limits" )); |
| 50086 | |
| 50087 | /* basic types */ |
| 50088 | DUK__DUMPLM_SIGNED(INT8); |
| 50089 | DUK__DUMPLM_UNSIGNED(UINT8); |
| 50090 | DUK__DUMPLM_SIGNED(INT_FAST8); |
| 50091 | DUK__DUMPLM_UNSIGNED(UINT_FAST8); |
| 50092 | DUK__DUMPLM_SIGNED(INT_LEAST8); |
| 50093 | DUK__DUMPLM_UNSIGNED(UINT_LEAST8); |
| 50094 | DUK__DUMPLM_SIGNED(INT16); |
| 50095 | DUK__DUMPLM_UNSIGNED(UINT16); |
| 50096 | DUK__DUMPLM_SIGNED(INT_FAST16); |
| 50097 | DUK__DUMPLM_UNSIGNED(UINT_FAST16); |
| 50098 | DUK__DUMPLM_SIGNED(INT_LEAST16); |
| 50099 | DUK__DUMPLM_UNSIGNED(UINT_LEAST16); |
| 50100 | DUK__DUMPLM_SIGNED(INT32); |
| 50101 | DUK__DUMPLM_UNSIGNED(UINT32); |
| 50102 | DUK__DUMPLM_SIGNED(INT_FAST32); |
| 50103 | DUK__DUMPLM_UNSIGNED(UINT_FAST32); |
| 50104 | DUK__DUMPLM_SIGNED(INT_LEAST32); |
| 50105 | DUK__DUMPLM_UNSIGNED(UINT_LEAST32); |
| 50106 | #if defined(DUK_USE_64BIT_OPS) |
| 50107 | DUK__DUMPLM_SIGNED(INT64); |
| 50108 | DUK__DUMPLM_UNSIGNED(UINT64); |
| 50109 | DUK__DUMPLM_SIGNED(INT_FAST64); |
| 50110 | DUK__DUMPLM_UNSIGNED(UINT_FAST64); |
| 50111 | DUK__DUMPLM_SIGNED(INT_LEAST64); |
| 50112 | DUK__DUMPLM_UNSIGNED(UINT_LEAST64); |
| 50113 | #endif |
| 50114 | DUK__DUMPLM_SIGNED(INTPTR); |
| 50115 | DUK__DUMPLM_UNSIGNED(UINTPTR); |
| 50116 | DUK__DUMPLM_SIGNED(INTMAX); |
| 50117 | DUK__DUMPLM_UNSIGNED(UINTMAX); |
| 50118 | |
| 50119 | /* derived types */ |
| 50120 | DUK__DUMPLM_SIGNED(INT); |
| 50121 | DUK__DUMPLM_UNSIGNED(UINT); |
| 50122 | DUK__DUMPLM_SIGNED(INT_FAST); |
| 50123 | DUK__DUMPLM_UNSIGNED(UINT_FAST); |
| 50124 | DUK__DUMPLM_SIGNED(SMALL_INT); |
| 50125 | DUK__DUMPLM_UNSIGNED(SMALL_UINT); |
| 50126 | DUK__DUMPLM_SIGNED(SMALL_INT_FAST); |
| 50127 | DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST); |
| 50128 | } |
| 50129 | |
| 50130 | DUK_LOCAL void duk__dump_misc_options(void) { |
| 50131 | DUK_D(DUK_DPRINT("DUK_VERSION: %ld" , (long) DUK_VERSION)); |
| 50132 | DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s" , DUK_GIT_DESCRIBE)); |
| 50133 | DUK_D(DUK_DPRINT("OS string: %s" , DUK_USE_OS_STRING)); |
| 50134 | DUK_D(DUK_DPRINT("architecture string: %s" , DUK_USE_ARCH_STRING)); |
| 50135 | DUK_D(DUK_DPRINT("compiler string: %s" , DUK_USE_COMPILER_STRING)); |
| 50136 | DUK_D(DUK_DPRINT("debug level: %ld" , (long) DUK_USE_DEBUG_LEVEL)); |
| 50137 | #if defined(DUK_USE_PACKED_TVAL) |
| 50138 | DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes" )); |
| 50139 | #else |
| 50140 | DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no" )); |
| 50141 | #endif |
| 50142 | #if defined(DUK_USE_VARIADIC_MACROS) |
| 50143 | DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes" )); |
| 50144 | #else |
| 50145 | DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no" )); |
| 50146 | #endif |
| 50147 | #if defined(DUK_USE_INTEGER_LE) |
| 50148 | DUK_D(DUK_DPRINT("integer endianness: little" )); |
| 50149 | #elif defined(DUK_USE_INTEGER_ME) |
| 50150 | DUK_D(DUK_DPRINT("integer endianness: mixed" )); |
| 50151 | #elif defined(DUK_USE_INTEGER_BE) |
| 50152 | DUK_D(DUK_DPRINT("integer endianness: big" )); |
| 50153 | #else |
| 50154 | DUK_D(DUK_DPRINT("integer endianness: ???" )); |
| 50155 | #endif |
| 50156 | #if defined(DUK_USE_DOUBLE_LE) |
| 50157 | DUK_D(DUK_DPRINT("IEEE double endianness: little" )); |
| 50158 | #elif defined(DUK_USE_DOUBLE_ME) |
| 50159 | DUK_D(DUK_DPRINT("IEEE double endianness: mixed" )); |
| 50160 | #elif defined(DUK_USE_DOUBLE_BE) |
| 50161 | DUK_D(DUK_DPRINT("IEEE double endianness: big" )); |
| 50162 | #else |
| 50163 | DUK_D(DUK_DPRINT("IEEE double endianness: ???" )); |
| 50164 | #endif |
| 50165 | } |
| 50166 | #endif /* DUK_USE_DEBUG */ |
| 50167 | |
| 50168 | DUK_INTERNAL |
| 50169 | duk_heap *duk_heap_alloc(duk_alloc_function alloc_func, |
| 50170 | duk_realloc_function realloc_func, |
| 50171 | duk_free_function free_func, |
| 50172 | void *heap_udata, |
| 50173 | duk_fatal_function fatal_func) { |
| 50174 | duk_heap *res = NULL; |
| 50175 | duk_uint32_t st_initsize; |
| 50176 | |
| 50177 | DUK_D(DUK_DPRINT("allocate heap" )); |
| 50178 | |
| 50179 | /* |
| 50180 | * Random config sanity asserts |
| 50181 | */ |
| 50182 | |
| 50183 | DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64); |
| 50184 | |
| 50185 | DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0); |
| 50186 | DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0); |
| 50187 | DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1); /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */ |
| 50188 | |
| 50189 | /* |
| 50190 | * Debug dump type sizes |
| 50191 | */ |
| 50192 | |
| 50193 | #if defined(DUK_USE_DEBUG) |
| 50194 | duk__dump_misc_options(); |
| 50195 | duk__dump_type_sizes(); |
| 50196 | duk__dump_type_limits(); |
| 50197 | #endif |
| 50198 | |
| 50199 | /* |
| 50200 | * If selftests enabled, run them as early as possible. |
| 50201 | */ |
| 50202 | |
| 50203 | #if defined(DUK_USE_SELF_TESTS) |
| 50204 | DUK_D(DUK_DPRINT("run self tests" )); |
| 50205 | if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) { |
| 50206 | fatal_func(heap_udata, "self test(s) failed" ); |
| 50207 | } |
| 50208 | DUK_D(DUK_DPRINT("self tests passed" )); |
| 50209 | #endif |
| 50210 | |
| 50211 | /* |
| 50212 | * Important assert-like checks that should be enabled even |
| 50213 | * when assertions are otherwise not enabled. |
| 50214 | */ |
| 50215 | |
| 50216 | #if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE) |
| 50217 | /* Can't check sizeof() using preprocessor so explicit check. |
| 50218 | * This will be optimized away in practice; unfortunately a |
| 50219 | * warning is generated on some compilers as a result. |
| 50220 | */ |
| 50221 | #if defined(DUK_USE_PACKED_TVAL) |
| 50222 | if (sizeof(duk_tval) != 8) { |
| 50223 | #else |
| 50224 | if (sizeof(duk_tval) != 16) { |
| 50225 | #endif |
| 50226 | fatal_func(heap_udata, "sizeof(duk_tval) not 8 or 16, cannot use DUK_USE_EXEC_REGCONST_OPTIMIZE option" ); |
| 50227 | } |
| 50228 | #endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */ |
| 50229 | |
| 50230 | /* |
| 50231 | * Computed values (e.g. INFINITY) |
| 50232 | */ |
| 50233 | |
| 50234 | #if defined(DUK_USE_COMPUTED_NAN) |
| 50235 | do { |
| 50236 | /* Workaround for some exotic platforms where NAN is missing |
| 50237 | * and the expression (0.0 / 0.0) does NOT result in a NaN. |
| 50238 | * Such platforms use the global 'duk_computed_nan' which must |
| 50239 | * be initialized at runtime. Use 'volatile' to ensure that |
| 50240 | * the compiler will actually do the computation and not try |
| 50241 | * to do constant folding which might result in the original |
| 50242 | * problem. |
| 50243 | */ |
| 50244 | volatile double dbl1 = 0.0; |
| 50245 | volatile double dbl2 = 0.0; |
| 50246 | duk_computed_nan = dbl1 / dbl2; |
| 50247 | } while (0); |
| 50248 | #endif |
| 50249 | |
| 50250 | #if defined(DUK_USE_COMPUTED_INFINITY) |
| 50251 | do { |
| 50252 | /* Similar workaround for INFINITY. */ |
| 50253 | volatile double dbl1 = 1.0; |
| 50254 | volatile double dbl2 = 0.0; |
| 50255 | duk_computed_infinity = dbl1 / dbl2; |
| 50256 | } while (0); |
| 50257 | #endif |
| 50258 | |
| 50259 | /* |
| 50260 | * Allocate heap struct |
| 50261 | * |
| 50262 | * Use a raw call, all macros expect the heap to be initialized |
| 50263 | */ |
| 50264 | |
| 50265 | #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1) |
| 50266 | goto failed; |
| 50267 | #endif |
| 50268 | DUK_D(DUK_DPRINT("alloc duk_heap object" )); |
| 50269 | res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap)); |
| 50270 | if (!res) { |
| 50271 | goto failed; |
| 50272 | } |
| 50273 | |
| 50274 | /* |
| 50275 | * Zero the struct, and start initializing roughly in order |
| 50276 | */ |
| 50277 | |
| 50278 | duk_memzero(res, sizeof(*res)); |
| 50279 | #if defined(DUK_USE_ASSERTIONS) |
| 50280 | res->heap_initializing = 1; |
| 50281 | #endif |
| 50282 | |
| 50283 | /* explicit NULL inits */ |
| 50284 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 50285 | res->heap_udata = NULL; |
| 50286 | res->heap_allocated = NULL; |
| 50287 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50288 | res->refzero_list = NULL; |
| 50289 | #endif |
| 50290 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 50291 | res->finalize_list = NULL; |
| 50292 | #if defined(DUK_USE_ASSERTIONS) |
| 50293 | res->currently_finalizing = NULL; |
| 50294 | #endif |
| 50295 | #endif |
| 50296 | #if defined(DUK_USE_CACHE_ACTIVATION) |
| 50297 | res->activation_free = NULL; |
| 50298 | #endif |
| 50299 | #if defined(DUK_USE_CACHE_CATCHER) |
| 50300 | res->catcher_free = NULL; |
| 50301 | #endif |
| 50302 | res->heap_thread = NULL; |
| 50303 | res->curr_thread = NULL; |
| 50304 | res->heap_object = NULL; |
| 50305 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 50306 | res->strtable16 = NULL; |
| 50307 | #else |
| 50308 | res->strtable = NULL; |
| 50309 | #endif |
| 50310 | #if defined(DUK_USE_ROM_STRINGS) |
| 50311 | /* no res->strs[] */ |
| 50312 | #else /* DUK_USE_ROM_STRINGS */ |
| 50313 | #if defined(DUK_USE_HEAPPTR16) |
| 50314 | /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */ |
| 50315 | #else |
| 50316 | { |
| 50317 | duk_small_uint_t i; |
| 50318 | for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { |
| 50319 | res->strs[i] = NULL; |
| 50320 | } |
| 50321 | } |
| 50322 | #endif |
| 50323 | #endif /* DUK_USE_ROM_STRINGS */ |
| 50324 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 50325 | res->dbg_read_cb = NULL; |
| 50326 | res->dbg_write_cb = NULL; |
| 50327 | res->dbg_peek_cb = NULL; |
| 50328 | res->dbg_read_flush_cb = NULL; |
| 50329 | res->dbg_write_flush_cb = NULL; |
| 50330 | res->dbg_request_cb = NULL; |
| 50331 | res->dbg_udata = NULL; |
| 50332 | res->dbg_pause_act = NULL; |
| 50333 | #endif |
| 50334 | #endif /* DUK_USE_EXPLICIT_NULL_INIT */ |
| 50335 | |
| 50336 | res->alloc_func = alloc_func; |
| 50337 | res->realloc_func = realloc_func; |
| 50338 | res->free_func = free_func; |
| 50339 | res->heap_udata = heap_udata; |
| 50340 | res->fatal_func = fatal_func; |
| 50341 | |
| 50342 | /* XXX: for now there's a pointer packing zero assumption, i.e. |
| 50343 | * NULL <=> compressed pointer 0. If this is removed, may need |
| 50344 | * to precompute e.g. null16 here. |
| 50345 | */ |
| 50346 | |
| 50347 | /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */ |
| 50348 | |
| 50349 | /* Prevent mark-and-sweep and finalizer execution until heap is completely |
| 50350 | * initialized. |
| 50351 | */ |
| 50352 | DUK_ASSERT(res->ms_prevent_count == 0); |
| 50353 | DUK_ASSERT(res->pf_prevent_count == 0); |
| 50354 | res->ms_prevent_count = 1; |
| 50355 | res->pf_prevent_count = 1; |
| 50356 | DUK_ASSERT(res->ms_running == 0); |
| 50357 | |
| 50358 | res->call_recursion_depth = 0; |
| 50359 | res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT; |
| 50360 | |
| 50361 | /* XXX: use the pointer as a seed for now: mix in time at least */ |
| 50362 | |
| 50363 | /* The casts through duk_uintptr_t is to avoid the following GCC warning: |
| 50364 | * |
| 50365 | * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] |
| 50366 | * |
| 50367 | * This still generates a /Wp64 warning on VS2010 when compiling for x86. |
| 50368 | */ |
| 50369 | #if defined(DUK_USE_ROM_STRINGS) |
| 50370 | /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */ |
| 50371 | DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx" , (long) DUK__FIXED_HASH_SEED)); |
| 50372 | res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED; |
| 50373 | #else /* DUK_USE_ROM_STRINGS */ |
| 50374 | res->hash_seed = (duk_uint32_t) (duk_uintptr_t) res; |
| 50375 | #if !defined(DUK_USE_STRHASH_DENSE) |
| 50376 | res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */ |
| 50377 | #endif |
| 50378 | #endif /* DUK_USE_ROM_STRINGS */ |
| 50379 | |
| 50380 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 50381 | res->lj.jmpbuf_ptr = NULL; |
| 50382 | #endif |
| 50383 | DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */ |
| 50384 | DUK_ASSERT(res->lj.iserror == 0); |
| 50385 | DUK_TVAL_SET_UNDEFINED(&res->lj.value1); |
| 50386 | DUK_TVAL_SET_UNDEFINED(&res->lj.value2); |
| 50387 | |
| 50388 | DUK_ASSERT_LJSTATE_UNSET(res); |
| 50389 | |
| 50390 | /* |
| 50391 | * Init stringtable: fixed variant |
| 50392 | */ |
| 50393 | |
| 50394 | st_initsize = DUK_USE_STRTAB_MINSIZE; |
| 50395 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 50396 | res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize); |
| 50397 | if (res->strtable16 == NULL) { |
| 50398 | goto failed; |
| 50399 | } |
| 50400 | #else |
| 50401 | res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize); |
| 50402 | if (res->strtable == NULL) { |
| 50403 | goto failed; |
| 50404 | } |
| 50405 | #endif |
| 50406 | res->st_size = st_initsize; |
| 50407 | res->st_mask = st_initsize - 1; |
| 50408 | #if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE) |
| 50409 | DUK_ASSERT(res->st_count == 0); |
| 50410 | #endif |
| 50411 | |
| 50412 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 50413 | /* zero assumption */ |
| 50414 | duk_memzero(res->strtable16, sizeof(duk_uint16_t) * st_initsize); |
| 50415 | #else |
| 50416 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 50417 | { |
| 50418 | duk_uint32_t i; |
| 50419 | for (i = 0; i < st_initsize; i++) { |
| 50420 | res->strtable[i] = NULL; |
| 50421 | } |
| 50422 | } |
| 50423 | #else |
| 50424 | duk_memzero(res->strtable, sizeof(duk_hstring *) * st_initsize); |
| 50425 | #endif /* DUK_USE_EXPLICIT_NULL_INIT */ |
| 50426 | #endif /* DUK_USE_STRTAB_PTRCOMP */ |
| 50427 | |
| 50428 | /* |
| 50429 | * Init stringcache |
| 50430 | */ |
| 50431 | |
| 50432 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 50433 | { |
| 50434 | duk_uint_t i; |
| 50435 | for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { |
| 50436 | res->strcache[i].h = NULL; |
| 50437 | } |
| 50438 | } |
| 50439 | #endif |
| 50440 | |
| 50441 | /* |
| 50442 | * Init litcache |
| 50443 | */ |
| 50444 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 50445 | DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0); |
| 50446 | DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE)); |
| 50447 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 50448 | { |
| 50449 | duk_uint_t i; |
| 50450 | for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) { |
| 50451 | res->litcache[i].addr = NULL; |
| 50452 | res->litcache[i].h = NULL; |
| 50453 | } |
| 50454 | } |
| 50455 | #endif |
| 50456 | #endif /* DUK_USE_LITCACHE_SIZE */ |
| 50457 | |
| 50458 | /* XXX: error handling is incomplete. It would be cleanest if |
| 50459 | * there was a setjmp catchpoint, so that all init code could |
| 50460 | * freely throw errors. If that were the case, the return code |
| 50461 | * passing here could be removed. |
| 50462 | */ |
| 50463 | |
| 50464 | /* |
| 50465 | * Init built-in strings |
| 50466 | */ |
| 50467 | |
| 50468 | #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2) |
| 50469 | goto failed; |
| 50470 | #endif |
| 50471 | DUK_D(DUK_DPRINT("heap init: initialize heap strings" )); |
| 50472 | if (!duk__init_heap_strings(res)) { |
| 50473 | goto failed; |
| 50474 | } |
| 50475 | |
| 50476 | /* |
| 50477 | * Init the heap thread |
| 50478 | */ |
| 50479 | |
| 50480 | #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3) |
| 50481 | goto failed; |
| 50482 | #endif |
| 50483 | DUK_D(DUK_DPRINT("heap init: initialize heap thread" )); |
| 50484 | if (!duk__init_heap_thread(res)) { |
| 50485 | goto failed; |
| 50486 | } |
| 50487 | |
| 50488 | /* |
| 50489 | * Init the heap object |
| 50490 | */ |
| 50491 | |
| 50492 | #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4) |
| 50493 | goto failed; |
| 50494 | #endif |
| 50495 | DUK_D(DUK_DPRINT("heap init: initialize heap object" )); |
| 50496 | DUK_ASSERT(res->heap_thread != NULL); |
| 50497 | res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 50498 | DUK_HOBJECT_FLAG_FASTREFS | |
| 50499 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT)); |
| 50500 | if (res->heap_object == NULL) { |
| 50501 | goto failed; |
| 50502 | } |
| 50503 | DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object); |
| 50504 | |
| 50505 | /* |
| 50506 | * Odds and ends depending on the heap thread |
| 50507 | */ |
| 50508 | |
| 50509 | #if !defined(DUK_USE_GET_RANDOM_DOUBLE) |
| 50510 | #if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) |
| 50511 | res->rnd_state = (duk_uint32_t) duk_time_get_ecmascript_time(res->heap_thread); |
| 50512 | duk_util_tinyrandom_prepare_seed(res->heap_thread); |
| 50513 | #else |
| 50514 | res->rnd_state[0] = (duk_uint64_t) duk_time_get_ecmascript_time(res->heap_thread); |
| 50515 | DUK_ASSERT(res->rnd_state[1] == 0); /* Not filled here, filled in by seed preparation. */ |
| 50516 | #if 0 /* Manual test values matching misc/xoroshiro128plus_test.c. */ |
| 50517 | res->rnd_state[0] = DUK_U64_CONSTANT(0xdeadbeef12345678); |
| 50518 | res->rnd_state[1] = DUK_U64_CONSTANT(0xcafed00d12345678); |
| 50519 | #endif |
| 50520 | duk_util_tinyrandom_prepare_seed(res->heap_thread); |
| 50521 | /* Mix in heap pointer: this ensures that if two Duktape heaps are |
| 50522 | * created on the same millisecond, they get a different PRNG |
| 50523 | * sequence (unless e.g. virtual memory addresses cause also the |
| 50524 | * heap object pointer to be the same). |
| 50525 | */ |
| 50526 | { |
| 50527 | duk_uint64_t tmp_u64; |
| 50528 | tmp_u64 = 0; |
| 50529 | duk_memcpy((void *) &tmp_u64, |
| 50530 | (const void *) &res, |
| 50531 | (size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *))); |
| 50532 | res->rnd_state[1] ^= tmp_u64; |
| 50533 | } |
| 50534 | do { |
| 50535 | duk_small_uint_t i; |
| 50536 | for (i = 0; i < 10; i++) { |
| 50537 | /* Throw away a few initial random numbers just in |
| 50538 | * case. Probably unnecessary due to SplitMix64 |
| 50539 | * preparation. |
| 50540 | */ |
| 50541 | (void) duk_util_tinyrandom_get_double(res->heap_thread); |
| 50542 | } |
| 50543 | } while (0); |
| 50544 | #endif |
| 50545 | #endif |
| 50546 | |
| 50547 | /* |
| 50548 | * Allow finalizer and mark-and-sweep processing. |
| 50549 | */ |
| 50550 | |
| 50551 | DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing" )); |
| 50552 | DUK_ASSERT(res->ms_prevent_count == 1); |
| 50553 | DUK_ASSERT(res->pf_prevent_count == 1); |
| 50554 | res->ms_prevent_count = 0; |
| 50555 | res->pf_prevent_count = 0; |
| 50556 | DUK_ASSERT(res->ms_running == 0); |
| 50557 | #if defined(DUK_USE_ASSERTIONS) |
| 50558 | res->heap_initializing = 0; |
| 50559 | #endif |
| 50560 | |
| 50561 | /* |
| 50562 | * All done. |
| 50563 | */ |
| 50564 | |
| 50565 | DUK_D(DUK_DPRINT("allocated heap: %p" , (void *) res)); |
| 50566 | return res; |
| 50567 | |
| 50568 | failed: |
| 50569 | DUK_D(DUK_DPRINT("heap allocation failed" )); |
| 50570 | |
| 50571 | if (res != NULL) { |
| 50572 | /* Assumes that allocated pointers and alloc funcs are valid |
| 50573 | * if res exists. |
| 50574 | */ |
| 50575 | DUK_ASSERT(res->ms_prevent_count == 1); |
| 50576 | DUK_ASSERT(res->pf_prevent_count == 1); |
| 50577 | DUK_ASSERT(res->ms_running == 0); |
| 50578 | if (res->heap_thread != NULL) { |
| 50579 | res->ms_prevent_count = 0; |
| 50580 | res->pf_prevent_count = 0; |
| 50581 | } |
| 50582 | #if defined(DUK_USE_ASSERTIONS) |
| 50583 | res->heap_initializing = 0; |
| 50584 | #endif |
| 50585 | |
| 50586 | DUK_ASSERT(res->alloc_func != NULL); |
| 50587 | DUK_ASSERT(res->realloc_func != NULL); |
| 50588 | DUK_ASSERT(res->free_func != NULL); |
| 50589 | duk_heap_free(res); |
| 50590 | } |
| 50591 | |
| 50592 | return NULL; |
| 50593 | } |
| 50594 | |
| 50595 | /* automatic undefs */ |
| 50596 | #undef DUK__DUMPLM_SIGNED |
| 50597 | #undef DUK__DUMPLM_SIGNED_RAW |
| 50598 | #undef DUK__DUMPLM_UNSIGNED |
| 50599 | #undef DUK__DUMPLM_UNSIGNED_RAW |
| 50600 | #undef DUK__DUMPSZ |
| 50601 | #undef DUK__FIXED_HASH_SEED |
| 50602 | #line 1 "duk_heap_finalize.c" |
| 50603 | /* |
| 50604 | * Finalizer handling. |
| 50605 | */ |
| 50606 | |
| 50607 | /* #include duk_internal.h -> already included */ |
| 50608 | |
| 50609 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 50610 | |
| 50611 | /* |
| 50612 | * Fake torture finalizer. |
| 50613 | */ |
| 50614 | |
| 50615 | #if defined(DUK_USE_FINALIZER_TORTURE) |
| 50616 | DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_hthread *thr) { |
| 50617 | DUK_DD(DUK_DDPRINT("fake global torture finalizer executed" )); |
| 50618 | |
| 50619 | /* Require a lot of stack to force a value stack grow/shrink. */ |
| 50620 | duk_require_stack(thr, 100000); |
| 50621 | |
| 50622 | /* Force a reallocation with pointer change for value stack |
| 50623 | * to maximize side effects. |
| 50624 | */ |
| 50625 | duk_hthread_valstack_torture_realloc(thr); |
| 50626 | |
| 50627 | /* Inner function call, error throw. */ |
| 50628 | duk_eval_string_noresult(thr, |
| 50629 | "(function dummy() {\n" |
| 50630 | " dummy.prototype = null; /* break reference loop */\n" |
| 50631 | " try {\n" |
| 50632 | " throw 'fake-finalizer-dummy-error';\n" |
| 50633 | " } catch (e) {\n" |
| 50634 | " void e;\n" |
| 50635 | " }\n" |
| 50636 | "})()" ); |
| 50637 | |
| 50638 | /* The above creates garbage (e.g. a function instance). Because |
| 50639 | * the function/prototype reference loop is broken, it gets collected |
| 50640 | * immediately by DECREF. If Function.prototype has a _Finalizer |
| 50641 | * property (happens in some test cases), the garbage gets queued to |
| 50642 | * finalize_list. This still won't cause an infinite loop because |
| 50643 | * the torture finalizer is called once per finalize_list run and |
| 50644 | * the garbage gets handled in the same run. (If the garbage needs |
| 50645 | * mark-and-sweep collection, an infinite loop might ensue.) |
| 50646 | */ |
| 50647 | return 0; |
| 50648 | } |
| 50649 | |
| 50650 | DUK_LOCAL void duk__run_global_torture_finalizer(duk_hthread *thr) { |
| 50651 | DUK_ASSERT(thr != NULL); |
| 50652 | |
| 50653 | /* Avoid fake finalization when callstack limit is near. Otherwise |
| 50654 | * a callstack limit error will be created, then refzero'ed. The |
| 50655 | * +5 headroom is conservative. |
| 50656 | */ |
| 50657 | if (thr->heap->call_recursion_depth + 5 >= thr->heap->call_recursion_limit || |
| 50658 | thr->callstack_top + 5 >= DUK_USE_CALLSTACK_LIMIT) { |
| 50659 | DUK_D(DUK_DPRINT("skip global torture finalizer, too little headroom for call recursion or call stack size" )); |
| 50660 | return; |
| 50661 | } |
| 50662 | |
| 50663 | /* Run fake finalizer. Avoid creating unnecessary garbage. */ |
| 50664 | duk_push_c_function(thr, duk__fake_global_finalizer, 0 /*nargs*/); |
| 50665 | (void) duk_pcall(thr, 0 /*nargs*/); |
| 50666 | duk_pop(thr); |
| 50667 | } |
| 50668 | #endif /* DUK_USE_FINALIZER_TORTURE */ |
| 50669 | |
| 50670 | /* |
| 50671 | * Process the finalize_list to completion. |
| 50672 | * |
| 50673 | * An object may be placed on finalize_list by either refcounting or |
| 50674 | * mark-and-sweep. The refcount of objects placed by refcounting will be |
| 50675 | * zero; the refcount of objects placed by mark-and-sweep is > 0. In both |
| 50676 | * cases the refcount is bumped by 1 artificially so that a REFZERO event |
| 50677 | * can never happen while an object is waiting for finalization. Without |
| 50678 | * this bump a REFZERO could now happen because user code may call |
| 50679 | * duk_push_heapptr() and then pop a value even when it's on finalize_list. |
| 50680 | * |
| 50681 | * List processing assumes refcounts are kept up-to-date at all times, so |
| 50682 | * that once the finalizer returns, a zero refcount is a reliable reason to |
| 50683 | * free the object immediately rather than place it back to the heap. This |
| 50684 | * is the case because we run outside of refzero_list processing so that |
| 50685 | * DECREF cascades are handled fully inline. |
| 50686 | * |
| 50687 | * For mark-and-sweep queued objects (had_zero_refcount false) the object |
| 50688 | * may be freed immediately if its refcount is zero after the finalizer call |
| 50689 | * (i.e. finalizer removed the reference loop for the object). If not, the |
| 50690 | * next mark-and-sweep will collect the object unless it has become reachable |
| 50691 | * (i.e. rescued) by that time and its refcount hasn't fallen to zero before |
| 50692 | * that. Mark-and-sweep detects these objects because their FINALIZED flag |
| 50693 | * is set. |
| 50694 | * |
| 50695 | * There's an inherent limitation for mark-and-sweep finalizer rescuing: an |
| 50696 | * object won't get refinalized if (1) it's rescued, but (2) becomes |
| 50697 | * unreachable before mark-and-sweep has had time to notice it. The next |
| 50698 | * mark-and-sweep round simply doesn't have any information of whether the |
| 50699 | * object has been unreachable the whole time or not (the only way to get |
| 50700 | * that information would be a mark-and-sweep pass for *every finalized |
| 50701 | * object*). This is awkward for the application because the mark-and-sweep |
| 50702 | * round is not generally visible or under full application control. |
| 50703 | * |
| 50704 | * For refcount queued objects (had_zero_refcount true) the object is either |
| 50705 | * immediately freed or rescued, and waiting for a mark-and-sweep round is not |
| 50706 | * necessary (or desirable); FINALIZED is cleared when a rescued object is |
| 50707 | * queued back to heap_allocated. The object is eligible for finalization |
| 50708 | * again (either via refcounting or mark-and-sweep) immediately after being |
| 50709 | * rescued. If a refcount finalized object is placed into an unreachable |
| 50710 | * reference loop by its finalizer, it will get collected by mark-and-sweep |
| 50711 | * and currently the finalizer will execute again. |
| 50712 | * |
| 50713 | * There's a special case where: |
| 50714 | * |
| 50715 | * - Mark-and-sweep queues an object to finalize_list for finalization. |
| 50716 | * - The finalizer is executed, FINALIZED is set, and object is queued |
| 50717 | * back to heap_allocated, waiting for a new mark-and-sweep round. |
| 50718 | * - The object's refcount drops to zero before mark-and-sweep has a |
| 50719 | * chance to run another round and make a rescue/free decision. |
| 50720 | * |
| 50721 | * This is now handled by refzero code: if an object has a finalizer but |
| 50722 | * FINALIZED is already set, the object is freed without finalizer processing. |
| 50723 | * The outcome is the same as if mark-and-sweep was executed at that point; |
| 50724 | * mark-and-sweep would also free the object without another finalizer run. |
| 50725 | * This could also be changed so that the refzero-triggered finalizer *IS* |
| 50726 | * executed: being refzero collected implies someone has operated on the |
| 50727 | * object so it hasn't been totally unreachable the whole time. This would |
| 50728 | * risk a finalizer loop however. |
| 50729 | */ |
| 50730 | |
| 50731 | DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) { |
| 50732 | duk_heaphdr *curr; |
| 50733 | #if defined(DUK_USE_DEBUG) |
| 50734 | duk_size_t count = 0; |
| 50735 | #endif |
| 50736 | |
| 50737 | DUK_DDD(DUK_DDDPRINT("duk_heap_process_finalize_list: %p" , (void *) heap)); |
| 50738 | |
| 50739 | if (heap->pf_prevent_count != 0) { |
| 50740 | DUK_DDD(DUK_DDDPRINT("skip finalize_list processing: pf_prevent_count != 0" )); |
| 50741 | return; |
| 50742 | } |
| 50743 | |
| 50744 | /* Heap alloc prevents mark-and-sweep before heap_thread is ready. */ |
| 50745 | DUK_ASSERT(heap != NULL); |
| 50746 | DUK_ASSERT(heap->heap_thread != NULL); |
| 50747 | DUK_ASSERT(heap->heap_thread->valstack != NULL); |
| 50748 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50749 | DUK_ASSERT(heap->refzero_list == NULL); |
| 50750 | #endif |
| 50751 | |
| 50752 | DUK_ASSERT(heap->pf_prevent_count == 0); |
| 50753 | heap->pf_prevent_count = 1; |
| 50754 | |
| 50755 | /* Mark-and-sweep no longer needs to be prevented when running |
| 50756 | * finalizers: mark-and-sweep skips any rescue decisions if there |
| 50757 | * are any objects in finalize_list when mark-and-sweep is entered. |
| 50758 | * This protects finalized objects from incorrect rescue decisions |
| 50759 | * caused by finalize_list being a reachability root and only |
| 50760 | * partially processed. Freeing decisions are not postponed. |
| 50761 | */ |
| 50762 | |
| 50763 | /* When finalizer torture is enabled, make a fake finalizer call with |
| 50764 | * maximum side effects regardless of whether finalize_list is empty. |
| 50765 | */ |
| 50766 | #if defined(DUK_USE_FINALIZER_TORTURE) |
| 50767 | duk__run_global_torture_finalizer(heap->heap_thread); |
| 50768 | #endif |
| 50769 | |
| 50770 | /* Process finalize_list until it becomes empty. There's currently no |
| 50771 | * protection against a finalizer always creating more garbage. |
| 50772 | */ |
| 50773 | while ((curr = heap->finalize_list) != NULL) { |
| 50774 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50775 | duk_bool_t queue_back; |
| 50776 | #endif |
| 50777 | |
| 50778 | DUK_DD(DUK_DDPRINT("processing finalize_list entry: %p -> %!iO" , (void *) curr, curr)); |
| 50779 | |
| 50780 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* Only objects have finalizers. */ |
| 50781 | DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); |
| 50782 | DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr)); |
| 50783 | DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); /* All objects on finalize_list will have this flag (except object being finalized right now). */ |
| 50784 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); /* Queueing code ensures. */ |
| 50785 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* ROM objects never get freed (or finalized). */ |
| 50786 | |
| 50787 | #if defined(DUK_USE_ASSERTIONS) |
| 50788 | DUK_ASSERT(heap->currently_finalizing == NULL); |
| 50789 | heap->currently_finalizing = curr; |
| 50790 | #endif |
| 50791 | |
| 50792 | /* Clear FINALIZABLE for object being finalized, so that |
| 50793 | * duk_push_heapptr() can properly ignore the object. |
| 50794 | */ |
| 50795 | DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); |
| 50796 | |
| 50797 | if (DUK_LIKELY(!heap->pf_skip_finalizers)) { |
| 50798 | /* Run the finalizer, duk_heap_run_finalizer() sets |
| 50799 | * and checks for FINALIZED to prevent the finalizer |
| 50800 | * from executing multiple times per finalization cycle. |
| 50801 | * (This safeguard shouldn't be actually needed anymore). |
| 50802 | */ |
| 50803 | |
| 50804 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50805 | duk_bool_t had_zero_refcount; |
| 50806 | #endif |
| 50807 | |
| 50808 | /* The object's refcount is >0 throughout so it won't be |
| 50809 | * refzero processed prematurely. |
| 50810 | */ |
| 50811 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50812 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); |
| 50813 | had_zero_refcount = (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1); /* Preincremented on finalize_list insert. */ |
| 50814 | #endif |
| 50815 | |
| 50816 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); |
| 50817 | duk_heap_run_finalizer(heap, (duk_hobject *) curr); /* must never longjmp */ |
| 50818 | DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr)); |
| 50819 | /* XXX: assert that object is still in finalize_list |
| 50820 | * when duk_push_heapptr() allows automatic rescue. |
| 50821 | */ |
| 50822 | |
| 50823 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50824 | DUK_DD(DUK_DDPRINT("refcount after finalizer (includes bump): %ld" , (long) DUK_HEAPHDR_GET_REFCOUNT(curr))); |
| 50825 | if (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1) { /* Only artificial bump in refcount? */ |
| 50826 | #if defined(DUK_USE_DEBUG) |
| 50827 | if (had_zero_refcount) { |
| 50828 | DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (refcount queued)" )); |
| 50829 | } else { |
| 50830 | DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (mark-and-sweep queued)" )); |
| 50831 | } |
| 50832 | #endif |
| 50833 | queue_back = 0; |
| 50834 | } else |
| 50835 | #endif |
| 50836 | { |
| 50837 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50838 | queue_back = 1; |
| 50839 | if (had_zero_refcount) { |
| 50840 | /* When finalization is triggered |
| 50841 | * by refzero and we queue the object |
| 50842 | * back, clear FINALIZED right away |
| 50843 | * so that the object can be refinalized |
| 50844 | * immediately if necessary. |
| 50845 | */ |
| 50846 | DUK_HEAPHDR_CLEAR_FINALIZED(curr); |
| 50847 | } |
| 50848 | #endif |
| 50849 | } |
| 50850 | } else { |
| 50851 | /* Used during heap destruction: don't actually run finalizers |
| 50852 | * because we're heading into forced finalization. Instead, |
| 50853 | * queue finalizable objects back to the heap_allocated list. |
| 50854 | */ |
| 50855 | DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing" )); |
| 50856 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); |
| 50857 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50858 | queue_back = 1; |
| 50859 | #endif |
| 50860 | } |
| 50861 | |
| 50862 | /* Dequeue object from finalize_list. Note that 'curr' may no |
| 50863 | * longer be finalize_list head because new objects may have |
| 50864 | * been queued to the list. As a result we can't optimize for |
| 50865 | * the single-linked heap case and must scan the list for |
| 50866 | * removal, typically the scan is very short however. |
| 50867 | */ |
| 50868 | DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap, curr); |
| 50869 | |
| 50870 | /* Queue back to heap_allocated or free immediately. */ |
| 50871 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 50872 | if (queue_back) { |
| 50873 | /* FINALIZED is only cleared if object originally |
| 50874 | * queued for finalization by refcounting. For |
| 50875 | * mark-and-sweep FINALIZED is left set, so that |
| 50876 | * next mark-and-sweep round can make a rescue/free |
| 50877 | * decision. |
| 50878 | */ |
| 50879 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1); |
| 50880 | DUK_HEAPHDR_PREDEC_REFCOUNT(curr); /* Remove artificial refcount bump. */ |
| 50881 | DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); |
| 50882 | DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); |
| 50883 | } else { |
| 50884 | /* No need to remove the refcount bump here. */ |
| 50885 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */ |
| 50886 | DUK_DD(DUK_DDPRINT("refcount finalize after finalizer call: %!O" , curr)); |
| 50887 | duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr); |
| 50888 | duk_free_hobject(heap, (duk_hobject *) curr); |
| 50889 | DUK_DD(DUK_DDPRINT("freed hobject after finalization: %p" , (void *) curr)); |
| 50890 | } |
| 50891 | #else /* DUK_USE_REFERENCE_COUNTING */ |
| 50892 | DUK_HEAPHDR_CLEAR_FINALIZABLE(curr); |
| 50893 | DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr); |
| 50894 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 50895 | |
| 50896 | #if defined(DUK_USE_DEBUG) |
| 50897 | count++; |
| 50898 | #endif |
| 50899 | |
| 50900 | #if defined(DUK_USE_ASSERTIONS) |
| 50901 | DUK_ASSERT(heap->currently_finalizing != NULL); |
| 50902 | heap->currently_finalizing = NULL; |
| 50903 | #endif |
| 50904 | } |
| 50905 | |
| 50906 | /* finalize_list will always be processed completely. */ |
| 50907 | DUK_ASSERT(heap->finalize_list == NULL); |
| 50908 | |
| 50909 | #if 0 |
| 50910 | /* While NORZ macros are used above, this is unnecessary because the |
| 50911 | * only pending side effects are now finalizers, and finalize_list is |
| 50912 | * empty. |
| 50913 | */ |
| 50914 | DUK_REFZERO_CHECK_SLOW(heap->heap_thread); |
| 50915 | #endif |
| 50916 | |
| 50917 | /* Prevent count may be bumped while finalizers run, but should always |
| 50918 | * be reliably unbumped by the time we get here. |
| 50919 | */ |
| 50920 | DUK_ASSERT(heap->pf_prevent_count == 1); |
| 50921 | heap->pf_prevent_count = 0; |
| 50922 | |
| 50923 | #if defined(DUK_USE_DEBUG) |
| 50924 | DUK_DD(DUK_DDPRINT("duk_heap_process_finalize_list: %ld finalizers called" , (long) count)); |
| 50925 | #endif |
| 50926 | } |
| 50927 | |
| 50928 | /* |
| 50929 | * Run an duk_hobject finalizer. Must never throw an uncaught error |
| 50930 | * (but may throw caught errors). |
| 50931 | * |
| 50932 | * There is no return value. Any return value or error thrown by |
| 50933 | * the finalizer is ignored (although errors are debug logged). |
| 50934 | * |
| 50935 | * Notes: |
| 50936 | * |
| 50937 | * - The finalizer thread 'top' assertions are there because it is |
| 50938 | * critical that strict stack policy is observed (i.e. no cruft |
| 50939 | * left on the finalizer stack). |
| 50940 | */ |
| 50941 | |
| 50942 | DUK_LOCAL duk_ret_t duk__finalize_helper(duk_hthread *thr, void *udata) { |
| 50943 | DUK_ASSERT(thr != NULL); |
| 50944 | DUK_UNREF(udata); |
| 50945 | |
| 50946 | DUK_DDD(DUK_DDDPRINT("protected finalization helper running" )); |
| 50947 | |
| 50948 | /* [... obj] */ |
| 50949 | |
| 50950 | /* _Finalizer property is read without checking if the value is |
| 50951 | * callable or even exists. This is intentional, and handled |
| 50952 | * by throwing an error which is caught by the safe call wrapper. |
| 50953 | * |
| 50954 | * XXX: Finalizer lookup should traverse the prototype chain (to allow |
| 50955 | * inherited finalizers) but should not invoke accessors or proxy object |
| 50956 | * behavior. At the moment this lookup will invoke proxy behavior, so |
| 50957 | * caller must ensure that this function is not called if the target is |
| 50958 | * a Proxy. |
| 50959 | */ |
| 50960 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ |
| 50961 | duk_dup_m2(thr); |
| 50962 | duk_push_boolean(thr, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); |
| 50963 | DUK_DDD(DUK_DDDPRINT("calling finalizer" )); |
| 50964 | duk_call(thr, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ |
| 50965 | DUK_DDD(DUK_DDDPRINT("finalizer returned successfully" )); |
| 50966 | return 0; |
| 50967 | |
| 50968 | /* Note: we rely on duk_safe_call() to fix up the stack for the caller, |
| 50969 | * so we don't need to pop stuff here. There is no return value; |
| 50970 | * caller determines rescued status based on object refcount. |
| 50971 | */ |
| 50972 | } |
| 50973 | |
| 50974 | DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) { |
| 50975 | duk_hthread *thr; |
| 50976 | duk_ret_t rc; |
| 50977 | #if defined(DUK_USE_ASSERTIONS) |
| 50978 | duk_idx_t entry_top; |
| 50979 | #endif |
| 50980 | |
| 50981 | DUK_DD(DUK_DDPRINT("running duk_hobject finalizer for object: %p" , (void *) obj)); |
| 50982 | |
| 50983 | DUK_ASSERT(heap != NULL); |
| 50984 | DUK_ASSERT(heap->heap_thread != NULL); |
| 50985 | thr = heap->heap_thread; |
| 50986 | DUK_ASSERT(obj != NULL); |
| 50987 | DUK_ASSERT_VALSTACK_SPACE(heap->heap_thread, 1); |
| 50988 | |
| 50989 | #if defined(DUK_USE_ASSERTIONS) |
| 50990 | entry_top = duk_get_top(thr); |
| 50991 | #endif |
| 50992 | /* |
| 50993 | * Get and call the finalizer. All of this must be wrapped |
| 50994 | * in a protected call, because even getting the finalizer |
| 50995 | * may trigger an error (getter may throw one, for instance). |
| 50996 | */ |
| 50997 | |
| 50998 | /* ROM objects could inherit a finalizer, but they are never deemed |
| 50999 | * unreachable by mark-and-sweep, and their refcount never falls to 0. |
| 51000 | */ |
| 51001 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); |
| 51002 | |
| 51003 | /* Duktape 2.1: finalize_list never contains objects with FINALIZED |
| 51004 | * set, so no need to check here. |
| 51005 | */ |
| 51006 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)); |
| 51007 | #if 0 |
| 51008 | if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) { |
| 51009 | DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O" , obj)); |
| 51010 | return; |
| 51011 | } |
| 51012 | #endif |
| 51013 | DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */ |
| 51014 | |
| 51015 | #if defined(DUK_USE_ES6_PROXY) |
| 51016 | if (DUK_HOBJECT_IS_PROXY(obj)) { |
| 51017 | /* This may happen if duk_set_finalizer() or Duktape.fin() is |
| 51018 | * called for a Proxy object. In such cases the fast finalizer |
| 51019 | * flag will be set on the Proxy, not the target, and neither |
| 51020 | * will be finalized. |
| 51021 | */ |
| 51022 | DUK_D(DUK_DPRINT("object is a Proxy, skip finalizer call" )); |
| 51023 | return; |
| 51024 | } |
| 51025 | #endif /* DUK_USE_ES6_PROXY */ |
| 51026 | |
| 51027 | duk_push_hobject(thr, obj); /* this also increases refcount by one */ |
| 51028 | rc = duk_safe_call(thr, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */ |
| 51029 | DUK_ASSERT_TOP(thr, entry_top + 2); /* duk_safe_call discipline */ |
| 51030 | |
| 51031 | if (rc != DUK_EXEC_SUCCESS) { |
| 51032 | /* Note: we ask for one return value from duk_safe_call to get this |
| 51033 | * error debugging here. |
| 51034 | */ |
| 51035 | DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T" , |
| 51036 | (void *) obj, (duk_tval *) duk_get_tval(thr, -1))); |
| 51037 | } |
| 51038 | duk_pop_2(thr); /* -> [...] */ |
| 51039 | |
| 51040 | DUK_ASSERT_TOP(thr, entry_top); |
| 51041 | } |
| 51042 | |
| 51043 | #else /* DUK_USE_FINALIZER_SUPPORT */ |
| 51044 | |
| 51045 | /* nothing */ |
| 51046 | |
| 51047 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 51048 | #line 1 "duk_heap_hashstring.c" |
| 51049 | /* |
| 51050 | * String hash computation (interning). |
| 51051 | * |
| 51052 | * String hashing is performance critical because a string hash is computed |
| 51053 | * for all new strings which are candidates to be added to the string table. |
| 51054 | * However, strings actually added to the string table go through a codepoint |
| 51055 | * length calculation which dominates performance because it goes through |
| 51056 | * every byte of the input string (but only for strings added). |
| 51057 | * |
| 51058 | * The string hash algorithm should be fast, but on the other hand provide |
| 51059 | * good enough hashes to ensure both string table and object property table |
| 51060 | * hash tables work reasonably well (i.e., there aren't too many collisions |
| 51061 | * with real world inputs). Unless the hash is cryptographic, it's always |
| 51062 | * possible to craft inputs with maximal hash collisions. |
| 51063 | * |
| 51064 | * NOTE: The hash algorithms must match tools/dukutil.py:duk_heap_hashstring() |
| 51065 | * for ROM string support! |
| 51066 | */ |
| 51067 | |
| 51068 | /* #include duk_internal.h -> already included */ |
| 51069 | |
| 51070 | #if defined(DUK_USE_STRHASH_DENSE) |
| 51071 | /* Constants for duk_hashstring(). */ |
| 51072 | #define DUK__STRHASH_SHORTSTRING 4096L |
| 51073 | #define DUK__STRHASH_MEDIUMSTRING (256L * 1024L) |
| 51074 | #define DUK__STRHASH_BLOCKSIZE 256L |
| 51075 | |
| 51076 | DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { |
| 51077 | duk_uint32_t hash; |
| 51078 | |
| 51079 | /* Use Murmurhash2 directly for short strings, and use "block skipping" |
| 51080 | * for long strings: hash an initial part and then sample the rest of |
| 51081 | * the string with reasonably sized chunks. An initial offset for the |
| 51082 | * sampling is computed based on a hash of the initial part of the string; |
| 51083 | * this is done to (usually) avoid the case where all long strings have |
| 51084 | * certain offset ranges which are never sampled. |
| 51085 | * |
| 51086 | * Skip should depend on length and bound the total time to roughly |
| 51087 | * logarithmic. With current values: |
| 51088 | * |
| 51089 | * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing |
| 51090 | * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing |
| 51091 | * |
| 51092 | * XXX: It would be better to compute the skip offset more "smoothly" |
| 51093 | * instead of having a few boundary values. |
| 51094 | */ |
| 51095 | |
| 51096 | /* note: mixing len into seed improves hashing when skipping */ |
| 51097 | duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len); |
| 51098 | |
| 51099 | if (len <= DUK__STRHASH_SHORTSTRING) { |
| 51100 | hash = duk_util_hashbytes(str, len, str_seed); |
| 51101 | } else { |
| 51102 | duk_size_t off; |
| 51103 | duk_size_t skip; |
| 51104 | |
| 51105 | if (len <= DUK__STRHASH_MEDIUMSTRING) { |
| 51106 | skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE); |
| 51107 | } else { |
| 51108 | skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE); |
| 51109 | } |
| 51110 | |
| 51111 | hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed); |
| 51112 | off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256; |
| 51113 | |
| 51114 | /* XXX: inefficient loop */ |
| 51115 | while (off < len) { |
| 51116 | duk_size_t left = len - off; |
| 51117 | duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left); |
| 51118 | hash ^= duk_util_hashbytes(str + off, now, str_seed); |
| 51119 | off += skip; |
| 51120 | } |
| 51121 | } |
| 51122 | |
| 51123 | #if defined(DUK_USE_STRHASH16) |
| 51124 | /* Truncate to 16 bits here, so that a computed hash can be compared |
| 51125 | * against a hash stored in a 16-bit field. |
| 51126 | */ |
| 51127 | hash &= 0x0000ffffUL; |
| 51128 | #endif |
| 51129 | return hash; |
| 51130 | } |
| 51131 | #else /* DUK_USE_STRHASH_DENSE */ |
| 51132 | DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) { |
| 51133 | duk_uint32_t hash; |
| 51134 | duk_size_t step; |
| 51135 | duk_size_t off; |
| 51136 | |
| 51137 | /* Slightly modified "Bernstein hash" from: |
| 51138 | * |
| 51139 | * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx |
| 51140 | * |
| 51141 | * Modifications: string skipping and reverse direction similar to |
| 51142 | * Lua 5.1.5, and different hash initializer. |
| 51143 | * |
| 51144 | * The reverse direction ensures last byte it always included in the |
| 51145 | * hash which is a good default as changing parts of the string are |
| 51146 | * more often in the suffix than in the prefix. |
| 51147 | */ |
| 51148 | |
| 51149 | hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */ |
| 51150 | step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1; |
| 51151 | for (off = len; off >= step; off -= step) { |
| 51152 | DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */ |
| 51153 | hash = (hash * 33) + str[off - 1]; |
| 51154 | } |
| 51155 | |
| 51156 | #if defined(DUK_USE_STRHASH16) |
| 51157 | /* Truncate to 16 bits here, so that a computed hash can be compared |
| 51158 | * against a hash stored in a 16-bit field. |
| 51159 | */ |
| 51160 | hash &= 0x0000ffffUL; |
| 51161 | #endif |
| 51162 | return hash; |
| 51163 | } |
| 51164 | #endif /* DUK_USE_STRHASH_DENSE */ |
| 51165 | |
| 51166 | /* automatic undefs */ |
| 51167 | #undef DUK__STRHASH_BLOCKSIZE |
| 51168 | #undef DUK__STRHASH_MEDIUMSTRING |
| 51169 | #undef DUK__STRHASH_SHORTSTRING |
| 51170 | #line 1 "duk_heap_markandsweep.c" |
| 51171 | /* |
| 51172 | * Mark-and-sweep garbage collection. |
| 51173 | */ |
| 51174 | |
| 51175 | /* #include duk_internal.h -> already included */ |
| 51176 | |
| 51177 | DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h); |
| 51178 | DUK_LOCAL_DECL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h); |
| 51179 | DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv); |
| 51180 | DUK_LOCAL_DECL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count); |
| 51181 | |
| 51182 | /* |
| 51183 | * Marking functions for heap types: mark children recursively. |
| 51184 | */ |
| 51185 | |
| 51186 | DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { |
| 51187 | DUK_UNREF(heap); |
| 51188 | DUK_UNREF(h); |
| 51189 | |
| 51190 | DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p" , (void *) h)); |
| 51191 | DUK_ASSERT(h); |
| 51192 | DUK_HSTRING_ASSERT_VALID(h); |
| 51193 | |
| 51194 | /* nothing to process */ |
| 51195 | } |
| 51196 | |
| 51197 | DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) { |
| 51198 | duk_uint_fast32_t i; |
| 51199 | |
| 51200 | DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p" , (void *) h)); |
| 51201 | |
| 51202 | DUK_ASSERT(h); |
| 51203 | DUK_HOBJECT_ASSERT_VALID(h); |
| 51204 | |
| 51205 | /* XXX: use advancing pointers instead of index macros -> faster and smaller? */ |
| 51206 | |
| 51207 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { |
| 51208 | duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i); |
| 51209 | if (key == NULL) { |
| 51210 | continue; |
| 51211 | } |
| 51212 | duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) key); |
| 51213 | if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) { |
| 51214 | duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get); |
| 51215 | duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set); |
| 51216 | } else { |
| 51217 | duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v); |
| 51218 | } |
| 51219 | } |
| 51220 | |
| 51221 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { |
| 51222 | duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i)); |
| 51223 | } |
| 51224 | |
| 51225 | /* Hash part is a 'weak reference' and does not contribute. */ |
| 51226 | |
| 51227 | duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h)); |
| 51228 | |
| 51229 | /* Fast path for objects which don't have a subclass struct, or have a |
| 51230 | * subclass struct but nothing that needs marking in the subclass struct. |
| 51231 | */ |
| 51232 | if (DUK_HOBJECT_HAS_FASTREFS(h)) { |
| 51233 | DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); |
| 51234 | return; |
| 51235 | } |
| 51236 | DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); |
| 51237 | |
| 51238 | /* XXX: reorg, more common first */ |
| 51239 | if (DUK_HOBJECT_IS_COMPFUNC(h)) { |
| 51240 | duk_hcompfunc *f = (duk_hcompfunc *) h; |
| 51241 | duk_tval *tv, *tv_end; |
| 51242 | duk_hobject **fn, **fn_end; |
| 51243 | |
| 51244 | DUK_HCOMPFUNC_ASSERT_VALID(f); |
| 51245 | |
| 51246 | /* 'data' is reachable through every compiled function which |
| 51247 | * contains a reference. |
| 51248 | */ |
| 51249 | |
| 51250 | duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_DATA(heap, f)); |
| 51251 | duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f)); |
| 51252 | duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f)); |
| 51253 | |
| 51254 | if (DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL) { |
| 51255 | tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f); |
| 51256 | tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f); |
| 51257 | while (tv < tv_end) { |
| 51258 | duk__mark_tval(heap, tv); |
| 51259 | tv++; |
| 51260 | } |
| 51261 | |
| 51262 | fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f); |
| 51263 | fn_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f); |
| 51264 | while (fn < fn_end) { |
| 51265 | duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) *fn); |
| 51266 | fn++; |
| 51267 | } |
| 51268 | } else { |
| 51269 | /* May happen in some out-of-memory corner cases. */ |
| 51270 | DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking" )); |
| 51271 | } |
| 51272 | } else if (DUK_HOBJECT_IS_DECENV(h)) { |
| 51273 | duk_hdecenv *e = (duk_hdecenv *) h; |
| 51274 | DUK_HDECENV_ASSERT_VALID(e); |
| 51275 | duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread); |
| 51276 | duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap); |
| 51277 | } else if (DUK_HOBJECT_IS_OBJENV(h)) { |
| 51278 | duk_hobjenv *e = (duk_hobjenv *) h; |
| 51279 | DUK_HOBJENV_ASSERT_VALID(e); |
| 51280 | duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) e->target); |
| 51281 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 51282 | } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 51283 | duk_hbufobj *b = (duk_hbufobj *) h; |
| 51284 | DUK_HBUFOBJ_ASSERT_VALID(b); |
| 51285 | duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf); |
| 51286 | duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop); |
| 51287 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 51288 | } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { |
| 51289 | duk_hboundfunc *f = (duk_hboundfunc *) (void *) h; |
| 51290 | DUK_HBOUNDFUNC_ASSERT_VALID(f); |
| 51291 | duk__mark_tval(heap, &f->target); |
| 51292 | duk__mark_tval(heap, &f->this_binding); |
| 51293 | duk__mark_tvals(heap, f->args, f->nargs); |
| 51294 | #if defined(DUK_USE_ES6_PROXY) |
| 51295 | } else if (DUK_HOBJECT_IS_PROXY(h)) { |
| 51296 | duk_hproxy *p = (duk_hproxy *) h; |
| 51297 | DUK_HPROXY_ASSERT_VALID(p); |
| 51298 | duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->target); |
| 51299 | duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->handler); |
| 51300 | #endif /* DUK_USE_ES6_PROXY */ |
| 51301 | } else if (DUK_HOBJECT_IS_THREAD(h)) { |
| 51302 | duk_hthread *t = (duk_hthread *) h; |
| 51303 | duk_activation *act; |
| 51304 | duk_tval *tv; |
| 51305 | |
| 51306 | DUK_HTHREAD_ASSERT_VALID(t); |
| 51307 | |
| 51308 | tv = t->valstack; |
| 51309 | while (tv < t->valstack_top) { |
| 51310 | duk__mark_tval(heap, tv); |
| 51311 | tv++; |
| 51312 | } |
| 51313 | |
| 51314 | for (act = t->callstack_curr; act != NULL; act = act->parent) { |
| 51315 | duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act)); |
| 51316 | duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env); |
| 51317 | duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env); |
| 51318 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 51319 | duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller); |
| 51320 | #endif |
| 51321 | #if 0 /* nothing now */ |
| 51322 | for (cat = act->cat; cat != NULL; cat = cat->parent) { |
| 51323 | } |
| 51324 | #endif |
| 51325 | } |
| 51326 | |
| 51327 | duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer); |
| 51328 | |
| 51329 | for (i = 0; i < DUK_NUM_BUILTINS; i++) { |
| 51330 | duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]); |
| 51331 | } |
| 51332 | } else { |
| 51333 | /* We may come here if the object should have a FASTREFS flag |
| 51334 | * but it's missing for some reason. Assert for never getting |
| 51335 | * here; however, other than performance, this is harmless. |
| 51336 | */ |
| 51337 | DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO" , h)); |
| 51338 | DUK_ASSERT(0); |
| 51339 | } |
| 51340 | } |
| 51341 | |
| 51342 | /* Mark any duk_heaphdr type. Recursion tracking happens only here. */ |
| 51343 | DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) { |
| 51344 | DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld" , |
| 51345 | (void *) h, |
| 51346 | (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1))); |
| 51347 | |
| 51348 | /* XXX: add non-null variant? */ |
| 51349 | if (h == NULL) { |
| 51350 | return; |
| 51351 | } |
| 51352 | |
| 51353 | DUK_HEAPHDR_ASSERT_VALID(h); |
| 51354 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h) || DUK_HEAPHDR_HAS_REACHABLE(h)); |
| 51355 | |
| 51356 | #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) |
| 51357 | if (!DUK_HEAPHDR_HAS_READONLY(h)) { |
| 51358 | h->h_assert_refcount++; /* Comparison refcount: bump even if already reachable. */ |
| 51359 | } |
| 51360 | #endif |
| 51361 | if (DUK_HEAPHDR_HAS_REACHABLE(h)) { |
| 51362 | DUK_DDD(DUK_DDDPRINT("already marked reachable, skip" )); |
| 51363 | return; |
| 51364 | } |
| 51365 | #if defined(DUK_USE_ROM_OBJECTS) |
| 51366 | /* READONLY objects always have REACHABLE set, so the check above |
| 51367 | * will prevent READONLY objects from being marked here. |
| 51368 | */ |
| 51369 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h)); |
| 51370 | #endif |
| 51371 | |
| 51372 | DUK_HEAPHDR_SET_REACHABLE(h); |
| 51373 | |
| 51374 | if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) { |
| 51375 | DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p" , (void *) h)); |
| 51376 | DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap); |
| 51377 | DUK_HEAPHDR_SET_TEMPROOT(h); |
| 51378 | return; |
| 51379 | } |
| 51380 | |
| 51381 | heap->ms_recursion_depth++; |
| 51382 | DUK_ASSERT(heap->ms_recursion_depth != 0); /* Wrap. */ |
| 51383 | |
| 51384 | switch (DUK_HEAPHDR_GET_TYPE(h)) { |
| 51385 | case DUK_HTYPE_STRING: |
| 51386 | duk__mark_hstring(heap, (duk_hstring *) h); |
| 51387 | break; |
| 51388 | case DUK_HTYPE_OBJECT: |
| 51389 | duk__mark_hobject(heap, (duk_hobject *) h); |
| 51390 | break; |
| 51391 | case DUK_HTYPE_BUFFER: |
| 51392 | /* nothing to mark */ |
| 51393 | break; |
| 51394 | default: |
| 51395 | DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld" , (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h))); |
| 51396 | DUK_UNREACHABLE(); |
| 51397 | } |
| 51398 | |
| 51399 | DUK_ASSERT(heap->ms_recursion_depth > 0); |
| 51400 | heap->ms_recursion_depth--; |
| 51401 | } |
| 51402 | |
| 51403 | DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) { |
| 51404 | DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p" , (void *) tv)); |
| 51405 | if (tv == NULL) { |
| 51406 | return; |
| 51407 | } |
| 51408 | DUK_TVAL_ASSERT_VALID(tv); |
| 51409 | if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { |
| 51410 | duk_heaphdr *h; |
| 51411 | h = DUK_TVAL_GET_HEAPHDR(tv); |
| 51412 | DUK_ASSERT(h != NULL); |
| 51413 | duk__mark_heaphdr_nonnull(heap, h); |
| 51414 | } |
| 51415 | } |
| 51416 | |
| 51417 | DUK_LOCAL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count) { |
| 51418 | DUK_ASSERT(count == 0 || tv != NULL); |
| 51419 | |
| 51420 | while (count-- > 0) { |
| 51421 | DUK_TVAL_ASSERT_VALID(tv); |
| 51422 | if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) { |
| 51423 | duk_heaphdr *h; |
| 51424 | h = DUK_TVAL_GET_HEAPHDR(tv); |
| 51425 | DUK_ASSERT(h != NULL); |
| 51426 | duk__mark_heaphdr_nonnull(heap, h); |
| 51427 | } |
| 51428 | tv++; |
| 51429 | } |
| 51430 | } |
| 51431 | |
| 51432 | /* Mark any duk_heaphdr type, caller guarantees a non-NULL pointer. */ |
| 51433 | DUK_LOCAL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h) { |
| 51434 | /* For now, just call the generic handler. Change when call sites |
| 51435 | * are changed too. |
| 51436 | */ |
| 51437 | duk__mark_heaphdr(heap, h); |
| 51438 | } |
| 51439 | |
| 51440 | /* |
| 51441 | * Mark the heap. |
| 51442 | */ |
| 51443 | |
| 51444 | DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) { |
| 51445 | duk_small_uint_t i; |
| 51446 | |
| 51447 | DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p" , (void *) heap)); |
| 51448 | |
| 51449 | duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread); |
| 51450 | duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object); |
| 51451 | |
| 51452 | for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) { |
| 51453 | duk_hstring *h = DUK_HEAP_GET_STRING(heap, i); |
| 51454 | duk__mark_heaphdr(heap, (duk_heaphdr *) h); |
| 51455 | } |
| 51456 | |
| 51457 | duk__mark_tval(heap, &heap->lj.value1); |
| 51458 | duk__mark_tval(heap, &heap->lj.value2); |
| 51459 | |
| 51460 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 51461 | for (i = 0; i < heap->dbg_breakpoint_count; i++) { |
| 51462 | duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename); |
| 51463 | } |
| 51464 | #endif |
| 51465 | } |
| 51466 | |
| 51467 | /* |
| 51468 | * Mark unreachable, finalizable objects. |
| 51469 | * |
| 51470 | * Such objects will be moved aside and their finalizers run later. They |
| 51471 | * have to be treated as reachability roots for their properties etc to |
| 51472 | * remain allocated. This marking is only done for unreachable values which |
| 51473 | * would be swept later. |
| 51474 | * |
| 51475 | * Objects are first marked FINALIZABLE and only then marked as reachability |
| 51476 | * roots; otherwise circular references might be handled inconsistently. |
| 51477 | */ |
| 51478 | |
| 51479 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 51480 | DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) { |
| 51481 | duk_heaphdr *hdr; |
| 51482 | duk_size_t count_finalizable = 0; |
| 51483 | |
| 51484 | DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p" , (void *) heap)); |
| 51485 | |
| 51486 | DUK_ASSERT(heap->heap_thread != NULL); |
| 51487 | |
| 51488 | hdr = heap->heap_allocated; |
| 51489 | while (hdr != NULL) { |
| 51490 | /* A finalizer is looked up from the object and up its |
| 51491 | * prototype chain (which allows inherited finalizers). |
| 51492 | * The finalizer is checked for using a duk_hobject flag |
| 51493 | * which is kept in sync with the presence and callability |
| 51494 | * of a _Finalizer hidden symbol. |
| 51495 | */ |
| 51496 | |
| 51497 | if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) && |
| 51498 | DUK_HEAPHDR_IS_OBJECT(hdr) && |
| 51499 | !DUK_HEAPHDR_HAS_FINALIZED(hdr) && |
| 51500 | DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) { |
| 51501 | /* heaphdr: |
| 51502 | * - is not reachable |
| 51503 | * - is an object |
| 51504 | * - is not a finalized object waiting for rescue/keep decision |
| 51505 | * - has a finalizer |
| 51506 | */ |
| 51507 | |
| 51508 | DUK_DD(DUK_DDPRINT("unreachable heap object will be " |
| 51509 | "finalized -> mark as finalizable " |
| 51510 | "and treat as a reachability root: %p" , |
| 51511 | (void *) hdr)); |
| 51512 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); |
| 51513 | DUK_HEAPHDR_SET_FINALIZABLE(hdr); |
| 51514 | count_finalizable++; |
| 51515 | } |
| 51516 | |
| 51517 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 51518 | } |
| 51519 | |
| 51520 | if (count_finalizable == 0) { |
| 51521 | return; |
| 51522 | } |
| 51523 | |
| 51524 | DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable" , |
| 51525 | (long) count_finalizable)); |
| 51526 | |
| 51527 | hdr = heap->heap_allocated; |
| 51528 | while (hdr != NULL) { |
| 51529 | if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) { |
| 51530 | duk__mark_heaphdr_nonnull(heap, hdr); |
| 51531 | } |
| 51532 | |
| 51533 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 51534 | } |
| 51535 | |
| 51536 | /* Caller will finish the marking process if we hit a recursion limit. */ |
| 51537 | } |
| 51538 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 51539 | |
| 51540 | /* |
| 51541 | * Mark objects on finalize_list. |
| 51542 | */ |
| 51543 | |
| 51544 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 51545 | DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) { |
| 51546 | duk_heaphdr *hdr; |
| 51547 | #if defined(DUK_USE_DEBUG) |
| 51548 | duk_size_t count_finalize_list = 0; |
| 51549 | #endif |
| 51550 | |
| 51551 | DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p" , (void *) heap)); |
| 51552 | |
| 51553 | hdr = heap->finalize_list; |
| 51554 | while (hdr != NULL) { |
| 51555 | duk__mark_heaphdr_nonnull(heap, hdr); |
| 51556 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 51557 | #if defined(DUK_USE_DEBUG) |
| 51558 | count_finalize_list++; |
| 51559 | #endif |
| 51560 | } |
| 51561 | |
| 51562 | #if defined(DUK_USE_DEBUG) |
| 51563 | if (count_finalize_list > 0) { |
| 51564 | DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)" , |
| 51565 | (long) count_finalize_list)); |
| 51566 | } |
| 51567 | #endif |
| 51568 | } |
| 51569 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 51570 | |
| 51571 | /* |
| 51572 | * Fallback marking handler if recursion limit is reached. |
| 51573 | * |
| 51574 | * Iterates 'temproots' until recursion limit is no longer hit. Temproots |
| 51575 | * can be in heap_allocated or finalize_list; refzero_list is now always |
| 51576 | * empty for mark-and-sweep. A temproot may occur in finalize_list now if |
| 51577 | * there are objects on the finalize_list and user code creates a reference |
| 51578 | * from an object in heap_allocated to the object in finalize_list (which is |
| 51579 | * now allowed), and it happened to coincide with the recursion depth limit. |
| 51580 | * |
| 51581 | * This is a slow scan, but guarantees that we finish with a bounded C stack. |
| 51582 | * |
| 51583 | * Note that nodes may have been marked as temproots before this scan begun, |
| 51584 | * OR they may have been marked during the scan (as we process nodes |
| 51585 | * recursively also during the scan). This is intended behavior. |
| 51586 | */ |
| 51587 | |
| 51588 | #if defined(DUK_USE_DEBUG) |
| 51589 | DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) { |
| 51590 | #else |
| 51591 | DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) { |
| 51592 | #endif |
| 51593 | DUK_ASSERT(hdr != NULL); |
| 51594 | |
| 51595 | if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) { |
| 51596 | DUK_DDD(DUK_DDDPRINT("not a temp root: %p" , (void *) hdr)); |
| 51597 | return; |
| 51598 | } |
| 51599 | |
| 51600 | DUK_DDD(DUK_DDDPRINT("found a temp root: %p" , (void *) hdr)); |
| 51601 | DUK_HEAPHDR_CLEAR_TEMPROOT(hdr); |
| 51602 | DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* Done so that duk__mark_heaphdr() works correctly. */ |
| 51603 | #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) |
| 51604 | hdr->h_assert_refcount--; /* Same node visited twice. */ |
| 51605 | #endif |
| 51606 | duk__mark_heaphdr_nonnull(heap, hdr); |
| 51607 | |
| 51608 | #if defined(DUK_USE_DEBUG) |
| 51609 | (*count)++; |
| 51610 | #endif |
| 51611 | } |
| 51612 | |
| 51613 | DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) { |
| 51614 | duk_heaphdr *hdr; |
| 51615 | #if defined(DUK_USE_DEBUG) |
| 51616 | duk_size_t count; |
| 51617 | #endif |
| 51618 | |
| 51619 | DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p" , (void *) heap)); |
| 51620 | |
| 51621 | while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) { |
| 51622 | DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots" )); |
| 51623 | |
| 51624 | #if defined(DUK_USE_DEBUG) |
| 51625 | count = 0; |
| 51626 | #endif |
| 51627 | DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap); |
| 51628 | |
| 51629 | hdr = heap->heap_allocated; |
| 51630 | while (hdr) { |
| 51631 | #if defined(DUK_USE_DEBUG) |
| 51632 | duk__handle_temproot(heap, hdr, &count); |
| 51633 | #else |
| 51634 | duk__handle_temproot(heap, hdr); |
| 51635 | #endif |
| 51636 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 51637 | } |
| 51638 | |
| 51639 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 51640 | hdr = heap->finalize_list; |
| 51641 | while (hdr) { |
| 51642 | #if defined(DUK_USE_DEBUG) |
| 51643 | duk__handle_temproot(heap, hdr, &count); |
| 51644 | #else |
| 51645 | duk__handle_temproot(heap, hdr); |
| 51646 | #endif |
| 51647 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 51648 | } |
| 51649 | #endif |
| 51650 | |
| 51651 | #if defined(DUK_USE_DEBUG) |
| 51652 | DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots" , (long) count)); |
| 51653 | #endif |
| 51654 | } |
| 51655 | } |
| 51656 | |
| 51657 | /* |
| 51658 | * Finalize refcounts for heap elements just about to be freed. |
| 51659 | * This must be done for all objects before freeing to avoid any |
| 51660 | * stale pointer dereferences. |
| 51661 | * |
| 51662 | * Note that this must deduce the set of objects to be freed |
| 51663 | * identically to duk__sweep_heap(). |
| 51664 | */ |
| 51665 | |
| 51666 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 51667 | DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) { |
| 51668 | duk_heaphdr *hdr; |
| 51669 | |
| 51670 | DUK_ASSERT(heap->heap_thread != NULL); |
| 51671 | |
| 51672 | DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p" , (void *) heap)); |
| 51673 | |
| 51674 | hdr = heap->heap_allocated; |
| 51675 | while (hdr) { |
| 51676 | if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) { |
| 51677 | /* |
| 51678 | * Unreachable object about to be swept. Finalize target refcounts |
| 51679 | * (objects which the unreachable object points to) without doing |
| 51680 | * refzero processing. Recursive decrefs are also prevented when |
| 51681 | * refzero processing is disabled. |
| 51682 | * |
| 51683 | * Value cannot be a finalizable object, as they have been made |
| 51684 | * temporarily reachable for this round. |
| 51685 | */ |
| 51686 | |
| 51687 | DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p" , (void *) hdr)); |
| 51688 | |
| 51689 | /* Finalize using heap->heap_thread; DECREF has a |
| 51690 | * suppress check for mark-and-sweep which is based |
| 51691 | * on heap->ms_running. |
| 51692 | */ |
| 51693 | duk_heaphdr_refcount_finalize_norz(heap, hdr); |
| 51694 | } |
| 51695 | |
| 51696 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 51697 | } |
| 51698 | } |
| 51699 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 51700 | |
| 51701 | /* |
| 51702 | * Clear (reachable) flags of finalize_list. |
| 51703 | * |
| 51704 | * We could mostly do in the sweep phase when we move objects from the |
| 51705 | * heap into the finalize_list. However, if a finalizer run is skipped |
| 51706 | * during a mark-and-sweep, the objects on the finalize_list will be marked |
| 51707 | * reachable during the next mark-and-sweep. Since they're already on the |
| 51708 | * finalize_list, no-one will be clearing their REACHABLE flag so we do it |
| 51709 | * here. (This now overlaps with the sweep handling in a harmless way.) |
| 51710 | */ |
| 51711 | |
| 51712 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 51713 | DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) { |
| 51714 | duk_heaphdr *hdr; |
| 51715 | |
| 51716 | DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p" , (void *) heap)); |
| 51717 | |
| 51718 | hdr = heap->finalize_list; |
| 51719 | while (hdr) { |
| 51720 | DUK_HEAPHDR_CLEAR_REACHABLE(hdr); |
| 51721 | #if defined(DUK_USE_ASSERTIONS) |
| 51722 | DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \ |
| 51723 | (heap->currently_finalizing == hdr)); |
| 51724 | #endif |
| 51725 | /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */ |
| 51726 | DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr)); |
| 51727 | hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 51728 | } |
| 51729 | } |
| 51730 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 51731 | |
| 51732 | /* |
| 51733 | * Sweep stringtable. |
| 51734 | */ |
| 51735 | |
| 51736 | DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) { |
| 51737 | duk_hstring *h; |
| 51738 | duk_hstring *prev; |
| 51739 | duk_uint32_t i; |
| 51740 | #if defined(DUK_USE_DEBUG) |
| 51741 | duk_size_t count_free = 0; |
| 51742 | #endif |
| 51743 | duk_size_t count_keep = 0; |
| 51744 | |
| 51745 | DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p" , (void *) heap)); |
| 51746 | |
| 51747 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 51748 | if (heap->strtable16 == NULL) { |
| 51749 | #else |
| 51750 | if (heap->strtable == NULL) { |
| 51751 | #endif |
| 51752 | goto done; |
| 51753 | } |
| 51754 | |
| 51755 | for (i = 0; i < heap->st_size; i++) { |
| 51756 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 51757 | h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); |
| 51758 | #else |
| 51759 | h = heap->strtable[i]; |
| 51760 | #endif |
| 51761 | prev = NULL; |
| 51762 | while (h != NULL) { |
| 51763 | duk_hstring *next; |
| 51764 | next = h->hdr.h_next; |
| 51765 | |
| 51766 | if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) |
| 51767 | { |
| 51768 | DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h); |
| 51769 | count_keep++; |
| 51770 | prev = h; |
| 51771 | } else { |
| 51772 | #if defined(DUK_USE_DEBUG) |
| 51773 | count_free++; |
| 51774 | #endif |
| 51775 | |
| 51776 | /* For pinned strings the refcount has been |
| 51777 | * bumped. We could unbump it here before |
| 51778 | * freeing, but that's actually not necessary |
| 51779 | * except for assertions. |
| 51780 | */ |
| 51781 | #if 0 |
| 51782 | if (DUK_HSTRING_HAS_PINNED_LITERAL(h)) { |
| 51783 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) > 0U); |
| 51784 | DUK_HSTRING_DECREF_NORZ(heap->heap_thread, h); |
| 51785 | DUK_HSTRING_CLEAR_PINNED_LITERAL(h); |
| 51786 | } |
| 51787 | #endif |
| 51788 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 51789 | /* Non-zero refcounts should not happen for unreachable strings, |
| 51790 | * because we refcount finalize all unreachable objects which |
| 51791 | * should have decreased unreachable string refcounts to zero |
| 51792 | * (even for cycles). However, pinned strings have a +1 bump. |
| 51793 | */ |
| 51794 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == |
| 51795 | DUK_HSTRING_HAS_PINNED_LITERAL(h) ? 1U : 0U); |
| 51796 | #endif |
| 51797 | |
| 51798 | /* Deal with weak references first. */ |
| 51799 | duk_heap_strcache_string_remove(heap, (duk_hstring *) h); |
| 51800 | |
| 51801 | /* Remove the string from the string table. */ |
| 51802 | duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev); |
| 51803 | |
| 51804 | /* Free inner references (these exist e.g. when external |
| 51805 | * strings are enabled) and the struct itself. |
| 51806 | */ |
| 51807 | duk_free_hstring(heap, (duk_hstring *) h); |
| 51808 | |
| 51809 | /* Don't update 'prev'; it should be last string kept. */ |
| 51810 | } |
| 51811 | |
| 51812 | h = next; |
| 51813 | } |
| 51814 | } |
| 51815 | |
| 51816 | done: |
| 51817 | #if defined(DUK_USE_DEBUG) |
| 51818 | DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept" , |
| 51819 | (long) count_free, (long) count_keep)); |
| 51820 | #endif |
| 51821 | *out_count_keep = count_keep; |
| 51822 | } |
| 51823 | |
| 51824 | /* |
| 51825 | * Sweep heap. |
| 51826 | */ |
| 51827 | |
| 51828 | DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_t *out_count_keep) { |
| 51829 | duk_heaphdr *prev; /* last element that was left in the heap */ |
| 51830 | duk_heaphdr *curr; |
| 51831 | duk_heaphdr *next; |
| 51832 | #if defined(DUK_USE_DEBUG) |
| 51833 | duk_size_t count_free = 0; |
| 51834 | duk_size_t count_finalize = 0; |
| 51835 | duk_size_t count_rescue = 0; |
| 51836 | #endif |
| 51837 | duk_size_t count_keep = 0; |
| 51838 | |
| 51839 | DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p" , (void *) heap)); |
| 51840 | |
| 51841 | prev = NULL; |
| 51842 | curr = heap->heap_allocated; |
| 51843 | heap->heap_allocated = NULL; |
| 51844 | while (curr) { |
| 51845 | /* Strings and ROM objects are never placed on the heap allocated list. */ |
| 51846 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING); |
| 51847 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); |
| 51848 | |
| 51849 | next = DUK_HEAPHDR_GET_NEXT(heap, curr); |
| 51850 | |
| 51851 | if (DUK_HEAPHDR_HAS_REACHABLE(curr)) { |
| 51852 | /* |
| 51853 | * Reachable object: |
| 51854 | * - If FINALIZABLE -> actually unreachable (but marked |
| 51855 | * artificially reachable), queue to finalize_list. |
| 51856 | * - If !FINALIZABLE but FINALIZED -> rescued after |
| 51857 | * finalizer execution. |
| 51858 | * - Otherwise just a normal, reachable object. |
| 51859 | * |
| 51860 | * Objects which are kept are queued to heap_allocated |
| 51861 | * tail (we're essentially filtering heap_allocated in |
| 51862 | * practice). |
| 51863 | */ |
| 51864 | |
| 51865 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 51866 | if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) { |
| 51867 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); |
| 51868 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); |
| 51869 | DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p" , (void *) curr)); |
| 51870 | |
| 51871 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 51872 | DUK_HEAPHDR_PREINC_REFCOUNT(curr); /* Bump refcount so that refzero never occurs when pending a finalizer call. */ |
| 51873 | #endif |
| 51874 | DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr); |
| 51875 | #if defined(DUK_USE_DEBUG) |
| 51876 | count_finalize++; |
| 51877 | #endif |
| 51878 | } |
| 51879 | else |
| 51880 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 51881 | { |
| 51882 | if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) { |
| 51883 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); |
| 51884 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); |
| 51885 | |
| 51886 | if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) { |
| 51887 | DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO" , curr)); |
| 51888 | count_keep++; |
| 51889 | } else { |
| 51890 | DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p" , (void *) curr)); |
| 51891 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 51892 | DUK_HEAPHDR_CLEAR_FINALIZED(curr); |
| 51893 | #endif |
| 51894 | #if defined(DUK_USE_DEBUG) |
| 51895 | count_rescue++; |
| 51896 | #endif |
| 51897 | } |
| 51898 | } else { |
| 51899 | DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO" , curr)); |
| 51900 | count_keep++; |
| 51901 | } |
| 51902 | |
| 51903 | if (prev != NULL) { |
| 51904 | DUK_ASSERT(heap->heap_allocated != NULL); |
| 51905 | DUK_HEAPHDR_SET_NEXT(heap, prev, curr); |
| 51906 | } else { |
| 51907 | DUK_ASSERT(heap->heap_allocated == NULL); |
| 51908 | heap->heap_allocated = curr; |
| 51909 | } |
| 51910 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 51911 | DUK_HEAPHDR_SET_PREV(heap, curr, prev); |
| 51912 | #endif |
| 51913 | DUK_HEAPHDR_ASSERT_LINKS(heap, prev); |
| 51914 | DUK_HEAPHDR_ASSERT_LINKS(heap, curr); |
| 51915 | prev = curr; |
| 51916 | } |
| 51917 | |
| 51918 | /* |
| 51919 | * Shrink check for value stacks here. We're inside |
| 51920 | * ms_prevent_count protection which prevents recursive |
| 51921 | * mark-and-sweep and refzero finalizers, so there are |
| 51922 | * no side effects that would affect the heap lists. |
| 51923 | */ |
| 51924 | if (DUK_HEAPHDR_IS_OBJECT(curr) && DUK_HOBJECT_IS_THREAD((duk_hobject *) curr)) { |
| 51925 | duk_hthread *thr_curr = (duk_hthread *) curr; |
| 51926 | DUK_DD(DUK_DDPRINT("value stack shrink check for thread: %!O" , curr)); |
| 51927 | duk_valstack_shrink_check_nothrow(thr_curr, flags & DUK_MS_FLAG_EMERGENCY /*snug*/); |
| 51928 | } |
| 51929 | |
| 51930 | DUK_HEAPHDR_CLEAR_REACHABLE(curr); |
| 51931 | /* Keep FINALIZED if set, used if rescue decisions are postponed. */ |
| 51932 | /* Keep FINALIZABLE for objects on finalize_list. */ |
| 51933 | DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); |
| 51934 | } else { |
| 51935 | /* |
| 51936 | * Unreachable object: |
| 51937 | * - If FINALIZED, object was finalized but not |
| 51938 | * rescued. This doesn't affect freeing. |
| 51939 | * - Otherwise normal unreachable object. |
| 51940 | * |
| 51941 | * There's no guard preventing a FINALIZED object |
| 51942 | * from being freed while finalizers execute: the |
| 51943 | * artificial finalize_list reachability roots can't |
| 51944 | * cause an incorrect free decision (but can cause |
| 51945 | * an incorrect rescue decision). |
| 51946 | */ |
| 51947 | |
| 51948 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 51949 | /* Non-zero refcounts should not happen because we refcount |
| 51950 | * finalize all unreachable objects which should cancel out |
| 51951 | * refcounts (even for cycles). |
| 51952 | */ |
| 51953 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0); |
| 51954 | #endif |
| 51955 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr)); |
| 51956 | |
| 51957 | #if defined(DUK_USE_DEBUG) |
| 51958 | if (DUK_HEAPHDR_HAS_FINALIZED(curr)) { |
| 51959 | DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p" , (void *) curr)); |
| 51960 | } else { |
| 51961 | DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p" , (void *) curr)); |
| 51962 | } |
| 51963 | |
| 51964 | #endif |
| 51965 | |
| 51966 | /* Note: object cannot be a finalizable unreachable object, as |
| 51967 | * they have been marked temporarily reachable for this round, |
| 51968 | * and are handled above. |
| 51969 | */ |
| 51970 | |
| 51971 | #if defined(DUK_USE_DEBUG) |
| 51972 | count_free++; |
| 51973 | #endif |
| 51974 | |
| 51975 | /* Weak refs should be handled here, but no weak refs for |
| 51976 | * any non-string objects exist right now. |
| 51977 | */ |
| 51978 | |
| 51979 | /* Free object and all auxiliary (non-heap) allocs. */ |
| 51980 | duk_heap_free_heaphdr_raw(heap, curr); |
| 51981 | } |
| 51982 | |
| 51983 | curr = next; |
| 51984 | } |
| 51985 | |
| 51986 | if (prev != NULL) { |
| 51987 | DUK_HEAPHDR_SET_NEXT(heap, prev, NULL); |
| 51988 | } |
| 51989 | DUK_HEAPHDR_ASSERT_LINKS(heap, prev); |
| 51990 | |
| 51991 | #if defined(DUK_USE_DEBUG) |
| 51992 | DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization" , |
| 51993 | (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize)); |
| 51994 | #endif |
| 51995 | *out_count_keep = count_keep; |
| 51996 | } |
| 51997 | |
| 51998 | /* |
| 51999 | * Litcache helpers. |
| 52000 | */ |
| 52001 | |
| 52002 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 52003 | DUK_LOCAL void duk__wipe_litcache(duk_heap *heap) { |
| 52004 | duk_uint_t i; |
| 52005 | duk_litcache_entry *e; |
| 52006 | |
| 52007 | e = heap->litcache; |
| 52008 | for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) { |
| 52009 | e->addr = NULL; |
| 52010 | /* e->h does not need to be invalidated: when e->addr is |
| 52011 | * NULL, e->h is considered garbage. |
| 52012 | */ |
| 52013 | e++; |
| 52014 | } |
| 52015 | } |
| 52016 | #endif /* DUK_USE_LITCACHE_SIZE */ |
| 52017 | |
| 52018 | /* |
| 52019 | * Object compaction. |
| 52020 | * |
| 52021 | * Compaction is assumed to never throw an error. |
| 52022 | */ |
| 52023 | |
| 52024 | DUK_LOCAL int duk__protected_compact_object(duk_hthread *thr, void *udata) { |
| 52025 | duk_hobject *obj; |
| 52026 | /* XXX: for threads, compact stacks? */ |
| 52027 | |
| 52028 | DUK_UNREF(udata); |
| 52029 | obj = duk_known_hobject(thr, -1); |
| 52030 | duk_hobject_compact_props(thr, obj); |
| 52031 | return 0; |
| 52032 | } |
| 52033 | |
| 52034 | #if defined(DUK_USE_DEBUG) |
| 52035 | DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, duk_size_t *p_count_check, duk_size_t *p_count_compact, duk_size_t *p_count_bytes_saved) { |
| 52036 | #else |
| 52037 | DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) { |
| 52038 | #endif |
| 52039 | duk_heaphdr *curr; |
| 52040 | #if defined(DUK_USE_DEBUG) |
| 52041 | duk_size_t old_size, new_size; |
| 52042 | #endif |
| 52043 | duk_hobject *obj; |
| 52044 | |
| 52045 | DUK_UNREF(heap); |
| 52046 | |
| 52047 | curr = start; |
| 52048 | while (curr) { |
| 52049 | DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p" , (void *) curr)); |
| 52050 | |
| 52051 | if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) { |
| 52052 | goto next; |
| 52053 | } |
| 52054 | obj = (duk_hobject *) curr; |
| 52055 | |
| 52056 | #if defined(DUK_USE_DEBUG) |
| 52057 | old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), |
| 52058 | DUK_HOBJECT_GET_ASIZE(obj), |
| 52059 | DUK_HOBJECT_GET_HSIZE(obj)); |
| 52060 | #endif |
| 52061 | |
| 52062 | DUK_DD(DUK_DDPRINT("compact object: %p" , (void *) obj)); |
| 52063 | duk_push_hobject(thr, obj); |
| 52064 | /* XXX: disable error handlers for duration of compaction? */ |
| 52065 | duk_safe_call(thr, duk__protected_compact_object, NULL, 1, 0); |
| 52066 | |
| 52067 | #if defined(DUK_USE_DEBUG) |
| 52068 | new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), |
| 52069 | DUK_HOBJECT_GET_ASIZE(obj), |
| 52070 | DUK_HOBJECT_GET_HSIZE(obj)); |
| 52071 | #endif |
| 52072 | |
| 52073 | #if defined(DUK_USE_DEBUG) |
| 52074 | (*p_count_compact)++; |
| 52075 | (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size); |
| 52076 | #endif |
| 52077 | |
| 52078 | next: |
| 52079 | curr = DUK_HEAPHDR_GET_NEXT(heap, curr); |
| 52080 | #if defined(DUK_USE_DEBUG) |
| 52081 | (*p_count_check)++; |
| 52082 | #endif |
| 52083 | } |
| 52084 | } |
| 52085 | |
| 52086 | DUK_LOCAL void duk__compact_objects(duk_heap *heap) { |
| 52087 | /* XXX: which lists should participate? to be finalized? */ |
| 52088 | #if defined(DUK_USE_DEBUG) |
| 52089 | duk_size_t count_check = 0; |
| 52090 | duk_size_t count_compact = 0; |
| 52091 | duk_size_t count_bytes_saved = 0; |
| 52092 | #endif |
| 52093 | |
| 52094 | DUK_DD(DUK_DDPRINT("duk__compact_objects: %p" , (void *) heap)); |
| 52095 | |
| 52096 | DUK_ASSERT(heap->heap_thread != NULL); |
| 52097 | |
| 52098 | #if defined(DUK_USE_DEBUG) |
| 52099 | duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved); |
| 52100 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52101 | duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved); |
| 52102 | #endif |
| 52103 | #else |
| 52104 | duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated); |
| 52105 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52106 | duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list); |
| 52107 | #endif |
| 52108 | #endif |
| 52109 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52110 | DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ |
| 52111 | #endif |
| 52112 | |
| 52113 | #if defined(DUK_USE_DEBUG) |
| 52114 | DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction" , |
| 52115 | (long) count_check, (long) count_compact, (long) count_bytes_saved)); |
| 52116 | #endif |
| 52117 | } |
| 52118 | |
| 52119 | /* |
| 52120 | * Assertion helpers. |
| 52121 | */ |
| 52122 | |
| 52123 | #if defined(DUK_USE_ASSERTIONS) |
| 52124 | typedef void (*duk__gc_heaphdr_assert)(duk_heap *heap, duk_heaphdr *h); |
| 52125 | typedef void (*duk__gc_hstring_assert)(duk_heap *heap, duk_hstring *h); |
| 52126 | |
| 52127 | DUK_LOCAL void duk__assert_walk_list(duk_heap *heap, duk_heaphdr *start, duk__gc_heaphdr_assert func) { |
| 52128 | duk_heaphdr *curr; |
| 52129 | for (curr = start; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { |
| 52130 | func(heap, curr); |
| 52131 | } |
| 52132 | } |
| 52133 | |
| 52134 | DUK_LOCAL void duk__assert_walk_strtable(duk_heap *heap, duk__gc_hstring_assert func) { |
| 52135 | duk_uint32_t i; |
| 52136 | |
| 52137 | for (i = 0; i < heap->st_size; i++) { |
| 52138 | duk_hstring *h; |
| 52139 | |
| 52140 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 52141 | h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]); |
| 52142 | #else |
| 52143 | h = heap->strtable[i]; |
| 52144 | #endif |
| 52145 | while (h != NULL) { |
| 52146 | func(heap, h); |
| 52147 | h = h->hdr.h_next; |
| 52148 | } |
| 52149 | } |
| 52150 | } |
| 52151 | |
| 52152 | DUK_LOCAL void duk__assert_heaphdr_flags_cb(duk_heap *heap, duk_heaphdr *h) { |
| 52153 | DUK_UNREF(heap); |
| 52154 | DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(h)); |
| 52155 | DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(h)); |
| 52156 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h)); |
| 52157 | /* may have FINALIZED */ |
| 52158 | } |
| 52159 | DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) { |
| 52160 | duk__assert_walk_list(heap, heap->heap_allocated, duk__assert_heaphdr_flags_cb); |
| 52161 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52162 | DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ |
| 52163 | #endif |
| 52164 | /* XXX: Assertions for finalize_list? */ |
| 52165 | } |
| 52166 | |
| 52167 | DUK_LOCAL void duk__assert_validity_cb1(duk_heap *heap, duk_heaphdr *h) { |
| 52168 | DUK_UNREF(heap); |
| 52169 | DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT(h) || DUK_HEAPHDR_IS_BUFFER(h)); |
| 52170 | duk_heaphdr_assert_valid_subclassed(h); |
| 52171 | } |
| 52172 | DUK_LOCAL void duk__assert_validity_cb2(duk_heap *heap, duk_hstring *h) { |
| 52173 | DUK_UNREF(heap); |
| 52174 | DUK_ASSERT(DUK_HEAPHDR_IS_STRING((duk_heaphdr *) h)); |
| 52175 | duk_heaphdr_assert_valid_subclassed((duk_heaphdr *) h); |
| 52176 | } |
| 52177 | DUK_LOCAL void duk__assert_validity(duk_heap *heap) { |
| 52178 | duk__assert_walk_list(heap, heap->heap_allocated, duk__assert_validity_cb1); |
| 52179 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52180 | duk__assert_walk_list(heap, heap->finalize_list, duk__assert_validity_cb1); |
| 52181 | #endif |
| 52182 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52183 | duk__assert_walk_list(heap, heap->refzero_list, duk__assert_validity_cb1); |
| 52184 | #endif |
| 52185 | duk__assert_walk_strtable(heap, duk__assert_validity_cb2); |
| 52186 | } |
| 52187 | |
| 52188 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52189 | DUK_LOCAL void duk__assert_valid_refcounts_cb(duk_heap *heap, duk_heaphdr *h) { |
| 52190 | /* Cannot really assert much w.r.t. refcounts now. */ |
| 52191 | |
| 52192 | DUK_UNREF(heap); |
| 52193 | if (DUK_HEAPHDR_GET_REFCOUNT(h) == 0 && |
| 52194 | DUK_HEAPHDR_HAS_FINALIZED(h)) { |
| 52195 | /* An object may be in heap_allocated list with a zero |
| 52196 | * refcount if it has just been finalized and is waiting |
| 52197 | * to be collected by the next cycle. |
| 52198 | * (This doesn't currently happen however.) |
| 52199 | */ |
| 52200 | } else if (DUK_HEAPHDR_GET_REFCOUNT(h) == 0) { |
| 52201 | /* An object may be in heap_allocated list with a zero |
| 52202 | * refcount also if it is a temporary object created |
| 52203 | * during debugger paused state. It will get collected |
| 52204 | * by mark-and-sweep based on its reachability status |
| 52205 | * (presumably not reachable because refcount is 0). |
| 52206 | */ |
| 52207 | } |
| 52208 | DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); /* Unsigned. */ |
| 52209 | } |
| 52210 | DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) { |
| 52211 | duk__assert_walk_list(heap, heap->heap_allocated, duk__assert_valid_refcounts_cb); |
| 52212 | } |
| 52213 | |
| 52214 | DUK_LOCAL void duk__clear_assert_refcounts_cb1(duk_heap *heap, duk_heaphdr *h) { |
| 52215 | DUK_UNREF(heap); |
| 52216 | h->h_assert_refcount = 0; |
| 52217 | } |
| 52218 | DUK_LOCAL void duk__clear_assert_refcounts_cb2(duk_heap *heap, duk_hstring *h) { |
| 52219 | DUK_UNREF(heap); |
| 52220 | ((duk_heaphdr *) h)->h_assert_refcount = 0; |
| 52221 | } |
| 52222 | DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) { |
| 52223 | duk__assert_walk_list(heap, heap->heap_allocated, duk__clear_assert_refcounts_cb1); |
| 52224 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52225 | duk__assert_walk_list(heap, heap->finalize_list, duk__clear_assert_refcounts_cb1); |
| 52226 | #endif |
| 52227 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52228 | duk__assert_walk_list(heap, heap->refzero_list, duk__clear_assert_refcounts_cb1); |
| 52229 | #endif |
| 52230 | duk__assert_walk_strtable(heap, duk__clear_assert_refcounts_cb2); |
| 52231 | } |
| 52232 | |
| 52233 | DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) { |
| 52234 | duk_bool_t count_ok; |
| 52235 | duk_size_t expect_refc; |
| 52236 | |
| 52237 | /* The refcount check only makes sense for reachable objects on |
| 52238 | * heap_allocated or string table, after the sweep phase. Prior to |
| 52239 | * sweep phase refcounts will include references that are not visible |
| 52240 | * via reachability roots. |
| 52241 | * |
| 52242 | * Because we're called after the sweep phase, all heap objects on |
| 52243 | * heap_allocated are reachable. REACHABLE flags have already been |
| 52244 | * cleared so we can't check them. |
| 52245 | */ |
| 52246 | |
| 52247 | /* ROM objects have intentionally incorrect refcount (1), but we won't |
| 52248 | * check them. |
| 52249 | */ |
| 52250 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr)); |
| 52251 | |
| 52252 | expect_refc = hdr->h_assert_refcount; |
| 52253 | if (DUK_HEAPHDR_IS_STRING(hdr) && DUK_HSTRING_HAS_PINNED_LITERAL((duk_hstring *) hdr)) { |
| 52254 | expect_refc++; |
| 52255 | } |
| 52256 | count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == expect_refc); |
| 52257 | if (!count_ok) { |
| 52258 | DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO" , |
| 52259 | (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr), |
| 52260 | (long) hdr->h_assert_refcount, hdr)); |
| 52261 | DUK_ASSERT(0); |
| 52262 | } |
| 52263 | } |
| 52264 | |
| 52265 | DUK_LOCAL void duk__check_assert_refcounts_cb1(duk_heap *heap, duk_heaphdr *h) { |
| 52266 | DUK_UNREF(heap); |
| 52267 | duk__check_refcount_heaphdr(h); |
| 52268 | } |
| 52269 | DUK_LOCAL void duk__check_assert_refcounts_cb2(duk_heap *heap, duk_hstring *h) { |
| 52270 | DUK_UNREF(heap); |
| 52271 | duk__check_refcount_heaphdr((duk_heaphdr *) h); |
| 52272 | } |
| 52273 | DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) { |
| 52274 | duk__assert_walk_list(heap, heap->heap_allocated, duk__check_assert_refcounts_cb1); |
| 52275 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52276 | duk__assert_walk_list(heap, heap->finalize_list, duk__check_assert_refcounts_cb1); |
| 52277 | #endif |
| 52278 | /* XXX: Assert anything for refzero_list? */ |
| 52279 | duk__assert_walk_strtable(heap, duk__check_assert_refcounts_cb2); |
| 52280 | } |
| 52281 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 52282 | |
| 52283 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 52284 | DUK_LOCAL void duk__assert_litcache_nulls(duk_heap *heap) { |
| 52285 | duk_uint_t i; |
| 52286 | duk_litcache_entry *e; |
| 52287 | |
| 52288 | e = heap->litcache; |
| 52289 | for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) { |
| 52290 | /* Entry addresses were NULLed before mark-and-sweep, check |
| 52291 | * that they're still NULL afterwards to ensure no pointers |
| 52292 | * were recorded through any side effects. |
| 52293 | */ |
| 52294 | DUK_ASSERT(e->addr == NULL); |
| 52295 | } |
| 52296 | } |
| 52297 | #endif /* DUK_USE_LITCACHE_SIZE */ |
| 52298 | #endif /* DUK_USE_ASSERTIONS */ |
| 52299 | |
| 52300 | /* |
| 52301 | * Stats dump. |
| 52302 | */ |
| 52303 | |
| 52304 | #if defined(DUK_USE_DEBUG) |
| 52305 | DUK_LOCAL void duk__dump_stats(duk_heap *heap) { |
| 52306 | DUK_D(DUK_DPRINT("stats executor: opcodes=%ld, interrupt=%ld, throw=%ld" , |
| 52307 | (long) heap->stats_exec_opcodes, (long) heap->stats_exec_interrupt, |
| 52308 | (long) heap->stats_exec_throw)); |
| 52309 | DUK_D(DUK_DPRINT("stats call: all=%ld, tailcall=%ld, ecmatoecma=%ld" , |
| 52310 | (long) heap->stats_call_all, (long) heap->stats_call_tailcall, |
| 52311 | (long) heap->stats_call_ecmatoecma)); |
| 52312 | DUK_D(DUK_DPRINT("stats safecall: all=%ld, nothrow=%ld, throw=%ld" , |
| 52313 | (long) heap->stats_safecall_all, (long) heap->stats_safecall_nothrow, |
| 52314 | (long) heap->stats_safecall_throw)); |
| 52315 | DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld" , |
| 52316 | (long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count, |
| 52317 | (long) heap->stats_ms_emergency_count)); |
| 52318 | DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, " |
| 52319 | "resize_check=%ld, resize_grow=%ld, resize_shrink=%ld, " |
| 52320 | "litcache_hit=%ld, litcache_miss=%ld, litcache_pin=%ld" , |
| 52321 | (long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss, |
| 52322 | (long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow, |
| 52323 | (long) heap->stats_strtab_resize_shrink, (long) heap->stats_strtab_litcache_hit, |
| 52324 | (long) heap->stats_strtab_litcache_miss, (long) heap->stats_strtab_litcache_pin)); |
| 52325 | DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld" , |
| 52326 | (long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array)); |
| 52327 | DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld" , |
| 52328 | (long) heap->stats_getownpropdesc_count, (long) heap->stats_getownpropdesc_hit, |
| 52329 | (long) heap->stats_getownpropdesc_miss)); |
| 52330 | DUK_D(DUK_DPRINT("stats getpropdesc: count=%ld, hit=%ld, miss=%ld" , |
| 52331 | (long) heap->stats_getpropdesc_count, (long) heap->stats_getpropdesc_hit, |
| 52332 | (long) heap->stats_getpropdesc_miss)); |
| 52333 | DUK_D(DUK_DPRINT("stats getprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, " |
| 52334 | "bufferidx=%ld, bufferlen=%ld, stringidx=%ld, stringlen=%ld, " |
| 52335 | "proxy=%ld, arguments=%ld" , |
| 52336 | (long) heap->stats_getprop_all, (long) heap->stats_getprop_arrayidx, |
| 52337 | (long) heap->stats_getprop_bufobjidx, (long) heap->stats_getprop_bufferidx, |
| 52338 | (long) heap->stats_getprop_bufferlen, (long) heap->stats_getprop_stringidx, |
| 52339 | (long) heap->stats_getprop_stringlen, (long) heap->stats_getprop_proxy, |
| 52340 | (long) heap->stats_getprop_arguments)); |
| 52341 | DUK_D(DUK_DPRINT("stats putprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, " |
| 52342 | "bufferidx=%ld, proxy=%ld" , |
| 52343 | (long) heap->stats_putprop_all, (long) heap->stats_putprop_arrayidx, |
| 52344 | (long) heap->stats_putprop_bufobjidx, (long) heap->stats_putprop_bufferidx, |
| 52345 | (long) heap->stats_putprop_proxy)); |
| 52346 | DUK_D(DUK_DPRINT("stats getvar: all=%ld" , |
| 52347 | (long) heap->stats_getvar_all)); |
| 52348 | DUK_D(DUK_DPRINT("stats putvar: all=%ld" , |
| 52349 | (long) heap->stats_putvar_all)); |
| 52350 | DUK_D(DUK_DPRINT("stats envrec: delayedcreate=%ld, create=%ld, newenv=%ld, oldenv=%ld, pushclosure=%ld" , |
| 52351 | (long) heap->stats_envrec_delayedcreate, |
| 52352 | (long) heap->stats_envrec_create, |
| 52353 | (long) heap->stats_envrec_newenv, |
| 52354 | (long) heap->stats_envrec_oldenv, |
| 52355 | (long) heap->stats_envrec_pushclosure)); |
| 52356 | } |
| 52357 | #endif /* DUK_USE_DEBUG */ |
| 52358 | |
| 52359 | /* |
| 52360 | * Main mark-and-sweep function. |
| 52361 | * |
| 52362 | * 'flags' represents the features requested by the caller. The current |
| 52363 | * heap->ms_base_flags is ORed automatically into the flags; the base flags |
| 52364 | * mask typically prevents certain mark-and-sweep operation to avoid trouble. |
| 52365 | */ |
| 52366 | |
| 52367 | DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) { |
| 52368 | duk_size_t count_keep_obj; |
| 52369 | duk_size_t count_keep_str; |
| 52370 | #if defined(DUK_USE_VOLUNTARY_GC) |
| 52371 | duk_size_t tmp; |
| 52372 | #endif |
| 52373 | duk_bool_t entry_creating_error; |
| 52374 | |
| 52375 | DUK_STATS_INC(heap, stats_ms_try_count); |
| 52376 | #if defined(DUK_USE_DEBUG) |
| 52377 | if (flags & DUK_MS_FLAG_EMERGENCY) { |
| 52378 | DUK_STATS_INC(heap, stats_ms_emergency_count); |
| 52379 | } |
| 52380 | #endif |
| 52381 | |
| 52382 | /* If debugger is paused, garbage collection is disabled by default. |
| 52383 | * This is achieved by bumping ms_prevent_count when becoming paused. |
| 52384 | */ |
| 52385 | DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0); |
| 52386 | |
| 52387 | /* Prevention/recursion check as soon as possible because we may |
| 52388 | * be called a number of times when voluntary mark-and-sweep is |
| 52389 | * pending. |
| 52390 | */ |
| 52391 | if (heap->ms_prevent_count != 0) { |
| 52392 | DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep" )); |
| 52393 | DUK_STATS_INC(heap, stats_ms_skip_count); |
| 52394 | return; |
| 52395 | } |
| 52396 | DUK_ASSERT(heap->ms_running == 0); /* ms_prevent_count is bumped when ms_running is set */ |
| 52397 | |
| 52398 | /* Heap_thread is used during mark-and-sweep for refcount finalization |
| 52399 | * (it's also used for finalizer execution once mark-and-sweep is |
| 52400 | * complete). Heap allocation code ensures heap_thread is set and |
| 52401 | * properly initialized before setting ms_prevent_count to 0. |
| 52402 | */ |
| 52403 | DUK_ASSERT(heap->heap_thread != NULL); |
| 52404 | DUK_ASSERT(heap->heap_thread->valstack != NULL); |
| 52405 | |
| 52406 | DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx" , |
| 52407 | (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags))); |
| 52408 | |
| 52409 | flags |= heap->ms_base_flags; |
| 52410 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52411 | if (heap->finalize_list != NULL) { |
| 52412 | flags |= DUK_MS_FLAG_POSTPONE_RESCUE; |
| 52413 | } |
| 52414 | #endif |
| 52415 | |
| 52416 | /* |
| 52417 | * Assertions before |
| 52418 | */ |
| 52419 | |
| 52420 | #if defined(DUK_USE_ASSERTIONS) |
| 52421 | DUK_ASSERT(heap->ms_prevent_count == 0); |
| 52422 | DUK_ASSERT(heap->ms_running == 0); |
| 52423 | DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap)); |
| 52424 | DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); |
| 52425 | DUK_ASSERT(heap->ms_recursion_depth == 0); |
| 52426 | duk__assert_heaphdr_flags(heap); |
| 52427 | duk__assert_validity(heap); |
| 52428 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52429 | /* Note: heap->refzero_free_running may be true; a refcount |
| 52430 | * finalizer may trigger a mark-and-sweep. |
| 52431 | */ |
| 52432 | duk__assert_valid_refcounts(heap); |
| 52433 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 52434 | #endif /* DUK_USE_ASSERTIONS */ |
| 52435 | |
| 52436 | /* |
| 52437 | * Begin |
| 52438 | */ |
| 52439 | |
| 52440 | DUK_ASSERT(heap->ms_prevent_count == 0); |
| 52441 | DUK_ASSERT(heap->ms_running == 0); |
| 52442 | heap->ms_prevent_count = 1; |
| 52443 | heap->ms_running = 1; |
| 52444 | entry_creating_error = heap->creating_error; |
| 52445 | heap->creating_error = 0; |
| 52446 | |
| 52447 | /* |
| 52448 | * Free activation/catcher freelists on every mark-and-sweep for now. |
| 52449 | * This is an initial rough draft; ideally we'd keep count of the |
| 52450 | * freelist size and free only excess entries. |
| 52451 | */ |
| 52452 | |
| 52453 | DUK_D(DUK_DPRINT("freeing temporary freelists" )); |
| 52454 | duk_heap_free_freelists(heap); |
| 52455 | |
| 52456 | /* |
| 52457 | * Mark roots, hoping that recursion limit is not normally hit. |
| 52458 | * If recursion limit is hit, run additional reachability rounds |
| 52459 | * starting from "temproots" until marking is complete. |
| 52460 | * |
| 52461 | * Marking happens in two phases: first we mark actual reachability |
| 52462 | * roots (and run "temproots" to complete the process). Then we |
| 52463 | * check which objects are unreachable and are finalizable; such |
| 52464 | * objects are marked as FINALIZABLE and marked as reachability |
| 52465 | * (and "temproots" is run again to complete the process). |
| 52466 | * |
| 52467 | * The heap finalize_list must also be marked as a reachability root. |
| 52468 | * There may be objects on the list from a previous round if the |
| 52469 | * previous run had finalizer skip flag. |
| 52470 | */ |
| 52471 | |
| 52472 | #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) |
| 52473 | duk__clear_assert_refcounts(heap); |
| 52474 | #endif |
| 52475 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 52476 | duk__wipe_litcache(heap); |
| 52477 | #endif |
| 52478 | duk__mark_roots_heap(heap); /* Mark main reachability roots. */ |
| 52479 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52480 | DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ |
| 52481 | #endif |
| 52482 | duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ |
| 52483 | |
| 52484 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52485 | duk__mark_finalizable(heap); /* Mark finalizable as reachability roots. */ |
| 52486 | duk__mark_finalize_list(heap); /* Mark finalizer work list as reachability roots. */ |
| 52487 | #endif |
| 52488 | duk__mark_temproots_by_heap_scan(heap); /* Temproots. */ |
| 52489 | |
| 52490 | /* |
| 52491 | * Sweep garbage and remove marking flags, and move objects with |
| 52492 | * finalizers to the finalizer work list. |
| 52493 | * |
| 52494 | * Objects to be swept need to get their refcounts finalized before |
| 52495 | * they are swept. In other words, their target object refcounts |
| 52496 | * need to be decreased. This has to be done before freeing any |
| 52497 | * objects to avoid decref'ing dangling pointers (which may happen |
| 52498 | * even without bugs, e.g. with reference loops) |
| 52499 | * |
| 52500 | * Because strings don't point to other heap objects, similar |
| 52501 | * finalization is not necessary for strings. |
| 52502 | */ |
| 52503 | |
| 52504 | /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */ |
| 52505 | |
| 52506 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52507 | duk__finalize_refcounts(heap); |
| 52508 | #endif |
| 52509 | duk__sweep_heap(heap, flags, &count_keep_obj); |
| 52510 | duk__sweep_stringtable(heap, &count_keep_str); |
| 52511 | #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING) |
| 52512 | duk__check_assert_refcounts(heap); |
| 52513 | #endif |
| 52514 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52515 | DUK_ASSERT(heap->refzero_list == NULL); /* Always handled to completion inline in DECREF. */ |
| 52516 | #endif |
| 52517 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52518 | duk__clear_finalize_list_flags(heap); |
| 52519 | #endif |
| 52520 | |
| 52521 | /* |
| 52522 | * Object compaction (emergency only). |
| 52523 | * |
| 52524 | * Object compaction is a separate step after sweeping, as there is |
| 52525 | * more free memory for it to work with. Also, currently compaction |
| 52526 | * may insert new objects into the heap allocated list and the string |
| 52527 | * table which we don't want to do during a sweep (the reachability |
| 52528 | * flags of such objects would be incorrect). The objects inserted |
| 52529 | * are currently: |
| 52530 | * |
| 52531 | * - a temporary duk_hbuffer for a new properties allocation |
| 52532 | * - if array part is abandoned, string keys are interned |
| 52533 | * |
| 52534 | * The object insertions go to the front of the list, so they do not |
| 52535 | * cause an infinite loop (they are not compacted). |
| 52536 | * |
| 52537 | * At present compaction is not allowed when mark-and-sweep runs |
| 52538 | * during error handling because it involves a duk_safe_call() |
| 52539 | * interfering with error state. |
| 52540 | */ |
| 52541 | |
| 52542 | if ((flags & DUK_MS_FLAG_EMERGENCY) && |
| 52543 | !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) { |
| 52544 | if (heap->lj.type != DUK_LJ_TYPE_UNKNOWN) { |
| 52545 | DUK_D(DUK_DPRINT("lj.type (%ld) not DUK_LJ_TYPE_UNKNOWN, skip object compaction" , (long) heap->lj.type)); |
| 52546 | } else { |
| 52547 | DUK_D(DUK_DPRINT("object compaction" )); |
| 52548 | duk__compact_objects(heap); |
| 52549 | } |
| 52550 | } |
| 52551 | |
| 52552 | /* |
| 52553 | * String table resize check. |
| 52554 | * |
| 52555 | * This is mainly useful in emergency GC: if the string table load |
| 52556 | * factor is really low for some reason, we can shrink the string |
| 52557 | * table to a smaller size and free some memory in the process. |
| 52558 | * Only execute in emergency GC. String table has internal flags |
| 52559 | * to protect against recursive resizing if this mark-and-sweep pass |
| 52560 | * was triggered by a string table resize. |
| 52561 | */ |
| 52562 | |
| 52563 | if (flags & DUK_MS_FLAG_EMERGENCY) { |
| 52564 | DUK_D(DUK_DPRINT("stringtable resize check in emergency gc" )); |
| 52565 | duk_heap_strtable_force_resize(heap); |
| 52566 | } |
| 52567 | |
| 52568 | /* |
| 52569 | * Finish |
| 52570 | */ |
| 52571 | |
| 52572 | DUK_ASSERT(heap->ms_prevent_count == 1); |
| 52573 | DUK_ASSERT(heap->ms_running == 1); |
| 52574 | heap->ms_prevent_count = 0; |
| 52575 | heap->ms_running = 0; |
| 52576 | heap->creating_error = entry_creating_error; /* for nested error handling, see GH-2278 */ |
| 52577 | |
| 52578 | /* |
| 52579 | * Assertions after |
| 52580 | */ |
| 52581 | |
| 52582 | #if defined(DUK_USE_ASSERTIONS) |
| 52583 | DUK_ASSERT(heap->ms_prevent_count == 0); |
| 52584 | DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)); |
| 52585 | DUK_ASSERT(heap->ms_recursion_depth == 0); |
| 52586 | duk__assert_heaphdr_flags(heap); |
| 52587 | duk__assert_validity(heap); |
| 52588 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 52589 | /* Note: heap->refzero_free_running may be true; a refcount |
| 52590 | * finalizer may trigger a mark-and-sweep. |
| 52591 | */ |
| 52592 | duk__assert_valid_refcounts(heap); |
| 52593 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 52594 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 52595 | duk__assert_litcache_nulls(heap); |
| 52596 | #endif /* DUK_USE_LITCACHE_SIZE */ |
| 52597 | #endif /* DUK_USE_ASSERTIONS */ |
| 52598 | |
| 52599 | /* |
| 52600 | * Reset trigger counter |
| 52601 | */ |
| 52602 | |
| 52603 | #if defined(DUK_USE_VOLUNTARY_GC) |
| 52604 | tmp = (count_keep_obj + count_keep_str) / 256; |
| 52605 | heap->ms_trigger_counter = (duk_int_t) ( |
| 52606 | (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) + |
| 52607 | DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD); |
| 52608 | DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld" , |
| 52609 | (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter)); |
| 52610 | #else |
| 52611 | DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger" , |
| 52612 | (long) count_keep_obj, (long) count_keep_str)); |
| 52613 | #endif |
| 52614 | |
| 52615 | /* |
| 52616 | * Stats dump |
| 52617 | */ |
| 52618 | |
| 52619 | #if defined(DUK_USE_DEBUG) |
| 52620 | duk__dump_stats(heap); |
| 52621 | #endif |
| 52622 | |
| 52623 | /* |
| 52624 | * Finalize objects in the finalization work list. Finalized |
| 52625 | * objects are queued back to heap_allocated with FINALIZED set. |
| 52626 | * |
| 52627 | * Since finalizers may cause arbitrary side effects, they are |
| 52628 | * prevented e.g. during string table and object property allocation |
| 52629 | * resizing using heap->pf_prevent_count. In this case the objects |
| 52630 | * remain in the finalization work list after mark-and-sweep exits |
| 52631 | * and they may be finalized on the next pass or any DECREF checking |
| 52632 | * for finalize_list. |
| 52633 | * |
| 52634 | * As of Duktape 2.1 finalization happens outside mark-and-sweep |
| 52635 | * protection. Mark-and-sweep is allowed while the finalize_list |
| 52636 | * is being processed, but no rescue decisions are done while the |
| 52637 | * process is on-going. This avoids incorrect rescue decisions |
| 52638 | * if an object is considered reachable (and thus rescued) because |
| 52639 | * of a reference via finalize_list (which is considered a reachability |
| 52640 | * root). When finalize_list is being processed, reachable objects |
| 52641 | * with FINALIZED set will just keep their FINALIZED flag for later |
| 52642 | * mark-and-sweep processing. |
| 52643 | * |
| 52644 | * This could also be handled (a bit better) by having a more refined |
| 52645 | * notion of reachability for rescue/free decisions. |
| 52646 | * |
| 52647 | * XXX: avoid finalizer execution when doing emergency GC? |
| 52648 | */ |
| 52649 | |
| 52650 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 52651 | /* Attempt to process finalize_list, pf_prevent_count check |
| 52652 | * is inside the target. |
| 52653 | */ |
| 52654 | duk_heap_process_finalize_list(heap); |
| 52655 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 52656 | } |
| 52657 | #line 1 "duk_heap_memory.c" |
| 52658 | /* |
| 52659 | * Memory allocation handling. |
| 52660 | */ |
| 52661 | |
| 52662 | /* #include duk_internal.h -> already included */ |
| 52663 | |
| 52664 | /* |
| 52665 | * Allocate memory with garbage collection. |
| 52666 | */ |
| 52667 | |
| 52668 | /* Slow path: voluntary GC triggered, first alloc attempt failed, or zero size. */ |
| 52669 | DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_alloc_slowpath(duk_heap *heap, duk_size_t size) { |
| 52670 | void *res; |
| 52671 | duk_small_int_t i; |
| 52672 | |
| 52673 | DUK_ASSERT(heap != NULL); |
| 52674 | DUK_ASSERT(heap->alloc_func != NULL); |
| 52675 | DUK_ASSERT_DISABLE(size >= 0); |
| 52676 | |
| 52677 | if (size == 0) { |
| 52678 | DUK_D(DUK_DPRINT("zero size alloc in slow path, return NULL" )); |
| 52679 | return NULL; |
| 52680 | } |
| 52681 | |
| 52682 | DUK_D(DUK_DPRINT("first alloc attempt failed or voluntary GC limit reached, attempt to gc and retry" )); |
| 52683 | |
| 52684 | #if 0 |
| 52685 | /* |
| 52686 | * If GC is already running there is no point in attempting a GC |
| 52687 | * because it will be skipped. This could be checked for explicitly, |
| 52688 | * but it isn't actually needed: the loop below will eventually |
| 52689 | * fail resulting in a NULL. |
| 52690 | */ |
| 52691 | |
| 52692 | if (heap->ms_prevent_count != 0) { |
| 52693 | DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld" , (long) size)); |
| 52694 | return NULL; |
| 52695 | } |
| 52696 | #endif |
| 52697 | |
| 52698 | /* |
| 52699 | * Retry with several GC attempts. Initial attempts are made without |
| 52700 | * emergency mode; later attempts use emergency mode which minimizes |
| 52701 | * memory allocations forcibly. |
| 52702 | */ |
| 52703 | |
| 52704 | for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { |
| 52705 | duk_small_uint_t flags; |
| 52706 | |
| 52707 | flags = 0; |
| 52708 | if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { |
| 52709 | flags |= DUK_MS_FLAG_EMERGENCY; |
| 52710 | } |
| 52711 | |
| 52712 | duk_heap_mark_and_sweep(heap, flags); |
| 52713 | |
| 52714 | DUK_ASSERT(size > 0); |
| 52715 | res = heap->alloc_func(heap->heap_udata, size); |
| 52716 | if (res != NULL) { |
| 52717 | DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld" , |
| 52718 | (long) (i + 1), (long) size)); |
| 52719 | return res; |
| 52720 | } |
| 52721 | } |
| 52722 | |
| 52723 | DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld" , (long) size)); |
| 52724 | return NULL; |
| 52725 | } |
| 52726 | |
| 52727 | DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) { |
| 52728 | void *res; |
| 52729 | |
| 52730 | DUK_ASSERT(heap != NULL); |
| 52731 | DUK_ASSERT(heap->alloc_func != NULL); |
| 52732 | DUK_ASSERT_DISABLE(size >= 0); |
| 52733 | |
| 52734 | #if defined(DUK_USE_VOLUNTARY_GC) |
| 52735 | /* Voluntary periodic GC (if enabled). */ |
| 52736 | if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { |
| 52737 | goto slowpath; |
| 52738 | } |
| 52739 | #endif |
| 52740 | |
| 52741 | #if defined(DUK_USE_GC_TORTURE) |
| 52742 | /* Simulate alloc failure on every alloc, except when mark-and-sweep |
| 52743 | * is running. |
| 52744 | */ |
| 52745 | if (heap->ms_prevent_count == 0) { |
| 52746 | DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails" )); |
| 52747 | res = NULL; |
| 52748 | DUK_UNREF(res); |
| 52749 | goto slowpath; |
| 52750 | } |
| 52751 | #endif |
| 52752 | |
| 52753 | /* Zero-size allocation should happen very rarely (if at all), so |
| 52754 | * don't check zero size on NULL; handle it in the slow path |
| 52755 | * instead. This reduces size of inlined code. |
| 52756 | */ |
| 52757 | res = heap->alloc_func(heap->heap_udata, size); |
| 52758 | if (DUK_LIKELY(res != NULL)) { |
| 52759 | return res; |
| 52760 | } |
| 52761 | |
| 52762 | slowpath: |
| 52763 | |
| 52764 | if (size == 0) { |
| 52765 | DUK_D(DUK_DPRINT("first alloc attempt returned NULL for zero size alloc, use slow path to deal with it" )); |
| 52766 | } else { |
| 52767 | DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry" )); |
| 52768 | } |
| 52769 | return duk__heap_mem_alloc_slowpath(heap, size); |
| 52770 | } |
| 52771 | |
| 52772 | DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) { |
| 52773 | void *res; |
| 52774 | |
| 52775 | DUK_ASSERT(heap != NULL); |
| 52776 | DUK_ASSERT(heap->alloc_func != NULL); |
| 52777 | DUK_ASSERT_DISABLE(size >= 0); |
| 52778 | |
| 52779 | res = DUK_ALLOC(heap, size); |
| 52780 | if (DUK_LIKELY(res != NULL)) { |
| 52781 | duk_memzero(res, size); |
| 52782 | } |
| 52783 | return res; |
| 52784 | } |
| 52785 | |
| 52786 | DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) { |
| 52787 | void *res; |
| 52788 | |
| 52789 | DUK_ASSERT(thr != NULL); |
| 52790 | DUK_ASSERT(thr->heap != NULL); |
| 52791 | DUK_ASSERT(thr->heap->alloc_func != NULL); |
| 52792 | |
| 52793 | res = duk_heap_mem_alloc(thr->heap, size); |
| 52794 | if (DUK_LIKELY(res != NULL)) { |
| 52795 | return res; |
| 52796 | } else if (size == 0) { |
| 52797 | DUK_ASSERT(res == NULL); |
| 52798 | return res; |
| 52799 | } |
| 52800 | DUK_ERROR_ALLOC_FAILED(thr); |
| 52801 | DUK_WO_NORETURN(return NULL;); |
| 52802 | } |
| 52803 | |
| 52804 | DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) { |
| 52805 | void *res; |
| 52806 | |
| 52807 | DUK_ASSERT(thr != NULL); |
| 52808 | DUK_ASSERT(thr->heap != NULL); |
| 52809 | DUK_ASSERT(thr->heap->alloc_func != NULL); |
| 52810 | |
| 52811 | res = duk_heap_mem_alloc(thr->heap, size); |
| 52812 | if (DUK_LIKELY(res != NULL)) { |
| 52813 | duk_memzero(res, size); |
| 52814 | return res; |
| 52815 | } else if (size == 0) { |
| 52816 | DUK_ASSERT(res == NULL); |
| 52817 | return res; |
| 52818 | } |
| 52819 | DUK_ERROR_ALLOC_FAILED(thr); |
| 52820 | DUK_WO_NORETURN(return NULL;); |
| 52821 | } |
| 52822 | |
| 52823 | /* |
| 52824 | * Reallocate memory with garbage collection. |
| 52825 | */ |
| 52826 | |
| 52827 | /* Slow path: voluntary GC triggered, first realloc attempt failed, or zero size. */ |
| 52828 | DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_realloc_slowpath(duk_heap *heap, void *ptr, duk_size_t newsize) { |
| 52829 | void *res; |
| 52830 | duk_small_int_t i; |
| 52831 | |
| 52832 | DUK_ASSERT(heap != NULL); |
| 52833 | DUK_ASSERT(heap->realloc_func != NULL); |
| 52834 | /* ptr may be NULL */ |
| 52835 | DUK_ASSERT_DISABLE(newsize >= 0); |
| 52836 | |
| 52837 | /* Newsize was 0 and realloc() returned NULL, this has the semantics |
| 52838 | * of free(oldptr), i.e. memory was successfully freed. |
| 52839 | */ |
| 52840 | if (newsize == 0) { |
| 52841 | DUK_D(DUK_DPRINT("zero size realloc in slow path, return NULL" )); |
| 52842 | return NULL; |
| 52843 | } |
| 52844 | |
| 52845 | DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry" )); |
| 52846 | |
| 52847 | #if 0 |
| 52848 | /* |
| 52849 | * Avoid a GC if GC is already running. See duk_heap_mem_alloc(). |
| 52850 | */ |
| 52851 | |
| 52852 | if (heap->ms_prevent_count != 0) { |
| 52853 | DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld" , (long) newsize)); |
| 52854 | return NULL; |
| 52855 | } |
| 52856 | #endif |
| 52857 | |
| 52858 | /* |
| 52859 | * Retry with several GC attempts. Initial attempts are made without |
| 52860 | * emergency mode; later attempts use emergency mode which minimizes |
| 52861 | * memory allocations forcibly. |
| 52862 | */ |
| 52863 | |
| 52864 | for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { |
| 52865 | duk_small_uint_t flags; |
| 52866 | |
| 52867 | flags = 0; |
| 52868 | if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { |
| 52869 | flags |= DUK_MS_FLAG_EMERGENCY; |
| 52870 | } |
| 52871 | |
| 52872 | duk_heap_mark_and_sweep(heap, flags); |
| 52873 | |
| 52874 | DUK_ASSERT(newsize > 0); |
| 52875 | res = heap->realloc_func(heap->heap_udata, ptr, newsize); |
| 52876 | if (res || newsize == 0) { |
| 52877 | DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld" , |
| 52878 | (long) (i + 1), (long) newsize)); |
| 52879 | return res; |
| 52880 | } |
| 52881 | } |
| 52882 | |
| 52883 | DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld" , (long) newsize)); |
| 52884 | return NULL; |
| 52885 | } |
| 52886 | |
| 52887 | DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) { |
| 52888 | void *res; |
| 52889 | |
| 52890 | DUK_ASSERT(heap != NULL); |
| 52891 | DUK_ASSERT(heap->realloc_func != NULL); |
| 52892 | /* ptr may be NULL */ |
| 52893 | DUK_ASSERT_DISABLE(newsize >= 0); |
| 52894 | |
| 52895 | #if defined(DUK_USE_VOLUNTARY_GC) |
| 52896 | /* Voluntary periodic GC (if enabled). */ |
| 52897 | if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { |
| 52898 | goto slowpath; |
| 52899 | } |
| 52900 | #endif |
| 52901 | |
| 52902 | #if defined(DUK_USE_GC_TORTURE) |
| 52903 | /* Simulate alloc failure on every realloc, except when mark-and-sweep |
| 52904 | * is running. |
| 52905 | */ |
| 52906 | if (heap->ms_prevent_count == 0) { |
| 52907 | DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails" )); |
| 52908 | res = NULL; |
| 52909 | DUK_UNREF(res); |
| 52910 | goto slowpath; |
| 52911 | } |
| 52912 | #endif |
| 52913 | |
| 52914 | res = heap->realloc_func(heap->heap_udata, ptr, newsize); |
| 52915 | if (DUK_LIKELY(res != NULL)) { |
| 52916 | return res; |
| 52917 | } |
| 52918 | |
| 52919 | slowpath: |
| 52920 | |
| 52921 | if (newsize == 0) { |
| 52922 | DUK_D(DUK_DPRINT("first realloc attempt returned NULL for zero size realloc, use slow path to deal with it" )); |
| 52923 | } else { |
| 52924 | DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry" )); |
| 52925 | } |
| 52926 | return duk__heap_mem_realloc_slowpath(heap, ptr, newsize); |
| 52927 | } |
| 52928 | |
| 52929 | /* |
| 52930 | * Reallocate memory with garbage collection, using a callback to provide |
| 52931 | * the current allocated pointer. This variant is used when a mark-and-sweep |
| 52932 | * (e.g. finalizers) might change the original pointer. |
| 52933 | */ |
| 52934 | |
| 52935 | /* Slow path: voluntary GC triggered, first realloc attempt failed, or zero size. */ |
| 52936 | DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_realloc_indirect_slowpath(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { |
| 52937 | void *res; |
| 52938 | duk_small_int_t i; |
| 52939 | |
| 52940 | DUK_ASSERT(heap != NULL); |
| 52941 | DUK_ASSERT(heap->realloc_func != NULL); |
| 52942 | DUK_ASSERT_DISABLE(newsize >= 0); |
| 52943 | |
| 52944 | if (newsize == 0) { |
| 52945 | DUK_D(DUK_DPRINT("zero size indirect realloc in slow path, return NULL" )); |
| 52946 | return NULL; |
| 52947 | } |
| 52948 | |
| 52949 | DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry" )); |
| 52950 | |
| 52951 | #if 0 |
| 52952 | /* |
| 52953 | * Avoid a GC if GC is already running. See duk_heap_mem_alloc(). |
| 52954 | */ |
| 52955 | |
| 52956 | if (heap->ms_prevent_count != 0) { |
| 52957 | DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld" , (long) newsize)); |
| 52958 | return NULL; |
| 52959 | } |
| 52960 | #endif |
| 52961 | |
| 52962 | /* |
| 52963 | * Retry with several GC attempts. Initial attempts are made without |
| 52964 | * emergency mode; later attempts use emergency mode which minimizes |
| 52965 | * memory allocations forcibly. |
| 52966 | */ |
| 52967 | |
| 52968 | for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) { |
| 52969 | duk_small_uint_t flags; |
| 52970 | |
| 52971 | #if defined(DUK_USE_DEBUG) |
| 52972 | void *ptr_pre; |
| 52973 | void *ptr_post; |
| 52974 | #endif |
| 52975 | |
| 52976 | #if defined(DUK_USE_DEBUG) |
| 52977 | ptr_pre = cb(heap, ud); |
| 52978 | #endif |
| 52979 | flags = 0; |
| 52980 | if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) { |
| 52981 | flags |= DUK_MS_FLAG_EMERGENCY; |
| 52982 | } |
| 52983 | |
| 52984 | duk_heap_mark_and_sweep(heap, flags); |
| 52985 | #if defined(DUK_USE_DEBUG) |
| 52986 | ptr_post = cb(heap, ud); |
| 52987 | if (ptr_pre != ptr_post) { |
| 52988 | DUK_DD(DUK_DDPRINT("realloc base pointer changed by mark-and-sweep: %p -> %p" , |
| 52989 | (void *) ptr_pre, (void *) ptr_post)); |
| 52990 | } |
| 52991 | #endif |
| 52992 | |
| 52993 | /* Note: key issue here is to re-lookup the base pointer on every attempt. |
| 52994 | * The pointer being reallocated may change after every mark-and-sweep. |
| 52995 | */ |
| 52996 | |
| 52997 | DUK_ASSERT(newsize > 0); |
| 52998 | res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); |
| 52999 | if (res || newsize == 0) { |
| 53000 | DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld" , |
| 53001 | (long) (i + 1), (long) newsize)); |
| 53002 | return res; |
| 53003 | } |
| 53004 | } |
| 53005 | |
| 53006 | DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld" , (long) newsize)); |
| 53007 | return NULL; |
| 53008 | } |
| 53009 | |
| 53010 | DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) { |
| 53011 | void *res; |
| 53012 | |
| 53013 | DUK_ASSERT(heap != NULL); |
| 53014 | DUK_ASSERT(heap->realloc_func != NULL); |
| 53015 | DUK_ASSERT_DISABLE(newsize >= 0); |
| 53016 | |
| 53017 | #if defined(DUK_USE_VOLUNTARY_GC) |
| 53018 | /* Voluntary periodic GC (if enabled). */ |
| 53019 | if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) { |
| 53020 | goto slowpath; |
| 53021 | } |
| 53022 | #endif |
| 53023 | |
| 53024 | #if defined(DUK_USE_GC_TORTURE) |
| 53025 | /* Simulate alloc failure on every realloc, except when mark-and-sweep |
| 53026 | * is running. |
| 53027 | */ |
| 53028 | if (heap->ms_prevent_count == 0) { |
| 53029 | DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails" )); |
| 53030 | res = NULL; |
| 53031 | DUK_UNREF(res); |
| 53032 | goto slowpath; |
| 53033 | } |
| 53034 | #endif |
| 53035 | |
| 53036 | res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize); |
| 53037 | if (DUK_LIKELY(res != NULL)) { |
| 53038 | return res; |
| 53039 | } |
| 53040 | |
| 53041 | slowpath: |
| 53042 | |
| 53043 | if (newsize == 0) { |
| 53044 | DUK_D(DUK_DPRINT("first indirect realloc attempt returned NULL for zero size realloc, use slow path to deal with it" )); |
| 53045 | } else { |
| 53046 | DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry" )); |
| 53047 | } |
| 53048 | return duk__heap_mem_realloc_indirect_slowpath(heap, cb, ud, newsize); |
| 53049 | } |
| 53050 | |
| 53051 | /* |
| 53052 | * Free memory |
| 53053 | */ |
| 53054 | |
| 53055 | DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void duk_heap_mem_free(duk_heap *heap, void *ptr) { |
| 53056 | DUK_ASSERT(heap != NULL); |
| 53057 | DUK_ASSERT(heap->free_func != NULL); |
| 53058 | /* ptr may be NULL */ |
| 53059 | |
| 53060 | /* Must behave like a no-op with NULL and any pointer returned from |
| 53061 | * malloc/realloc with zero size. |
| 53062 | */ |
| 53063 | heap->free_func(heap->heap_udata, ptr); |
| 53064 | |
| 53065 | /* Never perform a GC (even voluntary) in a memory free, otherwise |
| 53066 | * all call sites doing frees would need to deal with the side effects. |
| 53067 | * No need to update voluntary GC counter either. |
| 53068 | */ |
| 53069 | } |
| 53070 | #line 1 "duk_heap_misc.c" |
| 53071 | /* |
| 53072 | * Support functions for duk_heap. |
| 53073 | */ |
| 53074 | |
| 53075 | /* #include duk_internal.h -> already included */ |
| 53076 | |
| 53077 | DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { |
| 53078 | duk_heaphdr *root; |
| 53079 | |
| 53080 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); |
| 53081 | |
| 53082 | root = heap->heap_allocated; |
| 53083 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 53084 | if (root != NULL) { |
| 53085 | DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL); |
| 53086 | DUK_HEAPHDR_SET_PREV(heap, root, hdr); |
| 53087 | } |
| 53088 | DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); |
| 53089 | #endif |
| 53090 | DUK_HEAPHDR_SET_NEXT(heap, hdr, root); |
| 53091 | DUK_HEAPHDR_ASSERT_LINKS(heap, hdr); |
| 53092 | DUK_HEAPHDR_ASSERT_LINKS(heap, root); |
| 53093 | heap->heap_allocated = hdr; |
| 53094 | } |
| 53095 | |
| 53096 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 53097 | DUK_INTERNAL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) { |
| 53098 | duk_heaphdr *prev; |
| 53099 | duk_heaphdr *next; |
| 53100 | |
| 53101 | /* Strings are in string table. */ |
| 53102 | DUK_ASSERT(hdr != NULL); |
| 53103 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING); |
| 53104 | |
| 53105 | /* Target 'hdr' must be in heap_allocated (not e.g. finalize_list). |
| 53106 | * If not, heap lists will become corrupted so assert early for it. |
| 53107 | */ |
| 53108 | #if defined(DUK_USE_ASSERTIONS) |
| 53109 | { |
| 53110 | duk_heaphdr *tmp; |
| 53111 | for (tmp = heap->heap_allocated; tmp != NULL; tmp = DUK_HEAPHDR_GET_NEXT(heap, tmp)) { |
| 53112 | if (tmp == hdr) { |
| 53113 | break; |
| 53114 | } |
| 53115 | } |
| 53116 | DUK_ASSERT(tmp == hdr); |
| 53117 | } |
| 53118 | #endif |
| 53119 | |
| 53120 | /* Read/write only once to minimize pointer compression calls. */ |
| 53121 | prev = DUK_HEAPHDR_GET_PREV(heap, hdr); |
| 53122 | next = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 53123 | |
| 53124 | if (prev != NULL) { |
| 53125 | DUK_ASSERT(heap->heap_allocated != hdr); |
| 53126 | DUK_HEAPHDR_SET_NEXT(heap, prev, next); |
| 53127 | } else { |
| 53128 | DUK_ASSERT(heap->heap_allocated == hdr); |
| 53129 | heap->heap_allocated = next; |
| 53130 | } |
| 53131 | if (next != NULL) { |
| 53132 | DUK_HEAPHDR_SET_PREV(heap, next, prev); |
| 53133 | } else { |
| 53134 | ; |
| 53135 | } |
| 53136 | } |
| 53137 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 53138 | |
| 53139 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 53140 | DUK_INTERNAL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr) { |
| 53141 | duk_heaphdr *root; |
| 53142 | |
| 53143 | root = heap->finalize_list; |
| 53144 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 53145 | DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); |
| 53146 | if (root != NULL) { |
| 53147 | DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL); |
| 53148 | DUK_HEAPHDR_SET_PREV(heap, root, hdr); |
| 53149 | } |
| 53150 | #endif |
| 53151 | DUK_HEAPHDR_SET_NEXT(heap, hdr, root); |
| 53152 | DUK_HEAPHDR_ASSERT_LINKS(heap, hdr); |
| 53153 | DUK_HEAPHDR_ASSERT_LINKS(heap, root); |
| 53154 | heap->finalize_list = hdr; |
| 53155 | } |
| 53156 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 53157 | |
| 53158 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 53159 | DUK_INTERNAL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr) { |
| 53160 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 53161 | duk_heaphdr *next; |
| 53162 | duk_heaphdr *prev; |
| 53163 | |
| 53164 | next = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 53165 | prev = DUK_HEAPHDR_GET_PREV(heap, hdr); |
| 53166 | if (next != NULL) { |
| 53167 | DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, next) == hdr); |
| 53168 | DUK_HEAPHDR_SET_PREV(heap, next, prev); |
| 53169 | } |
| 53170 | if (prev == NULL) { |
| 53171 | DUK_ASSERT(hdr == heap->finalize_list); |
| 53172 | heap->finalize_list = next; |
| 53173 | } else { |
| 53174 | DUK_ASSERT(hdr != heap->finalize_list); |
| 53175 | DUK_HEAPHDR_SET_NEXT(heap, prev, next); |
| 53176 | } |
| 53177 | #else |
| 53178 | duk_heaphdr *next; |
| 53179 | duk_heaphdr *curr; |
| 53180 | |
| 53181 | /* Random removal is expensive: we need to locate the previous element |
| 53182 | * because we don't have a 'prev' pointer. |
| 53183 | */ |
| 53184 | curr = heap->finalize_list; |
| 53185 | if (curr == hdr) { |
| 53186 | heap->finalize_list = DUK_HEAPHDR_GET_NEXT(heap, curr); |
| 53187 | } else { |
| 53188 | DUK_ASSERT(hdr != heap->finalize_list); |
| 53189 | for (;;) { |
| 53190 | DUK_ASSERT(curr != NULL); /* Caller responsibility. */ |
| 53191 | |
| 53192 | next = DUK_HEAPHDR_GET_NEXT(heap, curr); |
| 53193 | if (next == hdr) { |
| 53194 | next = DUK_HEAPHDR_GET_NEXT(heap, hdr); |
| 53195 | DUK_HEAPHDR_SET_NEXT(heap, curr, next); |
| 53196 | break; |
| 53197 | } |
| 53198 | } |
| 53199 | } |
| 53200 | #endif |
| 53201 | } |
| 53202 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 53203 | |
| 53204 | #if defined(DUK_USE_ASSERTIONS) |
| 53205 | DUK_INTERNAL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr) { |
| 53206 | duk_heaphdr *curr; |
| 53207 | DUK_ASSERT(heap != NULL); |
| 53208 | |
| 53209 | for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) { |
| 53210 | if (curr == ptr) { |
| 53211 | return 1; |
| 53212 | } |
| 53213 | } |
| 53214 | return 0; |
| 53215 | } |
| 53216 | #endif /* DUK_USE_ASSERTIONS */ |
| 53217 | |
| 53218 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 53219 | DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) { |
| 53220 | duk_hthread *curr_thr; |
| 53221 | |
| 53222 | DUK_ASSERT(heap != NULL); |
| 53223 | |
| 53224 | if (new_thr != NULL) { |
| 53225 | curr_thr = heap->curr_thread; |
| 53226 | if (curr_thr == NULL) { |
| 53227 | /* For initial entry use default value; zero forces an |
| 53228 | * interrupt before executing the first insturction. |
| 53229 | */ |
| 53230 | DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter" )); |
| 53231 | new_thr->interrupt_counter = 0; |
| 53232 | new_thr->interrupt_init = 0; |
| 53233 | } else { |
| 53234 | /* Copy interrupt counter/init value state to new thread (if any). |
| 53235 | * It's OK for new_thr to be the same as curr_thr. |
| 53236 | */ |
| 53237 | #if defined(DUK_USE_DEBUG) |
| 53238 | if (new_thr != curr_thr) { |
| 53239 | DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter" )); |
| 53240 | } |
| 53241 | #endif |
| 53242 | new_thr->interrupt_counter = curr_thr->interrupt_counter; |
| 53243 | new_thr->interrupt_init = curr_thr->interrupt_init; |
| 53244 | } |
| 53245 | } else { |
| 53246 | DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes" )); |
| 53247 | } |
| 53248 | |
| 53249 | heap->curr_thread = new_thr; /* may be NULL */ |
| 53250 | } |
| 53251 | #endif /* DUK_USE_INTERRUPT_COUNTER */ |
| 53252 | |
| 53253 | #if defined(DUK_USE_ASSERTIONS) |
| 53254 | DUK_INTERNAL void duk_heap_assert_valid(duk_heap *heap) { |
| 53255 | DUK_ASSERT(heap != NULL); |
| 53256 | } |
| 53257 | #endif |
| 53258 | #line 1 "duk_heap_refcount.c" |
| 53259 | /* |
| 53260 | * Reference counting implementation. |
| 53261 | * |
| 53262 | * INCREF/DECREF, finalization and freeing of objects whose refcount reaches |
| 53263 | * zero (refzero). These operations are very performance sensitive, so |
| 53264 | * various small tricks are used in an attempt to maximize speed. |
| 53265 | */ |
| 53266 | |
| 53267 | /* #include duk_internal.h -> already included */ |
| 53268 | |
| 53269 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 53270 | |
| 53271 | #if !defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 53272 | #error internal error, reference counting requires a double linked heap |
| 53273 | #endif |
| 53274 | |
| 53275 | /* |
| 53276 | * Heap object refcount finalization. |
| 53277 | * |
| 53278 | * When an object is about to be freed, all other objects it refers to must |
| 53279 | * be decref'd. Refcount finalization does NOT free the object or its inner |
| 53280 | * allocations (mark-and-sweep shares these helpers), it just manipulates |
| 53281 | * the refcounts. |
| 53282 | * |
| 53283 | * Note that any of the DECREFs may cause a refcount to drop to zero. If so, |
| 53284 | * the object won't be refzero processed inline, but will just be queued to |
| 53285 | * refzero_list and processed by an earlier caller working on refzero_list, |
| 53286 | * eliminating C recursion from even long refzero cascades. If refzero |
| 53287 | * finalization is triggered by mark-and-sweep, refzero conditions are ignored |
| 53288 | * (objects are not even queued to refzero_list) because mark-and-sweep deals |
| 53289 | * with them; refcounts are still updated so that they remain in sync with |
| 53290 | * actual references. |
| 53291 | */ |
| 53292 | |
| 53293 | DUK_LOCAL void duk__decref_tvals_norz(duk_hthread *thr, duk_tval *tv, duk_idx_t count) { |
| 53294 | DUK_ASSERT(count == 0 || tv != NULL); |
| 53295 | |
| 53296 | while (count-- > 0) { |
| 53297 | DUK_TVAL_DECREF_NORZ(thr, tv); |
| 53298 | tv++; |
| 53299 | } |
| 53300 | } |
| 53301 | |
| 53302 | DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h) { |
| 53303 | duk_hthread *thr; |
| 53304 | duk_uint_fast32_t i; |
| 53305 | duk_uint_fast32_t n; |
| 53306 | duk_propvalue *p_val; |
| 53307 | duk_tval *p_tv; |
| 53308 | duk_hstring **p_key; |
| 53309 | duk_uint8_t *p_flag; |
| 53310 | duk_hobject *h_proto; |
| 53311 | |
| 53312 | DUK_ASSERT(heap != NULL); |
| 53313 | DUK_ASSERT(heap->heap_thread != NULL); |
| 53314 | DUK_ASSERT(h); |
| 53315 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT); |
| 53316 | |
| 53317 | thr = heap->heap_thread; |
| 53318 | DUK_ASSERT(thr != NULL); |
| 53319 | |
| 53320 | p_key = DUK_HOBJECT_E_GET_KEY_BASE(heap, h); |
| 53321 | p_val = DUK_HOBJECT_E_GET_VALUE_BASE(heap, h); |
| 53322 | p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(heap, h); |
| 53323 | n = DUK_HOBJECT_GET_ENEXT(h); |
| 53324 | while (n-- > 0) { |
| 53325 | duk_hstring *key; |
| 53326 | |
| 53327 | key = p_key[n]; |
| 53328 | if (DUK_UNLIKELY(key == NULL)) { |
| 53329 | continue; |
| 53330 | } |
| 53331 | DUK_HSTRING_DECREF_NORZ(thr, key); |
| 53332 | if (DUK_UNLIKELY(p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR)) { |
| 53333 | duk_hobject *h_getset; |
| 53334 | h_getset = p_val[n].a.get; |
| 53335 | DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset)); |
| 53336 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset); |
| 53337 | h_getset = p_val[n].a.set; |
| 53338 | DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset)); |
| 53339 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset); |
| 53340 | } else { |
| 53341 | duk_tval *tv_val; |
| 53342 | tv_val = &p_val[n].v; |
| 53343 | DUK_TVAL_DECREF_NORZ(thr, tv_val); |
| 53344 | } |
| 53345 | } |
| 53346 | |
| 53347 | p_tv = DUK_HOBJECT_A_GET_BASE(heap, h); |
| 53348 | n = DUK_HOBJECT_GET_ASIZE(h); |
| 53349 | while (n-- > 0) { |
| 53350 | duk_tval *tv_val; |
| 53351 | tv_val = p_tv + n; |
| 53352 | DUK_TVAL_DECREF_NORZ(thr, tv_val); |
| 53353 | } |
| 53354 | |
| 53355 | /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */ |
| 53356 | |
| 53357 | h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(heap, h); |
| 53358 | DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto)); |
| 53359 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto); |
| 53360 | |
| 53361 | /* XXX: Object subclass tests are quite awkward at present, ideally |
| 53362 | * we should be able to switch-case here with a dense index (subtype |
| 53363 | * number or something). For now, fast path plain objects and arrays |
| 53364 | * and bit test the rest individually. |
| 53365 | */ |
| 53366 | |
| 53367 | if (DUK_HOBJECT_HAS_FASTREFS(h)) { |
| 53368 | /* Plain object or array, nothing more to do. While a |
| 53369 | * duk_harray has additional fields, none of them need |
| 53370 | * DECREF updates. |
| 53371 | */ |
| 53372 | DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h)); |
| 53373 | return; |
| 53374 | } |
| 53375 | DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h)); |
| 53376 | |
| 53377 | /* Slow path: special object, start bit checks from most likely. */ |
| 53378 | |
| 53379 | /* XXX: reorg, more common first */ |
| 53380 | if (DUK_HOBJECT_IS_COMPFUNC(h)) { |
| 53381 | duk_hcompfunc *f = (duk_hcompfunc *) h; |
| 53382 | duk_tval *tv, *tv_end; |
| 53383 | duk_hobject **funcs, **funcs_end; |
| 53384 | |
| 53385 | DUK_HCOMPFUNC_ASSERT_VALID(f); |
| 53386 | |
| 53387 | if (DUK_LIKELY(DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL)) { |
| 53388 | tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f); |
| 53389 | tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f); |
| 53390 | while (tv < tv_end) { |
| 53391 | DUK_TVAL_DECREF_NORZ(thr, tv); |
| 53392 | tv++; |
| 53393 | } |
| 53394 | |
| 53395 | funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f); |
| 53396 | funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f); |
| 53397 | while (funcs < funcs_end) { |
| 53398 | duk_hobject *h_func; |
| 53399 | h_func = *funcs; |
| 53400 | DUK_ASSERT(h_func != NULL); |
| 53401 | DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_func)); |
| 53402 | DUK_HCOMPFUNC_DECREF_NORZ(thr, (duk_hcompfunc *) h_func); |
| 53403 | funcs++; |
| 53404 | } |
| 53405 | } else { |
| 53406 | /* May happen in some out-of-memory corner cases. */ |
| 53407 | DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref" )); |
| 53408 | } |
| 53409 | |
| 53410 | DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f)); |
| 53411 | DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f)); |
| 53412 | DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(heap, f)); |
| 53413 | } else if (DUK_HOBJECT_IS_DECENV(h)) { |
| 53414 | duk_hdecenv *e = (duk_hdecenv *) h; |
| 53415 | DUK_HDECENV_ASSERT_VALID(e); |
| 53416 | DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, e->thread); |
| 53417 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, e->varmap); |
| 53418 | } else if (DUK_HOBJECT_IS_OBJENV(h)) { |
| 53419 | duk_hobjenv *e = (duk_hobjenv *) h; |
| 53420 | DUK_HOBJENV_ASSERT_VALID(e); |
| 53421 | DUK_ASSERT(e->target != NULL); /* Required for object environments. */ |
| 53422 | DUK_HOBJECT_DECREF_NORZ(thr, e->target); |
| 53423 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 53424 | } else if (DUK_HOBJECT_IS_BUFOBJ(h)) { |
| 53425 | duk_hbufobj *b = (duk_hbufobj *) h; |
| 53426 | DUK_HBUFOBJ_ASSERT_VALID(b); |
| 53427 | DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf); |
| 53428 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop); |
| 53429 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 53430 | } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) { |
| 53431 | duk_hboundfunc *f = (duk_hboundfunc *) (void *) h; |
| 53432 | DUK_HBOUNDFUNC_ASSERT_VALID(f); |
| 53433 | DUK_TVAL_DECREF_NORZ(thr, &f->target); |
| 53434 | DUK_TVAL_DECREF_NORZ(thr, &f->this_binding); |
| 53435 | duk__decref_tvals_norz(thr, f->args, f->nargs); |
| 53436 | #if defined(DUK_USE_ES6_PROXY) |
| 53437 | } else if (DUK_HOBJECT_IS_PROXY(h)) { |
| 53438 | duk_hproxy *p = (duk_hproxy *) h; |
| 53439 | DUK_HPROXY_ASSERT_VALID(p); |
| 53440 | DUK_HOBJECT_DECREF_NORZ(thr, p->target); |
| 53441 | DUK_HOBJECT_DECREF_NORZ(thr, p->handler); |
| 53442 | #endif /* DUK_USE_ES6_PROXY */ |
| 53443 | } else if (DUK_HOBJECT_IS_THREAD(h)) { |
| 53444 | duk_hthread *t = (duk_hthread *) h; |
| 53445 | duk_activation *act; |
| 53446 | duk_tval *tv; |
| 53447 | |
| 53448 | DUK_HTHREAD_ASSERT_VALID(t); |
| 53449 | |
| 53450 | tv = t->valstack; |
| 53451 | while (tv < t->valstack_top) { |
| 53452 | DUK_TVAL_DECREF_NORZ(thr, tv); |
| 53453 | tv++; |
| 53454 | } |
| 53455 | |
| 53456 | for (act = t->callstack_curr; act != NULL; act = act->parent) { |
| 53457 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act)); |
| 53458 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env); |
| 53459 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env); |
| 53460 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 53461 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller); |
| 53462 | #endif |
| 53463 | #if 0 /* nothing now */ |
| 53464 | for (cat = act->cat; cat != NULL; cat = cat->parent) { |
| 53465 | } |
| 53466 | #endif |
| 53467 | } |
| 53468 | |
| 53469 | |
| 53470 | for (i = 0; i < DUK_NUM_BUILTINS; i++) { |
| 53471 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]); |
| 53472 | } |
| 53473 | |
| 53474 | DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, (duk_hthread *) t->resumer); |
| 53475 | } else { |
| 53476 | /* We may come here if the object should have a FASTREFS flag |
| 53477 | * but it's missing for some reason. Assert for never getting |
| 53478 | * here; however, other than performance, this is harmless. |
| 53479 | */ |
| 53480 | DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO" , h)); |
| 53481 | DUK_ASSERT(0); |
| 53482 | } |
| 53483 | } |
| 53484 | |
| 53485 | DUK_INTERNAL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr) { |
| 53486 | DUK_ASSERT(heap != NULL); |
| 53487 | DUK_ASSERT(heap->heap_thread != NULL); |
| 53488 | DUK_ASSERT(hdr != NULL); |
| 53489 | |
| 53490 | if (DUK_HEAPHDR_IS_OBJECT(hdr)) { |
| 53491 | duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) hdr); |
| 53492 | } |
| 53493 | /* DUK_HTYPE_BUFFER: nothing to finalize */ |
| 53494 | /* DUK_HTYPE_STRING: nothing to finalize */ |
| 53495 | } |
| 53496 | |
| 53497 | /* |
| 53498 | * Refzero processing for duk_hobject: queue a refzero'ed object to either |
| 53499 | * finalize_list or refzero_list and process the relevent list(s) if |
| 53500 | * necessary. |
| 53501 | * |
| 53502 | * Refzero_list is single linked, with only 'prev' pointers set and valid. |
| 53503 | * All 'next' pointers are intentionally left as garbage. This doesn't |
| 53504 | * matter because refzero_list is processed to completion before any other |
| 53505 | * code (like mark-and-sweep) might walk the list. |
| 53506 | * |
| 53507 | * In more detail: |
| 53508 | * |
| 53509 | * - On first insert refzero_list is NULL and the new object becomes the |
| 53510 | * first and only element on the list; duk__refcount_free_pending() is |
| 53511 | * called and it starts processing the list from the initial element, |
| 53512 | * i.e. the list tail. |
| 53513 | * |
| 53514 | * - As each object is refcount finalized, new objects may be queued to |
| 53515 | * refzero_list head. Their 'next' pointers are left as garbage, but |
| 53516 | * 'prev' points are set correctly, with the element at refzero_list |
| 53517 | * having a NULL 'prev' pointer. The fact that refzero_list is non-NULL |
| 53518 | * is used to reject (1) recursive duk__refcount_free_pending() and |
| 53519 | * (2) finalize_list processing calls. |
| 53520 | * |
| 53521 | * - When we're done with the current object, read its 'prev' pointer and |
| 53522 | * free the object. If 'prev' is NULL, we've reached head of list and are |
| 53523 | * done: set refzero_list to NULL and process pending finalizers. Otherwise |
| 53524 | * continue processing the list. |
| 53525 | * |
| 53526 | * A refzero cascade is free of side effects because it only involves |
| 53527 | * queueing more objects and freeing memory; finalizer execution is blocked |
| 53528 | * in the code path queueing objects to finalize_list. As a result the |
| 53529 | * initial refzero call (which triggers duk__refcount_free_pending()) must |
| 53530 | * check finalize_list so that finalizers are executed snappily. |
| 53531 | * |
| 53532 | * If finalize_list processing starts first, refzero may occur while we're |
| 53533 | * processing finalizers. That's fine: that particular refzero cascade is |
| 53534 | * handled to completion without side effects. Once the cascade is complete, |
| 53535 | * we'll run pending finalizers but notice that we're already doing that and |
| 53536 | * return. |
| 53537 | * |
| 53538 | * This could be expanded to allow incremental freeing: just bail out |
| 53539 | * early and resume at a future alloc/decref/refzero. However, if that |
| 53540 | * were done, the list structure would need to be kept consistent at all |
| 53541 | * times, mark-and-sweep would need to handle refzero_list, etc. |
| 53542 | */ |
| 53543 | |
| 53544 | DUK_LOCAL void duk__refcount_free_pending(duk_heap *heap) { |
| 53545 | duk_heaphdr *curr; |
| 53546 | #if defined(DUK_USE_DEBUG) |
| 53547 | duk_int_t count = 0; |
| 53548 | #endif |
| 53549 | |
| 53550 | DUK_ASSERT(heap != NULL); |
| 53551 | |
| 53552 | curr = heap->refzero_list; |
| 53553 | DUK_ASSERT(curr != NULL); |
| 53554 | DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, curr) == NULL); /* We're called on initial insert only. */ |
| 53555 | /* curr->next is GARBAGE. */ |
| 53556 | |
| 53557 | do { |
| 53558 | duk_heaphdr *prev; |
| 53559 | |
| 53560 | DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O" , (void *) curr, (duk_heaphdr *) curr)); |
| 53561 | |
| 53562 | #if defined(DUK_USE_DEBUG) |
| 53563 | count++; |
| 53564 | #endif |
| 53565 | |
| 53566 | DUK_ASSERT(curr != NULL); |
| 53567 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */ |
| 53568 | /* FINALIZED may be set; don't care about flags here. */ |
| 53569 | |
| 53570 | /* Refcount finalize 'curr'. Refzero_list must be non-NULL |
| 53571 | * here to prevent recursive entry to duk__refcount_free_pending(). |
| 53572 | */ |
| 53573 | DUK_ASSERT(heap->refzero_list != NULL); |
| 53574 | duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr); |
| 53575 | |
| 53576 | prev = DUK_HEAPHDR_GET_PREV(heap, curr); |
| 53577 | DUK_ASSERT((prev == NULL && heap->refzero_list == curr) || \ |
| 53578 | (prev != NULL && heap->refzero_list != curr)); |
| 53579 | /* prev->next is intentionally not updated and is garbage. */ |
| 53580 | |
| 53581 | duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */ |
| 53582 | |
| 53583 | curr = prev; |
| 53584 | } while (curr != NULL); |
| 53585 | |
| 53586 | heap->refzero_list = NULL; |
| 53587 | |
| 53588 | DUK_DD(DUK_DDPRINT("refzero processed %ld objects" , (long) count)); |
| 53589 | } |
| 53590 | |
| 53591 | DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hobject(duk_heap *heap, duk_hobject *obj, duk_bool_t skip_free_pending) { |
| 53592 | duk_heaphdr *hdr; |
| 53593 | duk_heaphdr *root; |
| 53594 | |
| 53595 | DUK_ASSERT(heap != NULL); |
| 53596 | DUK_ASSERT(heap->heap_thread != NULL); |
| 53597 | DUK_ASSERT(obj != NULL); |
| 53598 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) obj) == DUK_HTYPE_OBJECT); |
| 53599 | |
| 53600 | hdr = (duk_heaphdr *) obj; |
| 53601 | |
| 53602 | /* Refzero'd objects must be in heap_allocated. They can't be in |
| 53603 | * finalize_list because all objects on finalize_list have an |
| 53604 | * artificial +1 refcount bump. |
| 53605 | */ |
| 53606 | #if defined(DUK_USE_ASSERTIONS) |
| 53607 | DUK_ASSERT(duk_heap_in_heap_allocated(heap, (duk_heaphdr *) obj)); |
| 53608 | #endif |
| 53609 | |
| 53610 | DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, hdr); |
| 53611 | |
| 53612 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 53613 | /* This finalizer check MUST BE side effect free. It should also be |
| 53614 | * as fast as possible because it's applied to every object freed. |
| 53615 | */ |
| 53616 | if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr) != 0U)) { |
| 53617 | /* Special case: FINALIZED may be set if mark-and-sweep queued |
| 53618 | * object for finalization, the finalizer was executed (and |
| 53619 | * FINALIZED set), mark-and-sweep hasn't yet processed the |
| 53620 | * object again, but its refcount drops to zero. Free without |
| 53621 | * running the finalizer again. |
| 53622 | */ |
| 53623 | if (DUK_HEAPHDR_HAS_FINALIZED(hdr)) { |
| 53624 | DUK_D(DUK_DPRINT("refzero'd object has finalizer and FINALIZED is set -> free" )); |
| 53625 | } else { |
| 53626 | /* Set FINALIZABLE flag so that all objects on finalize_list |
| 53627 | * will have it set and are thus detectable based on the |
| 53628 | * flag alone. |
| 53629 | */ |
| 53630 | DUK_HEAPHDR_SET_FINALIZABLE(hdr); |
| 53631 | DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr)); |
| 53632 | |
| 53633 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 53634 | /* Bump refcount on finalize_list insert so that a |
| 53635 | * refzero can never occur when an object is waiting |
| 53636 | * for its finalizer call. Refzero might otherwise |
| 53637 | * now happen because we allow duk_push_heapptr() for |
| 53638 | * objects pending finalization. |
| 53639 | */ |
| 53640 | DUK_HEAPHDR_PREINC_REFCOUNT(hdr); |
| 53641 | #endif |
| 53642 | DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, hdr); |
| 53643 | |
| 53644 | /* Process finalizers unless skipping is explicitly |
| 53645 | * requested (NORZ) or refzero_list is being processed |
| 53646 | * (avoids side effects during a refzero cascade). |
| 53647 | * If refzero_list is processed, the initial refzero |
| 53648 | * call will run pending finalizers when refzero_list |
| 53649 | * is done. |
| 53650 | */ |
| 53651 | if (!skip_free_pending && heap->refzero_list == NULL) { |
| 53652 | duk_heap_process_finalize_list(heap); |
| 53653 | } |
| 53654 | return; |
| 53655 | } |
| 53656 | } |
| 53657 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 53658 | |
| 53659 | /* No need to finalize, free object via refzero_list. */ |
| 53660 | |
| 53661 | root = heap->refzero_list; |
| 53662 | |
| 53663 | DUK_HEAPHDR_SET_PREV(heap, hdr, NULL); |
| 53664 | /* 'next' is left as GARBAGE. */ |
| 53665 | heap->refzero_list = hdr; |
| 53666 | |
| 53667 | if (root == NULL) { |
| 53668 | /* Object is now queued. Refzero_list was NULL so |
| 53669 | * no-one is currently processing it; do it here. |
| 53670 | * With refzero processing just doing a cascade of |
| 53671 | * free calls, we can process it directly even when |
| 53672 | * NORZ macros are used: there are no side effects. |
| 53673 | */ |
| 53674 | duk__refcount_free_pending(heap); |
| 53675 | DUK_ASSERT(heap->refzero_list == NULL); |
| 53676 | |
| 53677 | /* Process finalizers only after the entire cascade |
| 53678 | * is finished. In most cases there's nothing to |
| 53679 | * finalize, so fast path check to avoid a call. |
| 53680 | */ |
| 53681 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 53682 | if (!skip_free_pending && DUK_UNLIKELY(heap->finalize_list != NULL)) { |
| 53683 | duk_heap_process_finalize_list(heap); |
| 53684 | } |
| 53685 | #endif |
| 53686 | } else { |
| 53687 | DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL); |
| 53688 | DUK_HEAPHDR_SET_PREV(heap, root, hdr); |
| 53689 | |
| 53690 | /* Object is now queued. Because refzero_list was |
| 53691 | * non-NULL, it's already being processed by someone |
| 53692 | * in the C call stack, so we're done. |
| 53693 | */ |
| 53694 | } |
| 53695 | } |
| 53696 | |
| 53697 | #if defined(DUK_USE_FINALIZER_SUPPORT) |
| 53698 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_refzero_check_fast(duk_hthread *thr) { |
| 53699 | DUK_ASSERT(thr != NULL); |
| 53700 | DUK_ASSERT(thr->heap != NULL); |
| 53701 | DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */ |
| 53702 | |
| 53703 | if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { |
| 53704 | duk_heap_process_finalize_list(thr->heap); |
| 53705 | } |
| 53706 | } |
| 53707 | |
| 53708 | DUK_INTERNAL void duk_refzero_check_slow(duk_hthread *thr) { |
| 53709 | DUK_ASSERT(thr != NULL); |
| 53710 | DUK_ASSERT(thr->heap != NULL); |
| 53711 | DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */ |
| 53712 | |
| 53713 | if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) { |
| 53714 | duk_heap_process_finalize_list(thr->heap); |
| 53715 | } |
| 53716 | } |
| 53717 | #endif /* DUK_USE_FINALIZER_SUPPORT */ |
| 53718 | |
| 53719 | /* |
| 53720 | * Refzero processing for duk_hstring. |
| 53721 | */ |
| 53722 | |
| 53723 | DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hstring(duk_heap *heap, duk_hstring *str) { |
| 53724 | DUK_ASSERT(heap != NULL); |
| 53725 | DUK_ASSERT(heap->heap_thread != NULL); |
| 53726 | DUK_ASSERT(str != NULL); |
| 53727 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) str) == DUK_HTYPE_STRING); |
| 53728 | |
| 53729 | duk_heap_strcache_string_remove(heap, str); |
| 53730 | duk_heap_strtable_unlink(heap, str); |
| 53731 | duk_free_hstring(heap, str); |
| 53732 | } |
| 53733 | |
| 53734 | /* |
| 53735 | * Refzero processing for duk_hbuffer. |
| 53736 | */ |
| 53737 | |
| 53738 | DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hbuffer(duk_heap *heap, duk_hbuffer *buf) { |
| 53739 | DUK_ASSERT(heap != NULL); |
| 53740 | DUK_ASSERT(heap->heap_thread != NULL); |
| 53741 | DUK_ASSERT(buf != NULL); |
| 53742 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) buf) == DUK_HTYPE_BUFFER); |
| 53743 | |
| 53744 | DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, (duk_heaphdr *) buf); |
| 53745 | duk_free_hbuffer(heap, buf); |
| 53746 | } |
| 53747 | |
| 53748 | /* |
| 53749 | * Incref and decref functions. |
| 53750 | * |
| 53751 | * Decref may trigger immediate refzero handling, which may free and finalize |
| 53752 | * an arbitrary number of objects (a "DECREF cascade"). |
| 53753 | * |
| 53754 | * Refzero handling is skipped entirely if (1) mark-and-sweep is running or |
| 53755 | * (2) execution is paused in the debugger. The objects are left in the heap, |
| 53756 | * and will be freed by mark-and-sweep or eventual heap destruction. |
| 53757 | * |
| 53758 | * This is necessary during mark-and-sweep because refcounts are also updated |
| 53759 | * during the sweep phase (otherwise objects referenced by a swept object |
| 53760 | * would have incorrect refcounts) which then calls here. This could be |
| 53761 | * avoided by using separate decref macros in mark-and-sweep; however, |
| 53762 | * mark-and-sweep also calls finalizers which would use the ordinary decref |
| 53763 | * macros anyway. |
| 53764 | * |
| 53765 | * We can't process refzeros (= free objects) when the debugger is running |
| 53766 | * as the debugger might make an object unreachable but still continue |
| 53767 | * inspecting it (or even cause it to be pushed back). So we must rely on |
| 53768 | * mark-and-sweep to collect them. |
| 53769 | * |
| 53770 | * The DUK__RZ_SUPPRESS_CHECK() condition is also used in heap destruction |
| 53771 | * when running finalizers for remaining objects: the flag prevents objects |
| 53772 | * from being moved around in heap linked lists while that's being done. |
| 53773 | * |
| 53774 | * The suppress condition is important to performance. |
| 53775 | */ |
| 53776 | |
| 53777 | #define DUK__RZ_SUPPRESS_ASSERT1() do { \ |
| 53778 | DUK_ASSERT(thr != NULL); \ |
| 53779 | DUK_ASSERT(thr->heap != NULL); \ |
| 53780 | /* When mark-and-sweep runs, heap_thread must exist. */ \ |
| 53781 | DUK_ASSERT(thr->heap->ms_running == 0 || thr->heap->heap_thread != NULL); \ |
| 53782 | /* In normal operation finalizers are executed with ms_running == 0 \ |
| 53783 | * so we should never see ms_running == 1 and thr != heap_thread. \ |
| 53784 | * In heap destruction finalizers are executed with ms_running != 0 \ |
| 53785 | * to e.g. prevent refzero; a special value ms_running == 2 is used \ |
| 53786 | * in that case so it can be distinguished from the normal runtime \ |
| 53787 | * case, and allows a stronger assertion here (GH-2030). \ |
| 53788 | */ \ |
| 53789 | DUK_ASSERT(!(thr->heap->ms_running == 1 && thr != thr->heap->heap_thread)); \ |
| 53790 | /* We may be called when the heap is initializing and we process \ |
| 53791 | * refzeros normally, but mark-and-sweep and finalizers are prevented \ |
| 53792 | * if that's the case. \ |
| 53793 | */ \ |
| 53794 | DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->ms_prevent_count > 0); \ |
| 53795 | DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->pf_prevent_count > 0); \ |
| 53796 | } while (0) |
| 53797 | |
| 53798 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 53799 | #define DUK__RZ_SUPPRESS_ASSERT2() do { \ |
| 53800 | /* When debugger is paused, ms_running is set. */ \ |
| 53801 | DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->ms_running != 0); \ |
| 53802 | } while (0) |
| 53803 | #define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0) |
| 53804 | #else |
| 53805 | #define DUK__RZ_SUPPRESS_ASSERT2() do { } while (0) |
| 53806 | #define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0) |
| 53807 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 53808 | |
| 53809 | #define DUK__RZ_SUPPRESS_CHECK() do { \ |
| 53810 | DUK__RZ_SUPPRESS_ASSERT1(); \ |
| 53811 | DUK__RZ_SUPPRESS_ASSERT2(); \ |
| 53812 | if (DUK_UNLIKELY(DUK__RZ_SUPPRESS_COND())) { \ |
| 53813 | DUK_DDD(DUK_DDDPRINT("refzero handling suppressed (not even queued) when mark-and-sweep running, object: %p", (void *) h)); \ |
| 53814 | return; \ |
| 53815 | } \ |
| 53816 | } while (0) |
| 53817 | |
| 53818 | #define DUK__RZ_STRING() do { \ |
| 53819 | duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \ |
| 53820 | } while (0) |
| 53821 | #define DUK__RZ_BUFFER() do { \ |
| 53822 | duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \ |
| 53823 | } while (0) |
| 53824 | #define DUK__RZ_OBJECT() do { \ |
| 53825 | duk__refcount_refzero_hobject(heap, (duk_hobject *) h, skip_free_pending); \ |
| 53826 | } while (0) |
| 53827 | |
| 53828 | /* XXX: test the effect of inlining here vs. NOINLINE in refzero helpers */ |
| 53829 | #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| 53830 | #define DUK__RZ_INLINE DUK_ALWAYS_INLINE |
| 53831 | #else |
| 53832 | #define DUK__RZ_INLINE /*nop*/ |
| 53833 | #endif |
| 53834 | |
| 53835 | DUK_LOCAL DUK__RZ_INLINE void duk__hstring_refzero_helper(duk_hthread *thr, duk_hstring *h) { |
| 53836 | duk_heap *heap; |
| 53837 | |
| 53838 | DUK_ASSERT(thr != NULL); |
| 53839 | DUK_ASSERT(h != NULL); |
| 53840 | heap = thr->heap; |
| 53841 | |
| 53842 | DUK__RZ_SUPPRESS_CHECK(); |
| 53843 | DUK__RZ_STRING(); |
| 53844 | } |
| 53845 | |
| 53846 | DUK_LOCAL DUK__RZ_INLINE void duk__hbuffer_refzero_helper(duk_hthread *thr, duk_hbuffer *h) { |
| 53847 | duk_heap *heap; |
| 53848 | |
| 53849 | DUK_ASSERT(thr != NULL); |
| 53850 | DUK_ASSERT(h != NULL); |
| 53851 | heap = thr->heap; |
| 53852 | |
| 53853 | DUK__RZ_SUPPRESS_CHECK(); |
| 53854 | DUK__RZ_BUFFER(); |
| 53855 | } |
| 53856 | |
| 53857 | DUK_LOCAL DUK__RZ_INLINE void duk__hobject_refzero_helper(duk_hthread *thr, duk_hobject *h, duk_bool_t skip_free_pending) { |
| 53858 | duk_heap *heap; |
| 53859 | |
| 53860 | DUK_ASSERT(thr != NULL); |
| 53861 | DUK_ASSERT(h != NULL); |
| 53862 | heap = thr->heap; |
| 53863 | |
| 53864 | DUK__RZ_SUPPRESS_CHECK(); |
| 53865 | DUK__RZ_OBJECT(); |
| 53866 | } |
| 53867 | |
| 53868 | DUK_LOCAL DUK__RZ_INLINE void duk__heaphdr_refzero_helper(duk_hthread *thr, duk_heaphdr *h, duk_bool_t skip_free_pending) { |
| 53869 | duk_heap *heap; |
| 53870 | duk_small_uint_t htype; |
| 53871 | |
| 53872 | DUK_ASSERT(thr != NULL); |
| 53873 | DUK_ASSERT(h != NULL); |
| 53874 | heap = thr->heap; |
| 53875 | |
| 53876 | htype = (duk_small_uint_t) DUK_HEAPHDR_GET_TYPE(h); |
| 53877 | DUK_DDD(DUK_DDDPRINT("ms_running=%ld, heap_thread=%p" , (long) thr->heap->ms_running, thr->heap->heap_thread)); |
| 53878 | DUK__RZ_SUPPRESS_CHECK(); |
| 53879 | |
| 53880 | switch (htype) { |
| 53881 | case DUK_HTYPE_STRING: |
| 53882 | /* Strings have no internal references but do have "weak" |
| 53883 | * references in the string cache. Also note that strings |
| 53884 | * are not on the heap_allocated list like other heap |
| 53885 | * elements. |
| 53886 | */ |
| 53887 | |
| 53888 | DUK__RZ_STRING(); |
| 53889 | break; |
| 53890 | |
| 53891 | case DUK_HTYPE_OBJECT: |
| 53892 | /* Objects have internal references. Must finalize through |
| 53893 | * the "refzero" work list. |
| 53894 | */ |
| 53895 | |
| 53896 | DUK__RZ_OBJECT(); |
| 53897 | break; |
| 53898 | |
| 53899 | default: |
| 53900 | /* Buffers have no internal references. However, a dynamic |
| 53901 | * buffer has a separate allocation for the buffer. This is |
| 53902 | * freed by duk_heap_free_heaphdr_raw(). |
| 53903 | */ |
| 53904 | |
| 53905 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_BUFFER); |
| 53906 | DUK__RZ_BUFFER(); |
| 53907 | break; |
| 53908 | } |
| 53909 | } |
| 53910 | |
| 53911 | DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) { |
| 53912 | duk__heaphdr_refzero_helper(thr, h, 0 /*skip_free_pending*/); |
| 53913 | } |
| 53914 | |
| 53915 | DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) { |
| 53916 | duk__heaphdr_refzero_helper(thr, h, 1 /*skip_free_pending*/); |
| 53917 | } |
| 53918 | |
| 53919 | DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) { |
| 53920 | duk__hstring_refzero_helper(thr, h); |
| 53921 | } |
| 53922 | |
| 53923 | DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) { |
| 53924 | duk__hbuffer_refzero_helper(thr, h); |
| 53925 | } |
| 53926 | |
| 53927 | DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h) { |
| 53928 | duk__hobject_refzero_helper(thr, h, 0 /*skip_free_pending*/); |
| 53929 | } |
| 53930 | |
| 53931 | DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) { |
| 53932 | duk__hobject_refzero_helper(thr, h, 1 /*skip_free_pending*/); |
| 53933 | } |
| 53934 | |
| 53935 | #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| 53936 | DUK_INTERNAL void duk_tval_incref(duk_tval *tv) { |
| 53937 | DUK_ASSERT(tv != NULL); |
| 53938 | |
| 53939 | if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { |
| 53940 | duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); |
| 53941 | DUK_ASSERT(h != NULL); |
| 53942 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); |
| 53943 | DUK_ASSERT_DISABLE(h->h_refcount >= 0); |
| 53944 | DUK_HEAPHDR_PREINC_REFCOUNT(h); |
| 53945 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) != 0); /* No wrapping. */ |
| 53946 | } |
| 53947 | } |
| 53948 | |
| 53949 | DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) { |
| 53950 | DUK_ASSERT(thr != NULL); |
| 53951 | DUK_ASSERT(tv != NULL); |
| 53952 | |
| 53953 | if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { |
| 53954 | duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); |
| 53955 | DUK_ASSERT(h != NULL); |
| 53956 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); |
| 53957 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1); |
| 53958 | #if 0 |
| 53959 | if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) { |
| 53960 | return; |
| 53961 | } |
| 53962 | duk_heaphdr_refzero(thr, h); |
| 53963 | #else |
| 53964 | duk_heaphdr_decref(thr, h); |
| 53965 | #endif |
| 53966 | } |
| 53967 | } |
| 53968 | |
| 53969 | DUK_INTERNAL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv) { |
| 53970 | DUK_ASSERT(thr != NULL); |
| 53971 | DUK_ASSERT(tv != NULL); |
| 53972 | |
| 53973 | if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) { |
| 53974 | duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); |
| 53975 | DUK_ASSERT(h != NULL); |
| 53976 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); |
| 53977 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1); |
| 53978 | #if 0 |
| 53979 | if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) { |
| 53980 | return; |
| 53981 | } |
| 53982 | duk_heaphdr_refzero_norz(thr, h); |
| 53983 | #else |
| 53984 | duk_heaphdr_decref_norz(thr, h); |
| 53985 | #endif |
| 53986 | } |
| 53987 | } |
| 53988 | #endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */ |
| 53989 | |
| 53990 | #define DUK__DECREF_ASSERTS() do { \ |
| 53991 | DUK_ASSERT(thr != NULL); \ |
| 53992 | DUK_ASSERT(thr->heap != NULL); \ |
| 53993 | DUK_ASSERT(h != NULL); \ |
| 53994 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((duk_heaphdr *) h)); \ |
| 53995 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) >= 1); \ |
| 53996 | } while (0) |
| 53997 | #if defined(DUK_USE_ROM_OBJECTS) |
| 53998 | #define DUK__INCREF_SHARED() do { \ |
| 53999 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \ |
| 54000 | return; \ |
| 54001 | } \ |
| 54002 | DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \ |
| 54003 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \ |
| 54004 | } while (0) |
| 54005 | #define DUK__DECREF_SHARED() do { \ |
| 54006 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \ |
| 54007 | return; \ |
| 54008 | } \ |
| 54009 | if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \ |
| 54010 | return; \ |
| 54011 | } \ |
| 54012 | } while (0) |
| 54013 | #else |
| 54014 | #define DUK__INCREF_SHARED() do { \ |
| 54015 | DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \ |
| 54016 | DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \ |
| 54017 | } while (0) |
| 54018 | #define DUK__DECREF_SHARED() do { \ |
| 54019 | if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \ |
| 54020 | return; \ |
| 54021 | } \ |
| 54022 | } while (0) |
| 54023 | #endif |
| 54024 | |
| 54025 | #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT) |
| 54026 | /* This will in practice be inlined because it's just an INC instructions |
| 54027 | * and a bit test + INC when ROM objects are enabled. |
| 54028 | */ |
| 54029 | DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) { |
| 54030 | DUK_ASSERT(h != NULL); |
| 54031 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); |
| 54032 | DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0); |
| 54033 | |
| 54034 | DUK__INCREF_SHARED(); |
| 54035 | } |
| 54036 | |
| 54037 | DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) { |
| 54038 | DUK__DECREF_ASSERTS(); |
| 54039 | DUK__DECREF_SHARED(); |
| 54040 | duk_heaphdr_refzero(thr, h); |
| 54041 | |
| 54042 | /* Forced mark-and-sweep when GC torture enabled; this could happen |
| 54043 | * on any DECREF (but not DECREF_NORZ). |
| 54044 | */ |
| 54045 | DUK_GC_TORTURE(thr->heap); |
| 54046 | } |
| 54047 | DUK_INTERNAL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h) { |
| 54048 | DUK__DECREF_ASSERTS(); |
| 54049 | DUK__DECREF_SHARED(); |
| 54050 | duk_heaphdr_refzero_norz(thr, h); |
| 54051 | } |
| 54052 | #endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */ |
| 54053 | |
| 54054 | #if 0 /* Not needed. */ |
| 54055 | DUK_INTERNAL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h) { |
| 54056 | DUK__DECREF_ASSERTS(); |
| 54057 | DUK__DECREF_SHARED(); |
| 54058 | duk_hstring_refzero(thr, h); |
| 54059 | } |
| 54060 | DUK_INTERNAL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h) { |
| 54061 | DUK__DECREF_ASSERTS(); |
| 54062 | DUK__DECREF_SHARED(); |
| 54063 | duk_hstring_refzero_norz(thr, h); |
| 54064 | } |
| 54065 | DUK_INTERNAL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h) { |
| 54066 | DUK__DECREF_ASSERTS(); |
| 54067 | DUK__DECREF_SHARED(); |
| 54068 | duk_hbuffer_refzero(thr, h); |
| 54069 | } |
| 54070 | DUK_INTERNAL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h) { |
| 54071 | DUK__DECREF_ASSERTS(); |
| 54072 | DUK__DECREF_SHARED(); |
| 54073 | duk_hbuffer_refzero_norz(thr, h); |
| 54074 | } |
| 54075 | DUK_INTERNAL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h) { |
| 54076 | DUK__DECREF_ASSERTS(); |
| 54077 | DUK__DECREF_SHARED(); |
| 54078 | duk_hobject_refzero(thr, h); |
| 54079 | } |
| 54080 | DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) { |
| 54081 | DUK__DECREF_ASSERTS(); |
| 54082 | DUK__DECREF_SHARED(); |
| 54083 | duk_hobject_refzero_norz(thr, h); |
| 54084 | } |
| 54085 | #endif |
| 54086 | |
| 54087 | #else /* DUK_USE_REFERENCE_COUNTING */ |
| 54088 | |
| 54089 | /* no refcounting */ |
| 54090 | |
| 54091 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 54092 | |
| 54093 | /* automatic undefs */ |
| 54094 | #undef DUK__DECREF_ASSERTS |
| 54095 | #undef DUK__DECREF_SHARED |
| 54096 | #undef DUK__INCREF_SHARED |
| 54097 | #undef DUK__RZ_BUFFER |
| 54098 | #undef DUK__RZ_INLINE |
| 54099 | #undef DUK__RZ_OBJECT |
| 54100 | #undef DUK__RZ_STRING |
| 54101 | #undef DUK__RZ_SUPPRESS_ASSERT1 |
| 54102 | #undef DUK__RZ_SUPPRESS_ASSERT2 |
| 54103 | #undef DUK__RZ_SUPPRESS_CHECK |
| 54104 | #undef DUK__RZ_SUPPRESS_COND |
| 54105 | #line 1 "duk_heap_stringcache.c" |
| 54106 | /* |
| 54107 | * String cache. |
| 54108 | * |
| 54109 | * Provides a cache to optimize indexed string lookups. The cache keeps |
| 54110 | * track of (byte offset, char offset) states for a fixed number of strings. |
| 54111 | * Otherwise we'd need to scan from either end of the string, as we store |
| 54112 | * strings in (extended) UTF-8. |
| 54113 | */ |
| 54114 | |
| 54115 | /* #include duk_internal.h -> already included */ |
| 54116 | |
| 54117 | /* |
| 54118 | * Delete references to given hstring from the heap string cache. |
| 54119 | * |
| 54120 | * String cache references are 'weak': they are not counted towards |
| 54121 | * reference counts, nor serve as roots for mark-and-sweep. When an |
| 54122 | * object is about to be freed, such references need to be removed. |
| 54123 | */ |
| 54124 | |
| 54125 | DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) { |
| 54126 | duk_uint_t i; |
| 54127 | for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { |
| 54128 | duk_strcache_entry *c = heap->strcache + i; |
| 54129 | if (c->h == h) { |
| 54130 | DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p" , |
| 54131 | (void *) h, (void *) heap)); |
| 54132 | c->h = NULL; |
| 54133 | |
| 54134 | /* XXX: the string shouldn't appear twice, but we now loop to the |
| 54135 | * end anyway; if fixed, add a looping assertion to ensure there |
| 54136 | * is no duplicate. |
| 54137 | */ |
| 54138 | } |
| 54139 | } |
| 54140 | } |
| 54141 | |
| 54142 | /* |
| 54143 | * String scanning helpers |
| 54144 | * |
| 54145 | * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are |
| 54146 | * considered to contribute a character. This must match how string |
| 54147 | * character length is computed. |
| 54148 | */ |
| 54149 | |
| 54150 | DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) { |
| 54151 | while (n > 0) { |
| 54152 | for (;;) { |
| 54153 | p++; |
| 54154 | if (p >= q) { |
| 54155 | return NULL; |
| 54156 | } |
| 54157 | if ((*p & 0xc0) != 0x80) { |
| 54158 | break; |
| 54159 | } |
| 54160 | } |
| 54161 | n--; |
| 54162 | } |
| 54163 | return p; |
| 54164 | } |
| 54165 | |
| 54166 | DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) { |
| 54167 | while (n > 0) { |
| 54168 | for (;;) { |
| 54169 | p--; |
| 54170 | if (p < q) { |
| 54171 | return NULL; |
| 54172 | } |
| 54173 | if ((*p & 0xc0) != 0x80) { |
| 54174 | break; |
| 54175 | } |
| 54176 | } |
| 54177 | n--; |
| 54178 | } |
| 54179 | return p; |
| 54180 | } |
| 54181 | |
| 54182 | /* |
| 54183 | * Convert char offset to byte offset |
| 54184 | * |
| 54185 | * Avoid using the string cache if possible: for ASCII strings byte and |
| 54186 | * char offsets are equal and for short strings direct scanning may be |
| 54187 | * better than using the string cache (which may evict a more important |
| 54188 | * entry). |
| 54189 | * |
| 54190 | * Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t). |
| 54191 | * Better typing might be to use duk_size_t. |
| 54192 | * |
| 54193 | * Caller should ensure 'char_offset' is within the string bounds [0,charlen] |
| 54194 | * (endpoint is inclusive). If this is not the case, no memory unsafe |
| 54195 | * behavior will happen but an error will be thrown. |
| 54196 | */ |
| 54197 | |
| 54198 | DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) { |
| 54199 | duk_heap *heap; |
| 54200 | duk_strcache_entry *sce; |
| 54201 | duk_uint_fast32_t byte_offset; |
| 54202 | duk_uint_t i; |
| 54203 | duk_bool_t use_cache; |
| 54204 | duk_uint_fast32_t dist_start, dist_end, dist_sce; |
| 54205 | duk_uint_fast32_t char_length; |
| 54206 | const duk_uint8_t *p_start; |
| 54207 | const duk_uint8_t *p_end; |
| 54208 | const duk_uint8_t *p_found; |
| 54209 | |
| 54210 | /* |
| 54211 | * For ASCII strings, the answer is simple. |
| 54212 | */ |
| 54213 | |
| 54214 | if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) { |
| 54215 | return char_offset; |
| 54216 | } |
| 54217 | |
| 54218 | char_length = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h); |
| 54219 | DUK_ASSERT(char_offset <= char_length); |
| 54220 | |
| 54221 | if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) { |
| 54222 | /* Must recheck because the 'is ascii' flag may be set |
| 54223 | * lazily. Alternatively, we could just compare charlen |
| 54224 | * to bytelen. |
| 54225 | */ |
| 54226 | return char_offset; |
| 54227 | } |
| 54228 | |
| 54229 | /* |
| 54230 | * For non-ASCII strings, we need to scan forwards or backwards |
| 54231 | * from some starting point. The starting point may be the start |
| 54232 | * or end of the string, or some cached midpoint in the string |
| 54233 | * cache. |
| 54234 | * |
| 54235 | * For "short" strings we simply scan without checking or updating |
| 54236 | * the cache. For longer strings we check and update the cache as |
| 54237 | * necessary, inserting a new cache entry if none exists. |
| 54238 | */ |
| 54239 | |
| 54240 | DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld" , |
| 54241 | (void *) h, (long) char_offset, |
| 54242 | (long) DUK_HSTRING_GET_CHARLEN(h), |
| 54243 | (long) DUK_HSTRING_GET_BYTELEN(h))); |
| 54244 | |
| 54245 | heap = thr->heap; |
| 54246 | sce = NULL; |
| 54247 | use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT); |
| 54248 | |
| 54249 | if (use_cache) { |
| 54250 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 54251 | DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):" )); |
| 54252 | for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { |
| 54253 | duk_strcache_entry *c = heap->strcache + i; |
| 54254 | DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld" , |
| 54255 | (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx)); |
| 54256 | } |
| 54257 | #endif |
| 54258 | |
| 54259 | for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { |
| 54260 | duk_strcache_entry *c = heap->strcache + i; |
| 54261 | |
| 54262 | if (c->h == h) { |
| 54263 | sce = c; |
| 54264 | break; |
| 54265 | } |
| 54266 | } |
| 54267 | } |
| 54268 | |
| 54269 | /* |
| 54270 | * Scan from shortest distance: |
| 54271 | * - start of string |
| 54272 | * - end of string |
| 54273 | * - cache entry (if exists) |
| 54274 | */ |
| 54275 | |
| 54276 | DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset); |
| 54277 | dist_start = char_offset; |
| 54278 | dist_end = char_length - char_offset; |
| 54279 | dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */ |
| 54280 | |
| 54281 | p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); |
| 54282 | p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h)); |
| 54283 | p_found = NULL; |
| 54284 | |
| 54285 | if (sce) { |
| 54286 | if (char_offset >= sce->cidx) { |
| 54287 | dist_sce = char_offset - sce->cidx; |
| 54288 | if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) { |
| 54289 | DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " |
| 54290 | "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " |
| 54291 | "scan forwards from sce" , |
| 54292 | (long) use_cache, (void *) (sce ? sce->h : NULL), |
| 54293 | (sce ? (long) sce->cidx : (long) -1), |
| 54294 | (sce ? (long) sce->bidx : (long) -1), |
| 54295 | (long) dist_start, (long) dist_end, (long) dist_sce)); |
| 54296 | |
| 54297 | p_found = duk__scan_forwards(p_start + sce->bidx, |
| 54298 | p_end, |
| 54299 | dist_sce); |
| 54300 | goto scan_done; |
| 54301 | } |
| 54302 | } else { |
| 54303 | dist_sce = sce->cidx - char_offset; |
| 54304 | if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) { |
| 54305 | DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " |
| 54306 | "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " |
| 54307 | "scan backwards from sce" , |
| 54308 | (long) use_cache, (void *) (sce ? sce->h : NULL), |
| 54309 | (sce ? (long) sce->cidx : (long) -1), |
| 54310 | (sce ? (long) sce->bidx : (long) -1), |
| 54311 | (long) dist_start, (long) dist_end, (long) dist_sce)); |
| 54312 | |
| 54313 | p_found = duk__scan_backwards(p_start + sce->bidx, |
| 54314 | p_start, |
| 54315 | dist_sce); |
| 54316 | goto scan_done; |
| 54317 | } |
| 54318 | } |
| 54319 | } |
| 54320 | |
| 54321 | /* no sce, or sce scan not best */ |
| 54322 | |
| 54323 | if (dist_start <= dist_end) { |
| 54324 | DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " |
| 54325 | "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " |
| 54326 | "scan forwards from string start" , |
| 54327 | (long) use_cache, (void *) (sce ? sce->h : NULL), |
| 54328 | (sce ? (long) sce->cidx : (long) -1), |
| 54329 | (sce ? (long) sce->bidx : (long) -1), |
| 54330 | (long) dist_start, (long) dist_end, (long) dist_sce)); |
| 54331 | |
| 54332 | p_found = duk__scan_forwards(p_start, |
| 54333 | p_end, |
| 54334 | dist_start); |
| 54335 | } else { |
| 54336 | DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, " |
| 54337 | "dist_start=%ld, dist_end=%ld, dist_sce=%ld => " |
| 54338 | "scan backwards from string end" , |
| 54339 | (long) use_cache, (void *) (sce ? sce->h : NULL), |
| 54340 | (sce ? (long) sce->cidx : (long) -1), |
| 54341 | (sce ? (long) sce->bidx : (long) -1), |
| 54342 | (long) dist_start, (long) dist_end, (long) dist_sce)); |
| 54343 | |
| 54344 | p_found = duk__scan_backwards(p_end, |
| 54345 | p_start, |
| 54346 | dist_end); |
| 54347 | } |
| 54348 | |
| 54349 | scan_done: |
| 54350 | |
| 54351 | if (DUK_UNLIKELY(p_found == NULL)) { |
| 54352 | /* Scan error: this shouldn't normally happen; it could happen if |
| 54353 | * string is not valid UTF-8 data, and clen/blen are not consistent |
| 54354 | * with the scanning algorithm. |
| 54355 | */ |
| 54356 | goto scan_error; |
| 54357 | } |
| 54358 | |
| 54359 | DUK_ASSERT(p_found >= p_start); |
| 54360 | DUK_ASSERT(p_found <= p_end); /* may be equal */ |
| 54361 | byte_offset = (duk_uint32_t) (p_found - p_start); |
| 54362 | |
| 54363 | DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld" , |
| 54364 | (void *) h, (long) char_offset, (long) byte_offset)); |
| 54365 | |
| 54366 | /* |
| 54367 | * Update cache entry (allocating if necessary), and move the |
| 54368 | * cache entry to the first place (in an "LRU" policy). |
| 54369 | */ |
| 54370 | |
| 54371 | if (use_cache) { |
| 54372 | /* update entry, allocating if necessary */ |
| 54373 | if (!sce) { |
| 54374 | sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */ |
| 54375 | sce->h = h; |
| 54376 | } |
| 54377 | DUK_ASSERT(sce != NULL); |
| 54378 | sce->bidx = (duk_uint32_t) (p_found - p_start); |
| 54379 | sce->cidx = (duk_uint32_t) char_offset; |
| 54380 | |
| 54381 | /* LRU: move our entry to first */ |
| 54382 | if (sce > &heap->strcache[0]) { |
| 54383 | /* |
| 54384 | * A C |
| 54385 | * B A |
| 54386 | * C <- sce ==> B |
| 54387 | * D D |
| 54388 | */ |
| 54389 | duk_strcache_entry tmp; |
| 54390 | |
| 54391 | tmp = *sce; |
| 54392 | duk_memmove((void *) (&heap->strcache[1]), |
| 54393 | (const void *) (&heap->strcache[0]), |
| 54394 | (size_t) (((char *) sce) - ((char *) &heap->strcache[0]))); |
| 54395 | heap->strcache[0] = tmp; |
| 54396 | |
| 54397 | /* 'sce' points to the wrong entry here, but is no longer used */ |
| 54398 | } |
| 54399 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 54400 | DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):" )); |
| 54401 | for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) { |
| 54402 | duk_strcache_entry *c = heap->strcache + i; |
| 54403 | DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld" , |
| 54404 | (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx)); |
| 54405 | } |
| 54406 | #endif |
| 54407 | } |
| 54408 | |
| 54409 | return byte_offset; |
| 54410 | |
| 54411 | scan_error: |
| 54412 | DUK_ERROR_INTERNAL(thr); |
| 54413 | DUK_WO_NORETURN(return 0;); |
| 54414 | } |
| 54415 | #line 1 "duk_heap_stringtable.c" |
| 54416 | /* |
| 54417 | * Heap string table handling, string interning. |
| 54418 | */ |
| 54419 | |
| 54420 | /* #include duk_internal.h -> already included */ |
| 54421 | |
| 54422 | /* Resize checks not needed if minsize == maxsize, typical for low memory |
| 54423 | * targets. |
| 54424 | */ |
| 54425 | #define DUK__STRTAB_RESIZE_CHECK |
| 54426 | #if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE) |
| 54427 | #undef DUK__STRTAB_RESIZE_CHECK |
| 54428 | #endif |
| 54429 | |
| 54430 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54431 | #define DUK__HEAPPTR_ENC16(heap,ptr) DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr)) |
| 54432 | #define DUK__HEAPPTR_DEC16(heap,val) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val)) |
| 54433 | #define DUK__GET_STRTABLE(heap) ((heap)->strtable16) |
| 54434 | #else |
| 54435 | #define DUK__HEAPPTR_ENC16(heap,ptr) (ptr) |
| 54436 | #define DUK__HEAPPTR_DEC16(heap,val) (val) |
| 54437 | #define DUK__GET_STRTABLE(heap) ((heap)->strtable) |
| 54438 | #endif |
| 54439 | |
| 54440 | #define DUK__STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */ |
| 54441 | |
| 54442 | /* |
| 54443 | * Debug dump stringtable. |
| 54444 | */ |
| 54445 | |
| 54446 | #if defined(DUK_USE_DEBUG) |
| 54447 | DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) { |
| 54448 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54449 | duk_uint16_t *strtable; |
| 54450 | #else |
| 54451 | duk_hstring **strtable; |
| 54452 | #endif |
| 54453 | duk_uint32_t i; |
| 54454 | duk_hstring *h; |
| 54455 | duk_size_t count_total = 0; |
| 54456 | duk_size_t count_chain; |
| 54457 | duk_size_t count_chain_min = DUK_SIZE_MAX; |
| 54458 | duk_size_t count_chain_max = 0; |
| 54459 | duk_size_t count_len[8]; /* chain lengths from 0 to 7 */ |
| 54460 | |
| 54461 | if (heap == NULL) { |
| 54462 | DUK_D(DUK_DPRINT("string table, heap=NULL" )); |
| 54463 | return; |
| 54464 | } |
| 54465 | |
| 54466 | strtable = DUK__GET_STRTABLE(heap); |
| 54467 | if (strtable == NULL) { |
| 54468 | DUK_D(DUK_DPRINT("string table, strtab=NULL" )); |
| 54469 | return; |
| 54470 | } |
| 54471 | |
| 54472 | duk_memzero((void *) count_len, sizeof(count_len)); |
| 54473 | for (i = 0; i < heap->st_size; i++) { |
| 54474 | h = DUK__HEAPPTR_DEC16(heap, strtable[i]); |
| 54475 | count_chain = 0; |
| 54476 | while (h != NULL) { |
| 54477 | count_chain++; |
| 54478 | h = h->hdr.h_next; |
| 54479 | } |
| 54480 | if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) { |
| 54481 | count_len[count_chain]++; |
| 54482 | } |
| 54483 | count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max); |
| 54484 | count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min); |
| 54485 | count_total += count_chain; |
| 54486 | } |
| 54487 | |
| 54488 | DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: " |
| 54489 | "counts: %lu %lu %lu %lu %lu %lu %lu %lu ..." , |
| 54490 | (void *) heap->strtable, (unsigned long) count_total, |
| 54491 | (unsigned long) count_chain_min, (unsigned long) count_chain_max, |
| 54492 | (double) count_total / (double) heap->st_size, |
| 54493 | (unsigned long) count_len[0], (unsigned long) count_len[1], |
| 54494 | (unsigned long) count_len[2], (unsigned long) count_len[3], |
| 54495 | (unsigned long) count_len[4], (unsigned long) count_len[5], |
| 54496 | (unsigned long) count_len[6], (unsigned long) count_len[7])); |
| 54497 | } |
| 54498 | #endif /* DUK_USE_DEBUG */ |
| 54499 | |
| 54500 | /* |
| 54501 | * Assertion helper to ensure strtable is populated correctly. |
| 54502 | */ |
| 54503 | |
| 54504 | #if defined(DUK_USE_ASSERTIONS) |
| 54505 | DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) { |
| 54506 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54507 | duk_uint16_t *strtable; |
| 54508 | #else |
| 54509 | duk_hstring **strtable; |
| 54510 | #endif |
| 54511 | duk_uint32_t i; |
| 54512 | duk_hstring *h; |
| 54513 | duk_size_t count = 0; |
| 54514 | |
| 54515 | DUK_ASSERT(heap != NULL); |
| 54516 | |
| 54517 | strtable = DUK__GET_STRTABLE(heap); |
| 54518 | if (strtable != NULL) { |
| 54519 | DUK_ASSERT(heap->st_size != 0); |
| 54520 | DUK_ASSERT(heap->st_mask == heap->st_size - 1); |
| 54521 | |
| 54522 | for (i = 0; i < heap->st_size; i++) { |
| 54523 | h = DUK__HEAPPTR_DEC16(heap, strtable[i]); |
| 54524 | while (h != NULL) { |
| 54525 | DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); |
| 54526 | count++; |
| 54527 | h = h->hdr.h_next; |
| 54528 | } |
| 54529 | } |
| 54530 | } else { |
| 54531 | DUK_ASSERT(heap->st_size == 0); |
| 54532 | DUK_ASSERT(heap->st_mask == 0); |
| 54533 | } |
| 54534 | |
| 54535 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 54536 | DUK_ASSERT(count == (duk_size_t) heap->st_count); |
| 54537 | #endif |
| 54538 | } |
| 54539 | #endif /* DUK_USE_ASSERTIONS */ |
| 54540 | |
| 54541 | /* |
| 54542 | * Allocate and initialize a duk_hstring. |
| 54543 | * |
| 54544 | * Returns a NULL if allocation or initialization fails for some reason. |
| 54545 | * |
| 54546 | * The string won't be inserted into the string table and isn't tracked in |
| 54547 | * any way (link pointers will be NULL). The caller must place the string |
| 54548 | * into the string table without any risk of a longjmp, otherwise the string |
| 54549 | * is leaked. |
| 54550 | */ |
| 54551 | |
| 54552 | DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap, |
| 54553 | const duk_uint8_t *str, |
| 54554 | duk_uint32_t blen, |
| 54555 | duk_uint32_t strhash, |
| 54556 | const duk_uint8_t *extdata) { |
| 54557 | duk_hstring *res; |
| 54558 | const duk_uint8_t *data; |
| 54559 | #if !defined(DUK_USE_HSTRING_ARRIDX) |
| 54560 | duk_uarridx_t dummy; |
| 54561 | #endif |
| 54562 | |
| 54563 | DUK_ASSERT(heap != NULL); |
| 54564 | DUK_UNREF(extdata); |
| 54565 | |
| 54566 | #if defined(DUK_USE_STRLEN16) |
| 54567 | /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */ |
| 54568 | if (blen > 0xffffUL) { |
| 54569 | DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern" )); |
| 54570 | goto alloc_error; |
| 54571 | } |
| 54572 | #endif |
| 54573 | |
| 54574 | /* XXX: Memzeroing the allocated structure is not really necessary |
| 54575 | * because we could just initialize all fields explicitly (almost |
| 54576 | * all fields are initialized explicitly anyway). |
| 54577 | */ |
| 54578 | #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) |
| 54579 | if (extdata) { |
| 54580 | res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external)); |
| 54581 | if (DUK_UNLIKELY(res == NULL)) { |
| 54582 | goto alloc_error; |
| 54583 | } |
| 54584 | duk_memzero(res, sizeof(duk_hstring_external)); |
| 54585 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 54586 | DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); |
| 54587 | #endif |
| 54588 | DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA); |
| 54589 | |
| 54590 | DUK_ASSERT(extdata[blen] == 0); /* Application responsibility. */ |
| 54591 | data = extdata; |
| 54592 | ((duk_hstring_external *) res)->extdata = extdata; |
| 54593 | } else |
| 54594 | #endif /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */ |
| 54595 | { |
| 54596 | duk_uint8_t *data_tmp; |
| 54597 | |
| 54598 | /* NUL terminate for convenient C access */ |
| 54599 | DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen); /* No wrap, limits ensure. */ |
| 54600 | res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1); |
| 54601 | if (DUK_UNLIKELY(res == NULL)) { |
| 54602 | goto alloc_error; |
| 54603 | } |
| 54604 | duk_memzero(res, sizeof(duk_hstring)); |
| 54605 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 54606 | DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); |
| 54607 | #endif |
| 54608 | DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); |
| 54609 | |
| 54610 | data_tmp = (duk_uint8_t *) (res + 1); |
| 54611 | duk_memcpy(data_tmp, str, blen); |
| 54612 | data_tmp[blen] = (duk_uint8_t) 0; |
| 54613 | data = (const duk_uint8_t *) data_tmp; |
| 54614 | } |
| 54615 | |
| 54616 | DUK_HSTRING_SET_BYTELEN(res, blen); |
| 54617 | DUK_HSTRING_SET_HASH(res, strhash); |
| 54618 | |
| 54619 | DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res)); |
| 54620 | #if defined(DUK_USE_HSTRING_ARRIDX) |
| 54621 | res->arridx = duk_js_to_arrayindex_string(data, blen); |
| 54622 | if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) { |
| 54623 | #else |
| 54624 | dummy = duk_js_to_arrayindex_string(data, blen); |
| 54625 | if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) { |
| 54626 | #endif |
| 54627 | /* Array index strings cannot be symbol strings, |
| 54628 | * and they're always pure ASCII so blen == clen. |
| 54629 | */ |
| 54630 | DUK_HSTRING_SET_ARRIDX(res); |
| 54631 | DUK_HSTRING_SET_ASCII(res); |
| 54632 | DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen); |
| 54633 | } else { |
| 54634 | /* Because 'data' is NUL-terminated, we don't need a |
| 54635 | * blen > 0 check here. For NUL (0x00) the symbol |
| 54636 | * checks will be false. |
| 54637 | */ |
| 54638 | if (DUK_UNLIKELY(data[0] >= 0x80U)) { |
| 54639 | if (data[0] <= 0x81) { |
| 54640 | DUK_HSTRING_SET_SYMBOL(res); |
| 54641 | } else if (data[0] == 0x82U || data[0] == 0xffU) { |
| 54642 | DUK_HSTRING_SET_HIDDEN(res); |
| 54643 | DUK_HSTRING_SET_SYMBOL(res); |
| 54644 | } |
| 54645 | } |
| 54646 | |
| 54647 | /* Using an explicit 'ASCII' flag has larger footprint (one call site |
| 54648 | * only) but is quite useful for the case when there's no explicit |
| 54649 | * 'clen' in duk_hstring. |
| 54650 | * |
| 54651 | * The flag is set lazily for RAM strings. |
| 54652 | */ |
| 54653 | DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res)); |
| 54654 | |
| 54655 | #if defined(DUK_USE_HSTRING_LAZY_CLEN) |
| 54656 | /* Charlen initialized to 0, updated on-the-fly. */ |
| 54657 | #else |
| 54658 | duk_hstring_init_charlen(res); /* Also sets ASCII flag. */ |
| 54659 | #endif |
| 54660 | } |
| 54661 | |
| 54662 | DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld" , |
| 54663 | (unsigned long) DUK_HSTRING_GET_HASH(res), |
| 54664 | (long) DUK_HSTRING_GET_BYTELEN(res), |
| 54665 | (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0), |
| 54666 | (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0))); |
| 54667 | |
| 54668 | DUK_ASSERT(res != NULL); |
| 54669 | return res; |
| 54670 | |
| 54671 | alloc_error: |
| 54672 | return NULL; |
| 54673 | } |
| 54674 | |
| 54675 | /* |
| 54676 | * Grow strtable allocation in-place. |
| 54677 | */ |
| 54678 | |
| 54679 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 54680 | DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) { |
| 54681 | duk_uint32_t new_st_size; |
| 54682 | duk_uint32_t old_st_size; |
| 54683 | duk_uint32_t i; |
| 54684 | duk_hstring *h; |
| 54685 | duk_hstring *next; |
| 54686 | duk_hstring *prev; |
| 54687 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54688 | duk_uint16_t *new_ptr; |
| 54689 | duk_uint16_t *new_ptr_high; |
| 54690 | #else |
| 54691 | duk_hstring **new_ptr; |
| 54692 | duk_hstring **new_ptr_high; |
| 54693 | #endif |
| 54694 | |
| 54695 | DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu" , (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); |
| 54696 | |
| 54697 | DUK_ASSERT(heap != NULL); |
| 54698 | DUK_ASSERT(heap->st_resizing == 1); |
| 54699 | DUK_ASSERT(heap->st_size >= 2); |
| 54700 | DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ |
| 54701 | DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); |
| 54702 | |
| 54703 | DUK_STATS_INC(heap, stats_strtab_resize_grow); |
| 54704 | |
| 54705 | new_st_size = heap->st_size << 1U; |
| 54706 | DUK_ASSERT(new_st_size > heap->st_size); /* No overflow. */ |
| 54707 | |
| 54708 | /* Reallocate the strtable first and then work in-place to rehash |
| 54709 | * strings. We don't need an indirect allocation here: even if GC |
| 54710 | * is triggered to satisfy the allocation, recursive strtable resize |
| 54711 | * is prevented by flags. This is also why we don't need to use |
| 54712 | * DUK_REALLOC_INDIRECT(). |
| 54713 | */ |
| 54714 | |
| 54715 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54716 | new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); |
| 54717 | #else |
| 54718 | new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); |
| 54719 | #endif |
| 54720 | if (DUK_UNLIKELY(new_ptr == NULL)) { |
| 54721 | /* If realloc fails we can continue normally: the string table |
| 54722 | * won't "fill up" although chains will gradually get longer. |
| 54723 | * When string insertions continue, we'll quite soon try again |
| 54724 | * with no special handling. |
| 54725 | */ |
| 54726 | DUK_D(DUK_DPRINT("string table grow failed, ignoring" )); |
| 54727 | return; |
| 54728 | } |
| 54729 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54730 | heap->strtable16 = new_ptr; |
| 54731 | #else |
| 54732 | heap->strtable = new_ptr; |
| 54733 | #endif |
| 54734 | |
| 54735 | /* Rehash a single bucket into two separate ones. When we grow |
| 54736 | * by x2 the highest 'new' bit determines whether a string remains |
| 54737 | * in its old position (bit is 0) or goes to a new one (bit is 1). |
| 54738 | */ |
| 54739 | |
| 54740 | old_st_size = heap->st_size; |
| 54741 | new_ptr_high = new_ptr + old_st_size; |
| 54742 | for (i = 0; i < old_st_size; i++) { |
| 54743 | duk_hstring *new_root; |
| 54744 | duk_hstring *new_root_high; |
| 54745 | |
| 54746 | h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]); |
| 54747 | new_root = h; |
| 54748 | new_root_high = NULL; |
| 54749 | |
| 54750 | prev = NULL; |
| 54751 | while (h != NULL) { |
| 54752 | duk_uint32_t mask; |
| 54753 | |
| 54754 | DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i); |
| 54755 | next = h->hdr.h_next; |
| 54756 | |
| 54757 | /* Example: if previous size was 256, previous mask is 0xFF |
| 54758 | * and size is 0x100 which corresponds to the new bit that |
| 54759 | * comes into play. |
| 54760 | */ |
| 54761 | DUK_ASSERT(heap->st_mask == old_st_size - 1); |
| 54762 | mask = old_st_size; |
| 54763 | if (DUK_HSTRING_GET_HASH(h) & mask) { |
| 54764 | if (prev != NULL) { |
| 54765 | prev->hdr.h_next = h->hdr.h_next; |
| 54766 | } else { |
| 54767 | DUK_ASSERT(h == new_root); |
| 54768 | new_root = h->hdr.h_next; |
| 54769 | } |
| 54770 | |
| 54771 | h->hdr.h_next = new_root_high; |
| 54772 | new_root_high = h; |
| 54773 | } else { |
| 54774 | prev = h; |
| 54775 | } |
| 54776 | h = next; |
| 54777 | } |
| 54778 | |
| 54779 | new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root); |
| 54780 | new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high); |
| 54781 | } |
| 54782 | |
| 54783 | heap->st_size = new_st_size; |
| 54784 | heap->st_mask = new_st_size - 1; |
| 54785 | |
| 54786 | #if defined(DUK_USE_ASSERTIONS) |
| 54787 | duk__strtable_assert_checks(heap); |
| 54788 | #endif |
| 54789 | } |
| 54790 | #endif /* DUK__STRTAB_RESIZE_CHECK */ |
| 54791 | |
| 54792 | /* |
| 54793 | * Shrink strtable allocation in-place. |
| 54794 | */ |
| 54795 | |
| 54796 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 54797 | DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) { |
| 54798 | duk_uint32_t new_st_size; |
| 54799 | duk_uint32_t i; |
| 54800 | duk_hstring *h; |
| 54801 | duk_hstring *other; |
| 54802 | duk_hstring *root; |
| 54803 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54804 | duk_uint16_t *old_ptr; |
| 54805 | duk_uint16_t *old_ptr_high; |
| 54806 | duk_uint16_t *new_ptr; |
| 54807 | #else |
| 54808 | duk_hstring **old_ptr; |
| 54809 | duk_hstring **old_ptr_high; |
| 54810 | duk_hstring **new_ptr; |
| 54811 | #endif |
| 54812 | |
| 54813 | DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu" , (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); |
| 54814 | |
| 54815 | DUK_ASSERT(heap != NULL); |
| 54816 | DUK_ASSERT(heap->st_resizing == 1); |
| 54817 | DUK_ASSERT(heap->st_size >= 2); |
| 54818 | DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0); /* 2^N */ |
| 54819 | DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); |
| 54820 | |
| 54821 | DUK_STATS_INC(heap, stats_strtab_resize_shrink); |
| 54822 | |
| 54823 | new_st_size = heap->st_size >> 1U; |
| 54824 | |
| 54825 | /* Combine two buckets into a single one. When we shrink, one hash |
| 54826 | * bit (highest) disappears. |
| 54827 | */ |
| 54828 | old_ptr = DUK__GET_STRTABLE(heap); |
| 54829 | old_ptr_high = old_ptr + new_st_size; |
| 54830 | for (i = 0; i < new_st_size; i++) { |
| 54831 | h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]); |
| 54832 | other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]); |
| 54833 | |
| 54834 | if (h == NULL) { |
| 54835 | /* First chain is empty, so use second one as is. */ |
| 54836 | root = other; |
| 54837 | } else { |
| 54838 | /* Find end of first chain, and link in the second. */ |
| 54839 | root = h; |
| 54840 | while (h->hdr.h_next != NULL) { |
| 54841 | h = h->hdr.h_next; |
| 54842 | } |
| 54843 | h->hdr.h_next = other; |
| 54844 | } |
| 54845 | |
| 54846 | old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root); |
| 54847 | } |
| 54848 | |
| 54849 | heap->st_size = new_st_size; |
| 54850 | heap->st_mask = new_st_size - 1; |
| 54851 | |
| 54852 | /* The strtable is now consistent and we can realloc safely. Even |
| 54853 | * if side effects cause string interning or removal the strtable |
| 54854 | * updates are safe. Recursive resize has been prevented by caller. |
| 54855 | * This is also why we don't need to use DUK_REALLOC_INDIRECT(). |
| 54856 | * |
| 54857 | * We assume a realloc() to a smaller size is guaranteed to succeed. |
| 54858 | * It would be relatively straightforward to handle the error by |
| 54859 | * essentially performing a "grow" step to recover. |
| 54860 | */ |
| 54861 | |
| 54862 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54863 | new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size); |
| 54864 | DUK_ASSERT(new_ptr != NULL); |
| 54865 | heap->strtable16 = new_ptr; |
| 54866 | #else |
| 54867 | new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size); |
| 54868 | DUK_ASSERT(new_ptr != NULL); |
| 54869 | heap->strtable = new_ptr; |
| 54870 | #endif |
| 54871 | |
| 54872 | #if defined(DUK_USE_ASSERTIONS) |
| 54873 | duk__strtable_assert_checks(heap); |
| 54874 | #endif |
| 54875 | } |
| 54876 | #endif /* DUK__STRTAB_RESIZE_CHECK */ |
| 54877 | |
| 54878 | /* |
| 54879 | * Grow/shrink check. |
| 54880 | */ |
| 54881 | |
| 54882 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 54883 | DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) { |
| 54884 | duk_uint32_t load_factor; /* fixed point */ |
| 54885 | |
| 54886 | DUK_ASSERT(heap != NULL); |
| 54887 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54888 | DUK_ASSERT(heap->strtable16 != NULL); |
| 54889 | #else |
| 54890 | DUK_ASSERT(heap->strtable != NULL); |
| 54891 | #endif |
| 54892 | |
| 54893 | DUK_STATS_INC(heap, stats_strtab_resize_check); |
| 54894 | |
| 54895 | /* Prevent recursive resizing. */ |
| 54896 | if (DUK_UNLIKELY(heap->st_resizing != 0U)) { |
| 54897 | DUK_D(DUK_DPRINT("prevent recursive strtable resize" )); |
| 54898 | return; |
| 54899 | } |
| 54900 | |
| 54901 | heap->st_resizing = 1; |
| 54902 | |
| 54903 | DUK_ASSERT(heap->st_size >= 16U); |
| 54904 | DUK_ASSERT((heap->st_size >> 4U) >= 1); |
| 54905 | load_factor = heap->st_count / (heap->st_size >> 4U); |
| 54906 | |
| 54907 | DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)" , |
| 54908 | (unsigned long) heap->st_size, (unsigned long) heap->st_count, |
| 54909 | (unsigned long) load_factor, |
| 54910 | (double) heap->st_count / (double) heap->st_size)); |
| 54911 | |
| 54912 | if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) { |
| 54913 | if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) { |
| 54914 | DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size" )); |
| 54915 | } else { |
| 54916 | DUK_D(DUK_DPRINT("grow string table: %lu -> %lu" , (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2)); |
| 54917 | #if defined(DUK_USE_DEBUG) |
| 54918 | duk_heap_strtable_dump(heap); |
| 54919 | #endif |
| 54920 | duk__strtable_grow_inplace(heap); |
| 54921 | } |
| 54922 | } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) { |
| 54923 | if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) { |
| 54924 | DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size" )); |
| 54925 | } else { |
| 54926 | DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu" , (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2)); |
| 54927 | #if defined(DUK_USE_DEBUG) |
| 54928 | duk_heap_strtable_dump(heap); |
| 54929 | #endif |
| 54930 | duk__strtable_shrink_inplace(heap); |
| 54931 | } |
| 54932 | } else { |
| 54933 | DUK_DD(DUK_DDPRINT("no need for strtable resize" )); |
| 54934 | } |
| 54935 | |
| 54936 | heap->st_resizing = 0; |
| 54937 | } |
| 54938 | #endif /* DUK__STRTAB_RESIZE_CHECK */ |
| 54939 | |
| 54940 | /* |
| 54941 | * Torture grow/shrink: unconditionally grow and shrink back. |
| 54942 | */ |
| 54943 | |
| 54944 | #if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) |
| 54945 | DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) { |
| 54946 | duk_uint32_t old_st_size; |
| 54947 | |
| 54948 | DUK_ASSERT(heap != NULL); |
| 54949 | |
| 54950 | old_st_size = heap->st_size; |
| 54951 | if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) { |
| 54952 | return; |
| 54953 | } |
| 54954 | |
| 54955 | heap->st_resizing = 1; |
| 54956 | duk__strtable_grow_inplace(heap); |
| 54957 | if (heap->st_size > old_st_size) { |
| 54958 | duk__strtable_shrink_inplace(heap); |
| 54959 | } |
| 54960 | heap->st_resizing = 0; |
| 54961 | } |
| 54962 | #endif /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */ |
| 54963 | |
| 54964 | /* |
| 54965 | * Raw intern; string already checked not to be present. |
| 54966 | */ |
| 54967 | |
| 54968 | DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { |
| 54969 | duk_hstring *res; |
| 54970 | const duk_uint8_t *extdata; |
| 54971 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 54972 | duk_uint16_t *slot; |
| 54973 | #else |
| 54974 | duk_hstring **slot; |
| 54975 | #endif |
| 54976 | |
| 54977 | DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf" , |
| 54978 | (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash, |
| 54979 | (unsigned long) heap->st_size, (unsigned long) heap->st_count, |
| 54980 | (double) heap->st_count / (double) heap->st_size)); |
| 54981 | |
| 54982 | DUK_ASSERT(heap != NULL); |
| 54983 | |
| 54984 | /* Prevent any side effects on the string table and the caller provided |
| 54985 | * str/blen arguments while interning is in progress. For example, if |
| 54986 | * the caller provided str/blen from a dynamic buffer, a finalizer |
| 54987 | * might resize or modify that dynamic buffer, invalidating the call |
| 54988 | * arguments. |
| 54989 | * |
| 54990 | * While finalizers must be prevented, mark-and-sweep itself is fine. |
| 54991 | * Recursive string table resize is prevented explicitly here. |
| 54992 | */ |
| 54993 | |
| 54994 | heap->pf_prevent_count++; |
| 54995 | DUK_ASSERT(heap->pf_prevent_count != 0); /* Wrap. */ |
| 54996 | |
| 54997 | #if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK) |
| 54998 | duk__strtable_resize_torture(heap); |
| 54999 | #endif |
| 55000 | |
| 55001 | /* String table grow/shrink check. Because of chaining (and no |
| 55002 | * accumulation issues as with hash probe chains and DELETED |
| 55003 | * markers) there's never a mandatory need to resize right now. |
| 55004 | * Check for the resize only periodically, based on st_count |
| 55005 | * bit pattern. Because string table removal doesn't do a shrink |
| 55006 | * check, we do that also here. |
| 55007 | * |
| 55008 | * Do the resize and possible grow/shrink before the new duk_hstring |
| 55009 | * has been allocated. Otherwise we may trigger a GC when the result |
| 55010 | * duk_hstring is not yet strongly referenced. |
| 55011 | */ |
| 55012 | |
| 55013 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 55014 | if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) { |
| 55015 | duk__strtable_resize_check(heap); |
| 55016 | } |
| 55017 | #endif |
| 55018 | |
| 55019 | /* External string check (low memory optimization). */ |
| 55020 | |
| 55021 | #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) |
| 55022 | extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); |
| 55023 | #else |
| 55024 | extdata = (const duk_uint8_t *) NULL; |
| 55025 | #endif |
| 55026 | |
| 55027 | /* Allocate and initialize string, not yet linked. This may cause a |
| 55028 | * GC which may cause other strings to be interned and inserted into |
| 55029 | * the string table before we insert our string. Finalizer execution |
| 55030 | * is disabled intentionally to avoid a finalizer from e.g. resizing |
| 55031 | * a buffer used as a data area for 'str'. |
| 55032 | */ |
| 55033 | |
| 55034 | res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata); |
| 55035 | |
| 55036 | /* Allow side effects again: GC must be avoided until duk_hstring |
| 55037 | * result (if successful) has been INCREF'd. |
| 55038 | */ |
| 55039 | DUK_ASSERT(heap->pf_prevent_count > 0); |
| 55040 | heap->pf_prevent_count--; |
| 55041 | |
| 55042 | /* Alloc error handling. */ |
| 55043 | |
| 55044 | if (DUK_UNLIKELY(res == NULL)) { |
| 55045 | #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) |
| 55046 | if (extdata != NULL) { |
| 55047 | DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata); |
| 55048 | } |
| 55049 | #endif |
| 55050 | return NULL; |
| 55051 | } |
| 55052 | |
| 55053 | /* Insert into string table. */ |
| 55054 | |
| 55055 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55056 | slot = heap->strtable16 + (strhash & heap->st_mask); |
| 55057 | #else |
| 55058 | slot = heap->strtable + (strhash & heap->st_mask); |
| 55059 | #endif |
| 55060 | DUK_ASSERT(res->hdr.h_next == NULL); /* This is the case now, but unnecessary zeroing/NULLing. */ |
| 55061 | res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot); |
| 55062 | *slot = DUK__HEAPPTR_ENC16(heap, res); |
| 55063 | |
| 55064 | /* Update string count only for successful inserts. */ |
| 55065 | |
| 55066 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 55067 | heap->st_count++; |
| 55068 | #endif |
| 55069 | |
| 55070 | /* The duk_hstring is in the string table but is not yet strongly |
| 55071 | * reachable. Calling code MUST NOT make any allocations or other |
| 55072 | * side effects before the duk_hstring has been INCREF'd and made |
| 55073 | * reachable. |
| 55074 | */ |
| 55075 | |
| 55076 | return res; |
| 55077 | } |
| 55078 | |
| 55079 | /* |
| 55080 | * Intern a string from str/blen, returning either an existing duk_hstring |
| 55081 | * or adding a new one into the string table. The input string does -not- |
| 55082 | * need to be NUL terminated. |
| 55083 | * |
| 55084 | * The input 'str' argument may point to a Duktape managed data area such as |
| 55085 | * the data area of a dynamic buffer. It's crucial to avoid any side effects |
| 55086 | * that might affect the data area (e.g. resize the dynamic buffer, or write |
| 55087 | * to the buffer) before the string is fully interned. |
| 55088 | */ |
| 55089 | |
| 55090 | #if defined(DUK_USE_ROM_STRINGS) |
| 55091 | DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) { |
| 55092 | duk_size_t lookup_hash; |
| 55093 | duk_hstring *curr; |
| 55094 | |
| 55095 | DUK_ASSERT(heap != NULL); |
| 55096 | DUK_UNREF(heap); |
| 55097 | |
| 55098 | lookup_hash = (blen << 4); |
| 55099 | if (blen > 0) { |
| 55100 | lookup_hash += str[0]; |
| 55101 | } |
| 55102 | lookup_hash &= 0xff; |
| 55103 | |
| 55104 | curr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]); |
| 55105 | while (curr != NULL) { |
| 55106 | /* Unsafe memcmp() because for zero blen, str may be NULL. */ |
| 55107 | if (strhash == DUK_HSTRING_GET_HASH(curr) && |
| 55108 | blen == DUK_HSTRING_GET_BYTELEN(curr) && |
| 55109 | duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) { |
| 55110 | DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx" , |
| 55111 | curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr))); |
| 55112 | return curr; |
| 55113 | } |
| 55114 | curr = curr->hdr.h_next; |
| 55115 | } |
| 55116 | |
| 55117 | return NULL; |
| 55118 | } |
| 55119 | #endif /* DUK_USE_ROM_STRINGS */ |
| 55120 | |
| 55121 | DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) { |
| 55122 | duk_uint32_t strhash; |
| 55123 | duk_hstring *h; |
| 55124 | |
| 55125 | DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu" , (void *) heap, (const void *) str, (unsigned long) blen)); |
| 55126 | |
| 55127 | /* Preliminaries. */ |
| 55128 | |
| 55129 | /* XXX: maybe just require 'str != NULL' even for zero size? */ |
| 55130 | DUK_ASSERT(heap != NULL); |
| 55131 | DUK_ASSERT(blen == 0 || str != NULL); |
| 55132 | DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN); /* Caller is responsible for ensuring this. */ |
| 55133 | strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen); |
| 55134 | |
| 55135 | /* String table lookup. */ |
| 55136 | |
| 55137 | DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL); |
| 55138 | DUK_ASSERT(heap->st_size > 0); |
| 55139 | DUK_ASSERT(heap->st_size == heap->st_mask + 1); |
| 55140 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55141 | h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]); |
| 55142 | #else |
| 55143 | h = heap->strtable[strhash & heap->st_mask]; |
| 55144 | #endif |
| 55145 | while (h != NULL) { |
| 55146 | if (DUK_HSTRING_GET_HASH(h) == strhash && |
| 55147 | DUK_HSTRING_GET_BYTELEN(h) == blen && |
| 55148 | duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) { |
| 55149 | /* Found existing entry. */ |
| 55150 | DUK_STATS_INC(heap, stats_strtab_intern_hit); |
| 55151 | return h; |
| 55152 | } |
| 55153 | h = h->hdr.h_next; |
| 55154 | } |
| 55155 | |
| 55156 | /* ROM table lookup. Because this lookup is slower, do it only after |
| 55157 | * RAM lookup. This works because no ROM string is ever interned into |
| 55158 | * the RAM string table. |
| 55159 | */ |
| 55160 | |
| 55161 | #if defined(DUK_USE_ROM_STRINGS) |
| 55162 | h = duk__strtab_romstring_lookup(heap, str, blen, strhash); |
| 55163 | if (h != NULL) { |
| 55164 | DUK_STATS_INC(heap, stats_strtab_intern_hit); |
| 55165 | return h; |
| 55166 | } |
| 55167 | #endif |
| 55168 | |
| 55169 | /* Not found in string table; insert. */ |
| 55170 | |
| 55171 | DUK_STATS_INC(heap, stats_strtab_intern_miss); |
| 55172 | h = duk__strtable_do_intern(heap, str, blen, strhash); |
| 55173 | return h; /* may be NULL */ |
| 55174 | } |
| 55175 | |
| 55176 | /* |
| 55177 | * Intern a string from u32. |
| 55178 | */ |
| 55179 | |
| 55180 | /* XXX: Could arrange some special handling because we know that the result |
| 55181 | * will have an arridx flag and an ASCII flag, won't need a clen check, etc. |
| 55182 | */ |
| 55183 | |
| 55184 | DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) { |
| 55185 | duk_uint8_t buf[DUK__STRTAB_U32_MAX_STRLEN]; |
| 55186 | duk_uint8_t *p; |
| 55187 | |
| 55188 | DUK_ASSERT(heap != NULL); |
| 55189 | |
| 55190 | /* This is smaller and faster than a %lu sprintf. */ |
| 55191 | p = buf + sizeof(buf); |
| 55192 | do { |
| 55193 | p--; |
| 55194 | *p = duk_lc_digits[val % 10]; |
| 55195 | val = val / 10; |
| 55196 | } while (val != 0); /* For val == 0, emit exactly one '0'. */ |
| 55197 | DUK_ASSERT(p >= buf); |
| 55198 | |
| 55199 | return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p)); |
| 55200 | } |
| 55201 | |
| 55202 | /* |
| 55203 | * Checked convenience variants. |
| 55204 | * |
| 55205 | * XXX: Because the main use case is for the checked variants, make them the |
| 55206 | * main functionality and provide a safe variant separately (it is only needed |
| 55207 | * during heap init). The problem with that is that longjmp state and error |
| 55208 | * creation must already be possible to throw. |
| 55209 | */ |
| 55210 | |
| 55211 | DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { |
| 55212 | duk_hstring *res; |
| 55213 | |
| 55214 | DUK_ASSERT(thr != NULL); |
| 55215 | DUK_ASSERT(thr->heap != NULL); |
| 55216 | DUK_ASSERT(blen == 0 || str != NULL); |
| 55217 | |
| 55218 | res = duk_heap_strtable_intern(thr->heap, str, blen); |
| 55219 | if (DUK_UNLIKELY(res == NULL)) { |
| 55220 | DUK_ERROR_ALLOC_FAILED(thr); |
| 55221 | DUK_WO_NORETURN(return NULL;); |
| 55222 | } |
| 55223 | return res; |
| 55224 | } |
| 55225 | |
| 55226 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 55227 | DUK_LOCAL duk_uint_t duk__strtable_litcache_key(const duk_uint8_t *str, duk_uint32_t blen) { |
| 55228 | duk_uintptr_t key; |
| 55229 | |
| 55230 | DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0); |
| 55231 | DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE)); |
| 55232 | |
| 55233 | key = (duk_uintptr_t) blen ^ (duk_uintptr_t) str; |
| 55234 | key &= (duk_uintptr_t) (DUK_USE_LITCACHE_SIZE - 1); /* Assumes size is power of 2. */ |
| 55235 | /* Due to masking, cast is in 32-bit range. */ |
| 55236 | DUK_ASSERT(key <= DUK_UINT_MAX); |
| 55237 | return (duk_uint_t) key; |
| 55238 | } |
| 55239 | |
| 55240 | DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) { |
| 55241 | duk_uint_t key; |
| 55242 | duk_litcache_entry *ent; |
| 55243 | duk_hstring *h; |
| 55244 | |
| 55245 | /* Fast path check: literal exists in literal cache. */ |
| 55246 | key = duk__strtable_litcache_key(str, blen); |
| 55247 | ent = thr->heap->litcache + key; |
| 55248 | if (ent->addr == str) { |
| 55249 | DUK_DD(DUK_DDPRINT("intern check for cached, pinned literal: str=%p, blen=%ld -> duk_hstring %!O" , |
| 55250 | (const void *) str, (long) blen, (duk_heaphdr *) ent->h)); |
| 55251 | DUK_ASSERT(ent->h != NULL); |
| 55252 | DUK_ASSERT(DUK_HSTRING_HAS_PINNED_LITERAL(ent->h)); |
| 55253 | DUK_STATS_INC(thr->heap, stats_strtab_litcache_hit); |
| 55254 | return ent->h; |
| 55255 | } |
| 55256 | |
| 55257 | /* Intern and update (overwrite) cache entry. */ |
| 55258 | h = duk_heap_strtable_intern_checked(thr, str, blen); |
| 55259 | ent->addr = str; |
| 55260 | ent->h = h; |
| 55261 | DUK_STATS_INC(thr->heap, stats_strtab_litcache_miss); |
| 55262 | |
| 55263 | /* Pin the duk_hstring until the next mark-and-sweep. This means |
| 55264 | * litcache entries don't need to be invalidated until the next |
| 55265 | * mark-and-sweep as their target duk_hstring is not freed before |
| 55266 | * the mark-and-sweep happens. The pin remains even if the literal |
| 55267 | * cache entry is overwritten, and is still useful to avoid string |
| 55268 | * table traffic. |
| 55269 | */ |
| 55270 | if (!DUK_HSTRING_HAS_PINNED_LITERAL(h)) { |
| 55271 | DUK_DD(DUK_DDPRINT("pin duk_hstring because it is a literal: %!O" , (duk_heaphdr *) h)); |
| 55272 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); |
| 55273 | DUK_HSTRING_INCREF(thr, h); |
| 55274 | DUK_HSTRING_SET_PINNED_LITERAL(h); |
| 55275 | DUK_STATS_INC(thr->heap, stats_strtab_litcache_pin); |
| 55276 | } |
| 55277 | |
| 55278 | return h; |
| 55279 | } |
| 55280 | #endif /* DUK_USE_LITCACHE_SIZE */ |
| 55281 | |
| 55282 | DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) { |
| 55283 | duk_hstring *res; |
| 55284 | |
| 55285 | DUK_ASSERT(thr != NULL); |
| 55286 | DUK_ASSERT(thr->heap != NULL); |
| 55287 | |
| 55288 | res = duk_heap_strtable_intern_u32(thr->heap, val); |
| 55289 | if (DUK_UNLIKELY(res == NULL)) { |
| 55290 | DUK_ERROR_ALLOC_FAILED(thr); |
| 55291 | DUK_WO_NORETURN(return NULL;); |
| 55292 | } |
| 55293 | return res; |
| 55294 | } |
| 55295 | |
| 55296 | /* |
| 55297 | * Remove (unlink) a string from the string table. |
| 55298 | * |
| 55299 | * Just unlinks the duk_hstring, leaving link pointers as garbage. |
| 55300 | * Caller must free the string itself. |
| 55301 | */ |
| 55302 | |
| 55303 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 55304 | /* Unlink without a 'prev' pointer. */ |
| 55305 | DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) { |
| 55306 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55307 | duk_uint16_t *slot; |
| 55308 | #else |
| 55309 | duk_hstring **slot; |
| 55310 | #endif |
| 55311 | duk_hstring *other; |
| 55312 | duk_hstring *prev; |
| 55313 | |
| 55314 | DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx" , |
| 55315 | (void *) heap, (void *) h, |
| 55316 | (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), |
| 55317 | (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); |
| 55318 | |
| 55319 | DUK_ASSERT(heap != NULL); |
| 55320 | DUK_ASSERT(h != NULL); |
| 55321 | |
| 55322 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 55323 | DUK_ASSERT(heap->st_count > 0); |
| 55324 | heap->st_count--; |
| 55325 | #endif |
| 55326 | |
| 55327 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55328 | slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); |
| 55329 | #else |
| 55330 | slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); |
| 55331 | #endif |
| 55332 | other = DUK__HEAPPTR_DEC16(heap, *slot); |
| 55333 | DUK_ASSERT(other != NULL); /* At least argument string is in the chain. */ |
| 55334 | |
| 55335 | prev = NULL; |
| 55336 | while (other != h) { |
| 55337 | prev = other; |
| 55338 | other = other->hdr.h_next; |
| 55339 | DUK_ASSERT(other != NULL); /* We'll eventually find 'h'. */ |
| 55340 | } |
| 55341 | if (prev != NULL) { |
| 55342 | /* Middle of list. */ |
| 55343 | prev->hdr.h_next = h->hdr.h_next; |
| 55344 | } else { |
| 55345 | /* Head of list. */ |
| 55346 | *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); |
| 55347 | } |
| 55348 | |
| 55349 | /* There's no resize check on a string free. The next string |
| 55350 | * intern will do one. |
| 55351 | */ |
| 55352 | } |
| 55353 | #endif /* DUK_USE_REFERENCE_COUNTING */ |
| 55354 | |
| 55355 | /* Unlink with a 'prev' pointer. */ |
| 55356 | DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) { |
| 55357 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55358 | duk_uint16_t *slot; |
| 55359 | #else |
| 55360 | duk_hstring **slot; |
| 55361 | #endif |
| 55362 | |
| 55363 | DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx" , |
| 55364 | (void *) heap, (void *) prev, (void *) h, |
| 55365 | (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0), |
| 55366 | (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0))); |
| 55367 | |
| 55368 | DUK_ASSERT(heap != NULL); |
| 55369 | DUK_ASSERT(h != NULL); |
| 55370 | DUK_ASSERT(prev == NULL || prev->hdr.h_next == h); |
| 55371 | |
| 55372 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 55373 | DUK_ASSERT(heap->st_count > 0); |
| 55374 | heap->st_count--; |
| 55375 | #endif |
| 55376 | |
| 55377 | if (prev != NULL) { |
| 55378 | /* Middle of list. */ |
| 55379 | prev->hdr.h_next = h->hdr.h_next; |
| 55380 | } else { |
| 55381 | /* Head of list. */ |
| 55382 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55383 | slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); |
| 55384 | #else |
| 55385 | slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask); |
| 55386 | #endif |
| 55387 | DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h); |
| 55388 | *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next); |
| 55389 | } |
| 55390 | } |
| 55391 | |
| 55392 | /* |
| 55393 | * Force string table resize check in mark-and-sweep. |
| 55394 | */ |
| 55395 | |
| 55396 | DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) { |
| 55397 | /* Does only one grow/shrink step if needed. The heap->st_resizing |
| 55398 | * flag protects against recursive resizing. |
| 55399 | */ |
| 55400 | |
| 55401 | DUK_ASSERT(heap != NULL); |
| 55402 | DUK_UNREF(heap); |
| 55403 | |
| 55404 | #if defined(DUK__STRTAB_RESIZE_CHECK) |
| 55405 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55406 | if (heap->strtable16 != NULL) { |
| 55407 | #else |
| 55408 | if (heap->strtable != NULL) { |
| 55409 | #endif |
| 55410 | duk__strtable_resize_check(heap); |
| 55411 | } |
| 55412 | #endif |
| 55413 | } |
| 55414 | |
| 55415 | /* |
| 55416 | * Free strings in the string table and the string table itself. |
| 55417 | */ |
| 55418 | |
| 55419 | DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) { |
| 55420 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 55421 | duk_uint16_t *strtable; |
| 55422 | duk_uint16_t *st; |
| 55423 | #else |
| 55424 | duk_hstring **strtable; |
| 55425 | duk_hstring **st; |
| 55426 | #endif |
| 55427 | duk_hstring *h; |
| 55428 | |
| 55429 | DUK_ASSERT(heap != NULL); |
| 55430 | |
| 55431 | #if defined(DUK_USE_ASSERTIONS) |
| 55432 | duk__strtable_assert_checks(heap); |
| 55433 | #endif |
| 55434 | |
| 55435 | /* Strtable can be NULL if heap init fails. However, in that case |
| 55436 | * heap->st_size is 0, so strtable == strtable_end and we skip the |
| 55437 | * loop without a special check. |
| 55438 | */ |
| 55439 | strtable = DUK__GET_STRTABLE(heap); |
| 55440 | st = strtable + heap->st_size; |
| 55441 | DUK_ASSERT(strtable != NULL || heap->st_size == 0); |
| 55442 | |
| 55443 | while (strtable != st) { |
| 55444 | --st; |
| 55445 | h = DUK__HEAPPTR_DEC16(heap, *st); |
| 55446 | while (h) { |
| 55447 | duk_hstring *h_next; |
| 55448 | h_next = h->hdr.h_next; |
| 55449 | |
| 55450 | /* Strings may have inner refs (extdata) in some cases. */ |
| 55451 | duk_free_hstring(heap, h); |
| 55452 | |
| 55453 | h = h_next; |
| 55454 | } |
| 55455 | } |
| 55456 | |
| 55457 | DUK_FREE(heap, strtable); |
| 55458 | } |
| 55459 | |
| 55460 | /* automatic undefs */ |
| 55461 | #undef DUK__GET_STRTABLE |
| 55462 | #undef DUK__HEAPPTR_DEC16 |
| 55463 | #undef DUK__HEAPPTR_ENC16 |
| 55464 | #undef DUK__STRTAB_U32_MAX_STRLEN |
| 55465 | #line 1 "duk_heaphdr_assert.c" |
| 55466 | /* |
| 55467 | * duk_heaphdr assertion helpers |
| 55468 | */ |
| 55469 | |
| 55470 | /* #include duk_internal.h -> already included */ |
| 55471 | |
| 55472 | #if defined(DUK_USE_ASSERTIONS) |
| 55473 | |
| 55474 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 55475 | DUK_INTERNAL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h) { |
| 55476 | DUK_UNREF(heap); |
| 55477 | if (h != NULL) { |
| 55478 | duk_heaphdr *h_prev, *h_next; |
| 55479 | h_prev = DUK_HEAPHDR_GET_PREV(heap, h); |
| 55480 | h_next = DUK_HEAPHDR_GET_NEXT(heap, h); |
| 55481 | DUK_ASSERT(h_prev == NULL || (DUK_HEAPHDR_GET_NEXT(heap, h_prev) == h)); |
| 55482 | DUK_ASSERT(h_next == NULL || (DUK_HEAPHDR_GET_PREV(heap, h_next) == h)); |
| 55483 | } |
| 55484 | } |
| 55485 | #else |
| 55486 | DUK_INTERNAL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h) { |
| 55487 | DUK_UNREF(heap); |
| 55488 | DUK_UNREF(h); |
| 55489 | } |
| 55490 | #endif |
| 55491 | |
| 55492 | DUK_INTERNAL void duk_heaphdr_assert_valid(duk_heaphdr *h) { |
| 55493 | DUK_ASSERT(h != NULL); |
| 55494 | DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h)); |
| 55495 | } |
| 55496 | |
| 55497 | /* Assert validity of a heaphdr, including all subclasses. */ |
| 55498 | DUK_INTERNAL void duk_heaphdr_assert_valid_subclassed(duk_heaphdr *h) { |
| 55499 | switch (DUK_HEAPHDR_GET_TYPE(h)) { |
| 55500 | case DUK_HTYPE_OBJECT: { |
| 55501 | duk_hobject *h_obj = (duk_hobject *) h; |
| 55502 | DUK_HOBJECT_ASSERT_VALID(h_obj); |
| 55503 | if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) { |
| 55504 | DUK_HCOMPFUNC_ASSERT_VALID((duk_hcompfunc *) h_obj); |
| 55505 | } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) { |
| 55506 | DUK_HNATFUNC_ASSERT_VALID((duk_hnatfunc *) h_obj); |
| 55507 | } else if (DUK_HOBJECT_IS_DECENV(h_obj)) { |
| 55508 | DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) h_obj); |
| 55509 | } else if (DUK_HOBJECT_IS_OBJENV(h_obj)) { |
| 55510 | DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) h_obj); |
| 55511 | } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) { |
| 55512 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 55513 | DUK_HBUFOBJ_ASSERT_VALID((duk_hbufobj *) h_obj); |
| 55514 | #endif |
| 55515 | } else if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) { |
| 55516 | DUK_HBOUNDFUNC_ASSERT_VALID((duk_hboundfunc *) h_obj); |
| 55517 | } else if (DUK_HOBJECT_IS_PROXY(h_obj)) { |
| 55518 | DUK_HPROXY_ASSERT_VALID((duk_hproxy *) h_obj); |
| 55519 | } else if (DUK_HOBJECT_IS_THREAD(h_obj)) { |
| 55520 | DUK_HTHREAD_ASSERT_VALID((duk_hthread *) h_obj); |
| 55521 | } else { |
| 55522 | /* Just a plain object. */ |
| 55523 | ; |
| 55524 | } |
| 55525 | break; |
| 55526 | } |
| 55527 | case DUK_HTYPE_STRING: { |
| 55528 | duk_hstring *h_str = (duk_hstring *) h; |
| 55529 | DUK_HSTRING_ASSERT_VALID(h_str); |
| 55530 | break; |
| 55531 | } |
| 55532 | case DUK_HTYPE_BUFFER: { |
| 55533 | duk_hbuffer *h_buf = (duk_hbuffer *) h; |
| 55534 | DUK_HBUFFER_ASSERT_VALID(h_buf); |
| 55535 | break; |
| 55536 | } |
| 55537 | default: { |
| 55538 | DUK_ASSERT(0); |
| 55539 | } |
| 55540 | } |
| 55541 | } |
| 55542 | |
| 55543 | #endif /* DUK_USE_ASSERTIONS */ |
| 55544 | #line 1 "duk_hobject_alloc.c" |
| 55545 | /* |
| 55546 | * Hobject allocation. |
| 55547 | * |
| 55548 | * Provides primitive allocation functions for all object types (plain object, |
| 55549 | * compiled function, native function, thread). The object return is not yet |
| 55550 | * in "heap allocated" list and has a refcount of zero, so caller must careful. |
| 55551 | */ |
| 55552 | |
| 55553 | /* XXX: In most cases there's no need for plain allocation without pushing |
| 55554 | * to the value stack. Maybe rework contract? |
| 55555 | */ |
| 55556 | |
| 55557 | /* #include duk_internal.h -> already included */ |
| 55558 | |
| 55559 | /* |
| 55560 | * Helpers. |
| 55561 | */ |
| 55562 | |
| 55563 | DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_uint_t hobject_flags, duk_hobject *obj) { |
| 55564 | DUK_ASSERT(obj != NULL); |
| 55565 | /* Zeroed by caller. */ |
| 55566 | |
| 55567 | obj->hdr.h_flags = hobject_flags | DUK_HTYPE_OBJECT; |
| 55568 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(&obj->hdr) == DUK_HTYPE_OBJECT); /* Assume zero shift. */ |
| 55569 | |
| 55570 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55571 | DUK_HOBJECT_SET_PROTOTYPE(heap, obj, NULL); |
| 55572 | DUK_HOBJECT_SET_PROPS(heap, obj, NULL); |
| 55573 | #endif |
| 55574 | #if defined(DUK_USE_HEAPPTR16) |
| 55575 | /* Zero encoded pointer is required to match NULL. */ |
| 55576 | DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL); |
| 55577 | #if defined(DUK_USE_DOUBLE_LINKED_HEAP) |
| 55578 | DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL); |
| 55579 | #endif |
| 55580 | #endif |
| 55581 | DUK_HEAPHDR_ASSERT_LINKS(heap, &obj->hdr); |
| 55582 | DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr); |
| 55583 | |
| 55584 | /* obj->props is intentionally left as NULL, and duk_hobject_props.c must deal |
| 55585 | * with this properly. This is intentional: empty objects consume a minimum |
| 55586 | * amount of memory. Further, an initial allocation might fail and cause |
| 55587 | * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet. |
| 55588 | */ |
| 55589 | } |
| 55590 | |
| 55591 | DUK_LOCAL void *duk__hobject_alloc_init(duk_hthread *thr, duk_uint_t hobject_flags, duk_size_t size) { |
| 55592 | void *res; |
| 55593 | |
| 55594 | res = (void *) DUK_ALLOC_CHECKED_ZEROED(thr, size); |
| 55595 | DUK_ASSERT(res != NULL); |
| 55596 | duk__init_object_parts(thr->heap, hobject_flags, (duk_hobject *) res); |
| 55597 | return res; |
| 55598 | } |
| 55599 | |
| 55600 | /* |
| 55601 | * Allocate an duk_hobject. |
| 55602 | * |
| 55603 | * The allocated object has no allocation for properties; the caller may |
| 55604 | * want to force a resize if a desired size is known. |
| 55605 | * |
| 55606 | * The allocated object has zero reference count and is not reachable. |
| 55607 | * The caller MUST make the object reachable and increase its reference |
| 55608 | * count before invoking any operation that might require memory allocation. |
| 55609 | */ |
| 55610 | |
| 55611 | DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { |
| 55612 | duk_hobject *res; |
| 55613 | |
| 55614 | DUK_ASSERT(heap != NULL); |
| 55615 | |
| 55616 | /* different memory layout, alloc size, and init */ |
| 55617 | DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0); |
| 55618 | DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0); |
| 55619 | DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_BOUNDFUNC) == 0); |
| 55620 | |
| 55621 | res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject)); |
| 55622 | if (DUK_UNLIKELY(res == NULL)) { |
| 55623 | return NULL; |
| 55624 | } |
| 55625 | DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); |
| 55626 | |
| 55627 | duk__init_object_parts(heap, hobject_flags, res); |
| 55628 | |
| 55629 | DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res)); |
| 55630 | return res; |
| 55631 | } |
| 55632 | |
| 55633 | DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55634 | duk_hobject *res; |
| 55635 | |
| 55636 | res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject)); |
| 55637 | return res; |
| 55638 | } |
| 55639 | |
| 55640 | DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55641 | duk_hcompfunc *res; |
| 55642 | |
| 55643 | res = (duk_hcompfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hcompfunc)); |
| 55644 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55645 | #if defined(DUK_USE_HEAPPTR16) |
| 55646 | /* NULL pointer is required to encode to zero, so memset is enough. */ |
| 55647 | #else |
| 55648 | res->data = NULL; |
| 55649 | res->funcs = NULL; |
| 55650 | res->bytecode = NULL; |
| 55651 | #endif |
| 55652 | res->lex_env = NULL; |
| 55653 | res->var_env = NULL; |
| 55654 | #endif |
| 55655 | |
| 55656 | return res; |
| 55657 | } |
| 55658 | |
| 55659 | DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55660 | duk_hnatfunc *res; |
| 55661 | |
| 55662 | res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc)); |
| 55663 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55664 | res->func = NULL; |
| 55665 | #endif |
| 55666 | |
| 55667 | return res; |
| 55668 | } |
| 55669 | |
| 55670 | DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) { |
| 55671 | duk_hboundfunc *res; |
| 55672 | |
| 55673 | res = (duk_hboundfunc *) DUK_ALLOC(heap, sizeof(duk_hboundfunc)); |
| 55674 | if (!res) { |
| 55675 | return NULL; |
| 55676 | } |
| 55677 | duk_memzero(res, sizeof(duk_hboundfunc)); |
| 55678 | |
| 55679 | duk__init_object_parts(heap, hobject_flags, &res->obj); |
| 55680 | |
| 55681 | DUK_TVAL_SET_UNDEFINED(&res->target); |
| 55682 | DUK_TVAL_SET_UNDEFINED(&res->this_binding); |
| 55683 | |
| 55684 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55685 | res->args = NULL; |
| 55686 | #endif |
| 55687 | |
| 55688 | return res; |
| 55689 | } |
| 55690 | |
| 55691 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 55692 | DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55693 | duk_hbufobj *res; |
| 55694 | |
| 55695 | res = (duk_hbufobj *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hbufobj)); |
| 55696 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55697 | res->buf = NULL; |
| 55698 | res->buf_prop = NULL; |
| 55699 | #endif |
| 55700 | |
| 55701 | DUK_HBUFOBJ_ASSERT_VALID(res); |
| 55702 | return res; |
| 55703 | } |
| 55704 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 55705 | |
| 55706 | /* Allocate a new thread. |
| 55707 | * |
| 55708 | * Leaves the built-ins array uninitialized. The caller must either |
| 55709 | * initialize a new global context or share existing built-ins from |
| 55710 | * another thread. |
| 55711 | */ |
| 55712 | DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) { |
| 55713 | duk_hthread *res; |
| 55714 | |
| 55715 | res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread)); |
| 55716 | if (DUK_UNLIKELY(res == NULL)) { |
| 55717 | return NULL; |
| 55718 | } |
| 55719 | duk_memzero(res, sizeof(duk_hthread)); |
| 55720 | |
| 55721 | duk__init_object_parts(heap, hobject_flags, &res->obj); |
| 55722 | |
| 55723 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55724 | res->ptr_curr_pc = NULL; |
| 55725 | res->heap = NULL; |
| 55726 | res->valstack = NULL; |
| 55727 | res->valstack_end = NULL; |
| 55728 | res->valstack_alloc_end = NULL; |
| 55729 | res->valstack_bottom = NULL; |
| 55730 | res->valstack_top = NULL; |
| 55731 | res->callstack_curr = NULL; |
| 55732 | res->resumer = NULL; |
| 55733 | res->compile_ctx = NULL, |
| 55734 | #if defined(DUK_USE_HEAPPTR16) |
| 55735 | res->strs16 = NULL; |
| 55736 | #else |
| 55737 | res->strs = NULL; |
| 55738 | #endif |
| 55739 | { |
| 55740 | duk_small_uint_t i; |
| 55741 | for (i = 0; i < DUK_NUM_BUILTINS; i++) { |
| 55742 | res->builtins[i] = NULL; |
| 55743 | } |
| 55744 | } |
| 55745 | #endif |
| 55746 | /* When nothing is running, API calls are in non-strict mode. */ |
| 55747 | DUK_ASSERT(res->strict == 0); |
| 55748 | |
| 55749 | res->heap = heap; |
| 55750 | |
| 55751 | /* XXX: Any reason not to merge duk_hthread_alloc.c here? */ |
| 55752 | return res; |
| 55753 | } |
| 55754 | |
| 55755 | DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55756 | duk_hthread *res; |
| 55757 | |
| 55758 | res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags); |
| 55759 | if (res == NULL) { |
| 55760 | DUK_ERROR_ALLOC_FAILED(thr); |
| 55761 | DUK_WO_NORETURN(return NULL;); |
| 55762 | } |
| 55763 | return res; |
| 55764 | } |
| 55765 | |
| 55766 | DUK_INTERNAL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55767 | duk_harray *res; |
| 55768 | |
| 55769 | res = (duk_harray *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_harray)); |
| 55770 | |
| 55771 | DUK_ASSERT(res->length == 0); |
| 55772 | |
| 55773 | return res; |
| 55774 | } |
| 55775 | |
| 55776 | DUK_INTERNAL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55777 | duk_hdecenv *res; |
| 55778 | |
| 55779 | res = (duk_hdecenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hdecenv)); |
| 55780 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55781 | res->thread = NULL; |
| 55782 | res->varmap = NULL; |
| 55783 | #endif |
| 55784 | |
| 55785 | DUK_ASSERT(res->thread == NULL); |
| 55786 | DUK_ASSERT(res->varmap == NULL); |
| 55787 | DUK_ASSERT(res->regbase_byteoff == 0); |
| 55788 | |
| 55789 | return res; |
| 55790 | } |
| 55791 | |
| 55792 | DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55793 | duk_hobjenv *res; |
| 55794 | |
| 55795 | res = (duk_hobjenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobjenv)); |
| 55796 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 55797 | res->target = NULL; |
| 55798 | #endif |
| 55799 | |
| 55800 | DUK_ASSERT(res->target == NULL); |
| 55801 | |
| 55802 | return res; |
| 55803 | } |
| 55804 | |
| 55805 | DUK_INTERNAL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags) { |
| 55806 | duk_hproxy *res; |
| 55807 | |
| 55808 | res = (duk_hproxy *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hproxy)); |
| 55809 | |
| 55810 | /* Leave ->target and ->handler uninitialized, as caller will always |
| 55811 | * explicitly initialize them before any side effects are possible. |
| 55812 | */ |
| 55813 | |
| 55814 | return res; |
| 55815 | } |
| 55816 | #line 1 "duk_hobject_assert.c" |
| 55817 | /* |
| 55818 | * duk_hobject and subclass assertion helpers |
| 55819 | */ |
| 55820 | |
| 55821 | /* #include duk_internal.h -> already included */ |
| 55822 | |
| 55823 | #if defined(DUK_USE_ASSERTIONS) |
| 55824 | |
| 55825 | DUK_INTERNAL void duk_hobject_assert_valid(duk_hobject *h) { |
| 55826 | DUK_ASSERT(h != NULL); |
| 55827 | DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h) || |
| 55828 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FUNCTION); |
| 55829 | DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ(h) || |
| 55830 | (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER || |
| 55831 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_DATAVIEW || |
| 55832 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT8ARRAY || |
| 55833 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT8ARRAY || |
| 55834 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || |
| 55835 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT16ARRAY || |
| 55836 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT16ARRAY || |
| 55837 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT32ARRAY || |
| 55838 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT32ARRAY || |
| 55839 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || |
| 55840 | DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); |
| 55841 | /* Object is an Array <=> object has exotic array behavior */ |
| 55842 | DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) || |
| 55843 | (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY(h))); |
| 55844 | } |
| 55845 | |
| 55846 | DUK_INTERNAL void duk_harray_assert_valid(duk_harray *h) { |
| 55847 | DUK_ASSERT(h != NULL); |
| 55848 | DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h)); |
| 55849 | DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) h)); |
| 55850 | } |
| 55851 | |
| 55852 | DUK_INTERNAL void duk_hboundfunc_assert_valid(duk_hboundfunc *h) { |
| 55853 | DUK_ASSERT(h != NULL); |
| 55854 | DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) h)); |
| 55855 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h->target) || |
| 55856 | (DUK_TVAL_IS_OBJECT(&h->target) && |
| 55857 | DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h->target)))); |
| 55858 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&h->this_binding)); |
| 55859 | DUK_ASSERT(h->nargs == 0 || h->args != NULL); |
| 55860 | } |
| 55861 | |
| 55862 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 55863 | DUK_INTERNAL void duk_hbufobj_assert_valid(duk_hbufobj *h) { |
| 55864 | DUK_ASSERT(h != NULL); |
| 55865 | DUK_ASSERT(h->shift <= 3); |
| 55866 | DUK_ASSERT(h->elem_type <= DUK_HBUFOBJ_ELEM_MAX); |
| 55867 | DUK_ASSERT((h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT8) || |
| 55868 | (h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) || |
| 55869 | (h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_INT8) || |
| 55870 | (h->shift == 1 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT16) || |
| 55871 | (h->shift == 1 && h->elem_type == DUK_HBUFOBJ_ELEM_INT16) || |
| 55872 | (h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT32) || |
| 55873 | (h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_INT32) || |
| 55874 | (h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) || |
| 55875 | (h->shift == 3 && h->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64)); |
| 55876 | DUK_ASSERT(h->is_typedarray == 0 || h->is_typedarray == 1); |
| 55877 | DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h)); |
| 55878 | if (h->buf == NULL) { |
| 55879 | DUK_ASSERT(h->offset == 0); |
| 55880 | DUK_ASSERT(h->length == 0); |
| 55881 | } else { |
| 55882 | /* No assertions for offset or length; in particular, |
| 55883 | * it's OK for length to be longer than underlying |
| 55884 | * buffer. Just ensure they don't wrap when added. |
| 55885 | */ |
| 55886 | DUK_ASSERT(h->offset + h->length >= h->offset); |
| 55887 | } |
| 55888 | } |
| 55889 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 55890 | |
| 55891 | DUK_INTERNAL void duk_hcompfunc_assert_valid(duk_hcompfunc *h) { |
| 55892 | DUK_ASSERT(h != NULL); |
| 55893 | } |
| 55894 | |
| 55895 | DUK_INTERNAL void duk_hnatfunc_assert_valid(duk_hnatfunc *h) { |
| 55896 | DUK_ASSERT(h != NULL); |
| 55897 | } |
| 55898 | |
| 55899 | DUK_INTERNAL void duk_hdecenv_assert_valid(duk_hdecenv *h) { |
| 55900 | DUK_ASSERT(h != NULL); |
| 55901 | DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) h)); |
| 55902 | DUK_ASSERT(h->thread == NULL || h->varmap != NULL); |
| 55903 | } |
| 55904 | |
| 55905 | DUK_INTERNAL void duk_hobjenv_assert_valid(duk_hobjenv *h) { |
| 55906 | DUK_ASSERT(h != NULL); |
| 55907 | DUK_ASSERT(DUK_HOBJECT_IS_OBJENV((duk_hobject *) h)); |
| 55908 | DUK_ASSERT(h->target != NULL); |
| 55909 | DUK_ASSERT(h->has_this == 0 || h->has_this == 1); |
| 55910 | } |
| 55911 | |
| 55912 | DUK_INTERNAL void duk_hproxy_assert_valid(duk_hproxy *h) { |
| 55913 | DUK_ASSERT(h != NULL); |
| 55914 | DUK_ASSERT(h->target != NULL); |
| 55915 | DUK_ASSERT(h->handler != NULL); |
| 55916 | DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) h)); |
| 55917 | } |
| 55918 | |
| 55919 | DUK_INTERNAL void duk_hthread_assert_valid(duk_hthread *thr) { |
| 55920 | DUK_ASSERT(thr != NULL); |
| 55921 | DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) thr) == DUK_HTYPE_OBJECT); |
| 55922 | DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) thr)); |
| 55923 | DUK_ASSERT(thr->unused1 == 0); |
| 55924 | DUK_ASSERT(thr->unused2 == 0); |
| 55925 | } |
| 55926 | |
| 55927 | DUK_INTERNAL void duk_ctx_assert_valid(duk_hthread *thr) { |
| 55928 | DUK_ASSERT(thr != NULL); |
| 55929 | DUK_HTHREAD_ASSERT_VALID(thr); |
| 55930 | DUK_ASSERT(thr->valstack != NULL); |
| 55931 | DUK_ASSERT(thr->valstack_bottom != NULL); |
| 55932 | DUK_ASSERT(thr->valstack_top != NULL); |
| 55933 | DUK_ASSERT(thr->valstack_end != NULL); |
| 55934 | DUK_ASSERT(thr->valstack_alloc_end != NULL); |
| 55935 | DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack); |
| 55936 | DUK_ASSERT(thr->valstack_end >= thr->valstack); |
| 55937 | DUK_ASSERT(thr->valstack_top >= thr->valstack); |
| 55938 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 55939 | DUK_ASSERT(thr->valstack_end >= thr->valstack_top); |
| 55940 | DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end); |
| 55941 | } |
| 55942 | |
| 55943 | #endif /* DUK_USE_ASSERTIONS */ |
| 55944 | #line 1 "duk_hobject_enum.c" |
| 55945 | /* |
| 55946 | * Object enumeration support. |
| 55947 | * |
| 55948 | * Creates an internal enumeration state object to be used e.g. with for-in |
| 55949 | * enumeration. The state object contains a snapshot of target object keys |
| 55950 | * and internal control state for enumeration. Enumerator flags allow caller |
| 55951 | * to e.g. request internal/non-enumerable properties, and to enumerate only |
| 55952 | * "own" properties. |
| 55953 | * |
| 55954 | * Also creates the result value for e.g. Object.keys() based on the same |
| 55955 | * internal structure. |
| 55956 | * |
| 55957 | * This snapshot-based enumeration approach is used to simplify enumeration: |
| 55958 | * non-snapshot-based approaches are difficult to reconcile with mutating |
| 55959 | * the enumeration target, running multiple long-lived enumerators at the |
| 55960 | * same time, garbage collection details, etc. The downside is that the |
| 55961 | * enumerator object is memory inefficient especially for iterating arrays. |
| 55962 | */ |
| 55963 | |
| 55964 | /* #include duk_internal.h -> already included */ |
| 55965 | |
| 55966 | /* XXX: identify enumeration target with an object index (not top of stack) */ |
| 55967 | |
| 55968 | /* First enumerated key index in enumerator object, must match exactly the |
| 55969 | * number of control properties inserted to the enumerator. |
| 55970 | */ |
| 55971 | #define DUK__ENUM_START_INDEX 2 |
| 55972 | |
| 55973 | /* Current implementation suffices for ES2015 for now because there's no symbol |
| 55974 | * sorting, so commented out for now. |
| 55975 | */ |
| 55976 | |
| 55977 | /* |
| 55978 | * Helper to sort enumeration keys using a callback for pairwise duk_hstring |
| 55979 | * comparisons. The keys are in the enumeration object entry part, starting |
| 55980 | * from DUK__ENUM_START_INDEX, and the entry part is dense. Entry part values |
| 55981 | * are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true, "2" -> true, |
| 55982 | * so it suffices to just switch keys without switching values. |
| 55983 | * |
| 55984 | * ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects: |
| 55985 | * (1) array indices in ascending order, |
| 55986 | * (2) non-array-index keys in insertion order, and |
| 55987 | * (3) symbols in insertion order. |
| 55988 | * http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys. |
| 55989 | * |
| 55990 | * This rule is applied to "own properties" at each inheritance level; |
| 55991 | * non-duplicate parent keys always follow child keys. For example, |
| 55992 | * an inherited array index will enumerate -after- a symbol in the |
| 55993 | * child. |
| 55994 | * |
| 55995 | * Insertion sort is used because (1) it's simple and compact, (2) works |
| 55996 | * in-place, (3) minimizes operations if data is already nearly sorted, |
| 55997 | * (4) doesn't reorder elements considered equal. |
| 55998 | * http://en.wikipedia.org/wiki/Insertion_sort |
| 55999 | */ |
| 56000 | |
| 56001 | /* Sort key, must hold array indices, "not array index" marker, and one more |
| 56002 | * higher value for symbols. |
| 56003 | */ |
| 56004 | #if !defined(DUK_USE_SYMBOL_BUILTIN) |
| 56005 | typedef duk_uint32_t duk__sort_key_t; |
| 56006 | #elif defined(DUK_USE_64BIT_OPS) |
| 56007 | typedef duk_uint64_t duk__sort_key_t; |
| 56008 | #else |
| 56009 | typedef duk_double_t duk__sort_key_t; |
| 56010 | #endif |
| 56011 | |
| 56012 | /* Get sort key for a duk_hstring. */ |
| 56013 | DUK_LOCAL duk__sort_key_t duk__hstring_sort_key(duk_hstring *x) { |
| 56014 | duk__sort_key_t val; |
| 56015 | |
| 56016 | /* For array indices [0,0xfffffffe] use the array index as is. |
| 56017 | * For strings, use 0xffffffff, the marker 'arridx' already in |
| 56018 | * duk_hstring. For symbols, any value above 0xffffffff works, |
| 56019 | * as long as it is the same for all symbols; currently just add |
| 56020 | * the masked flag field into the arridx temporary. |
| 56021 | */ |
| 56022 | DUK_ASSERT(x != NULL); |
| 56023 | DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(x) || DUK_HSTRING_GET_ARRIDX_FAST(x) == DUK_HSTRING_NO_ARRAY_INDEX); |
| 56024 | |
| 56025 | val = (duk__sort_key_t) DUK_HSTRING_GET_ARRIDX_FAST(x); |
| 56026 | |
| 56027 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 56028 | val = val + (duk__sort_key_t) (DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) x) & DUK_HSTRING_FLAG_SYMBOL); |
| 56029 | #endif |
| 56030 | |
| 56031 | return (duk__sort_key_t) val; |
| 56032 | } |
| 56033 | |
| 56034 | /* Insert element 'b' after element 'a'? */ |
| 56035 | DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk__sort_key_t val_b) { |
| 56036 | duk__sort_key_t val_a; |
| 56037 | |
| 56038 | DUK_ASSERT(a != NULL); |
| 56039 | DUK_ASSERT(b != NULL); |
| 56040 | DUK_UNREF(b); /* Not actually needed now, val_b suffices. */ |
| 56041 | |
| 56042 | val_a = duk__hstring_sort_key(a); |
| 56043 | |
| 56044 | if (val_a > val_b) { |
| 56045 | return 0; |
| 56046 | } else { |
| 56047 | return 1; |
| 56048 | } |
| 56049 | } |
| 56050 | |
| 56051 | DUK_LOCAL void duk__sort_enum_keys_es6(duk_hthread *thr, duk_hobject *h_obj, duk_int_fast32_t idx_start, duk_int_fast32_t idx_end) { |
| 56052 | duk_hstring **keys; |
| 56053 | duk_int_fast32_t idx; |
| 56054 | |
| 56055 | DUK_ASSERT(h_obj != NULL); |
| 56056 | DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX); |
| 56057 | DUK_ASSERT(idx_end >= idx_start); |
| 56058 | DUK_UNREF(thr); |
| 56059 | |
| 56060 | if (idx_end <= idx_start + 1) { |
| 56061 | return; /* Zero or one element(s). */ |
| 56062 | } |
| 56063 | |
| 56064 | keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj); |
| 56065 | |
| 56066 | for (idx = idx_start + 1; idx < idx_end; idx++) { |
| 56067 | duk_hstring *h_curr; |
| 56068 | duk_int_fast32_t idx_insert; |
| 56069 | duk__sort_key_t val_curr; |
| 56070 | |
| 56071 | h_curr = keys[idx]; |
| 56072 | DUK_ASSERT(h_curr != NULL); |
| 56073 | |
| 56074 | /* Scan backwards for insertion place. This works very well |
| 56075 | * when the elements are nearly in order which is the common |
| 56076 | * (and optimized for) case. |
| 56077 | */ |
| 56078 | |
| 56079 | val_curr = duk__hstring_sort_key(h_curr); /* Remains same during scanning. */ |
| 56080 | for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) { |
| 56081 | duk_hstring *h_insert; |
| 56082 | h_insert = keys[idx_insert]; |
| 56083 | DUK_ASSERT(h_insert != NULL); |
| 56084 | |
| 56085 | if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) { |
| 56086 | break; |
| 56087 | } |
| 56088 | } |
| 56089 | /* If we're out of indices, idx_insert == idx_start - 1 and idx_insert++ |
| 56090 | * brings us back to idx_start. |
| 56091 | */ |
| 56092 | idx_insert++; |
| 56093 | DUK_ASSERT(idx_insert >= 0 && idx_insert <= idx); |
| 56094 | |
| 56095 | /* .-- p_insert .-- p_curr |
| 56096 | * v v |
| 56097 | * | ... | insert | ... | curr |
| 56098 | */ |
| 56099 | |
| 56100 | /* This could also done when the keys are in order, i.e. |
| 56101 | * idx_insert == idx. The result would be an unnecessary |
| 56102 | * memmove() but we use an explicit check because the keys |
| 56103 | * are very often in order already. |
| 56104 | */ |
| 56105 | if (idx != idx_insert) { |
| 56106 | duk_memmove((void *) (keys + idx_insert + 1), |
| 56107 | (const void *) (keys + idx_insert), |
| 56108 | ((size_t) (idx - idx_insert) * sizeof(duk_hstring *))); |
| 56109 | keys[idx_insert] = h_curr; |
| 56110 | } |
| 56111 | } |
| 56112 | |
| 56113 | /* Entry part has been reordered now with no side effects. |
| 56114 | * If the object has a hash part, it will now be incorrect |
| 56115 | * and we need to rehash. Do that by forcing a resize to |
| 56116 | * the current size. |
| 56117 | */ |
| 56118 | duk_hobject_resize_entrypart(thr, h_obj, DUK_HOBJECT_GET_ESIZE(h_obj)); |
| 56119 | } |
| 56120 | |
| 56121 | /* |
| 56122 | * Create an internal enumerator object E, which has its keys ordered |
| 56123 | * to match desired enumeration ordering. Also initialize internal control |
| 56124 | * properties for enumeration. |
| 56125 | * |
| 56126 | * Note: if an array was used to hold enumeration keys instead, an array |
| 56127 | * scan would be needed to eliminate duplicates found in the prototype chain. |
| 56128 | */ |
| 56129 | |
| 56130 | DUK_LOCAL void duk__add_enum_key(duk_hthread *thr, duk_hstring *k) { |
| 56131 | /* 'k' may be unreachable on entry so must push without any |
| 56132 | * potential for GC. |
| 56133 | */ |
| 56134 | duk_push_hstring(thr, k); |
| 56135 | duk_push_true(thr); |
| 56136 | duk_put_prop(thr, -3); |
| 56137 | } |
| 56138 | |
| 56139 | DUK_LOCAL void duk__add_enum_key_stridx(duk_hthread *thr, duk_small_uint_t stridx) { |
| 56140 | duk__add_enum_key(thr, DUK_HTHREAD_GET_STRING(thr, stridx)); |
| 56141 | } |
| 56142 | |
| 56143 | DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags) { |
| 56144 | duk_hobject *enum_target; |
| 56145 | duk_hobject *curr; |
| 56146 | duk_hobject *res; |
| 56147 | #if defined(DUK_USE_ES6_PROXY) |
| 56148 | duk_hobject *h_proxy_target; |
| 56149 | duk_hobject *h_proxy_handler; |
| 56150 | duk_hobject *h_trap_result; |
| 56151 | #endif |
| 56152 | duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */ |
| 56153 | duk_uint_fast32_t sort_start_index; |
| 56154 | |
| 56155 | DUK_ASSERT(thr != NULL); |
| 56156 | |
| 56157 | enum_target = duk_require_hobject(thr, -1); |
| 56158 | DUK_ASSERT(enum_target != NULL); |
| 56159 | |
| 56160 | duk_push_bare_object(thr); |
| 56161 | res = duk_known_hobject(thr, -1); |
| 56162 | |
| 56163 | /* [enum_target res] */ |
| 56164 | |
| 56165 | /* Target must be stored so that we can recheck whether or not |
| 56166 | * keys still exist when we enumerate. This is not done if the |
| 56167 | * enumeration result comes from a proxy trap as there is no |
| 56168 | * real object to check against. |
| 56169 | */ |
| 56170 | duk_push_hobject(thr, enum_target); |
| 56171 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_TARGET); /* Target is bare, plain put OK. */ |
| 56172 | |
| 56173 | /* Initialize index so that we skip internal control keys. */ |
| 56174 | duk_push_int(thr, DUK__ENUM_START_INDEX); |
| 56175 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT); /* Target is bare, plain put OK. */ |
| 56176 | |
| 56177 | /* |
| 56178 | * Proxy object handling |
| 56179 | */ |
| 56180 | |
| 56181 | #if defined(DUK_USE_ES6_PROXY) |
| 56182 | if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) { |
| 56183 | goto skip_proxy; |
| 56184 | } |
| 56185 | if (DUK_LIKELY(!duk_hobject_proxy_check(enum_target, |
| 56186 | &h_proxy_target, |
| 56187 | &h_proxy_handler))) { |
| 56188 | goto skip_proxy; |
| 56189 | } |
| 56190 | |
| 56191 | /* XXX: share code with Object.keys() Proxy handling */ |
| 56192 | |
| 56193 | /* In ES2015 for-in invoked the "enumerate" trap; in ES2016 "enumerate" |
| 56194 | * has been obsoleted and "ownKeys" is used instead. |
| 56195 | */ |
| 56196 | DUK_DDD(DUK_DDDPRINT("proxy enumeration" )); |
| 56197 | duk_push_hobject(thr, h_proxy_handler); |
| 56198 | if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) { |
| 56199 | /* No need to replace the 'enum_target' value in stack, only the |
| 56200 | * enum_target reference. This also ensures that the original |
| 56201 | * enum target is reachable, which keeps the proxy and the proxy |
| 56202 | * target reachable. We do need to replace the internal _Target. |
| 56203 | */ |
| 56204 | DUK_DDD(DUK_DDDPRINT("no ownKeys trap, enumerate proxy target instead" )); |
| 56205 | DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O" , (duk_heaphdr *) h_proxy_target)); |
| 56206 | enum_target = h_proxy_target; |
| 56207 | |
| 56208 | duk_push_hobject(thr, enum_target); /* -> [ ... enum_target res handler undefined target ] */ |
| 56209 | duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_INT_TARGET); /* Target is bare, plain put OK. */ |
| 56210 | |
| 56211 | duk_pop_2(thr); /* -> [ ... enum_target res ] */ |
| 56212 | goto skip_proxy; |
| 56213 | } |
| 56214 | |
| 56215 | /* [ ... enum_target res handler trap ] */ |
| 56216 | duk_insert(thr, -2); |
| 56217 | duk_push_hobject(thr, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */ |
| 56218 | duk_call_method(thr, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */ |
| 56219 | h_trap_result = duk_require_hobject(thr, -1); |
| 56220 | DUK_UNREF(h_trap_result); |
| 56221 | |
| 56222 | duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags); |
| 56223 | /* -> [ ... enum_target res trap_result keys_array ] */ |
| 56224 | |
| 56225 | /* Copy cleaned up trap result keys into the enumerator object. */ |
| 56226 | /* XXX: result is a dense array; could make use of that. */ |
| 56227 | DUK_ASSERT(duk_is_array(thr, -1)); |
| 56228 | len = (duk_uint_fast32_t) duk_get_length(thr, -1); |
| 56229 | for (i = 0; i < len; i++) { |
| 56230 | (void) duk_get_prop_index(thr, -1, (duk_uarridx_t) i); |
| 56231 | DUK_ASSERT(duk_is_string(thr, -1)); /* postprocess cleaned up */ |
| 56232 | /* [ ... enum_target res trap_result keys_array val ] */ |
| 56233 | duk_push_true(thr); |
| 56234 | /* [ ... enum_target res trap_result keys_array val true ] */ |
| 56235 | duk_put_prop(thr, -5); |
| 56236 | } |
| 56237 | /* [ ... enum_target res trap_result keys_array ] */ |
| 56238 | duk_pop_2(thr); |
| 56239 | duk_remove_m2(thr); |
| 56240 | |
| 56241 | /* [ ... res ] */ |
| 56242 | |
| 56243 | /* The internal _Target property is kept pointing to the original |
| 56244 | * enumeration target (the proxy object), so that the enumerator |
| 56245 | * 'next' operation can read property values if so requested. The |
| 56246 | * fact that the _Target is a proxy disables key existence check |
| 56247 | * during enumeration. |
| 56248 | */ |
| 56249 | DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O" , (duk_heaphdr *) res)); |
| 56250 | goto compact_and_return; |
| 56251 | |
| 56252 | skip_proxy: |
| 56253 | #endif /* DUK_USE_ES6_PROXY */ |
| 56254 | |
| 56255 | curr = enum_target; |
| 56256 | sort_start_index = DUK__ENUM_START_INDEX; |
| 56257 | DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(res) == DUK__ENUM_START_INDEX); |
| 56258 | while (curr) { |
| 56259 | duk_uint_fast32_t sort_end_index; |
| 56260 | #if !defined(DUK_USE_PREFER_SIZE) |
| 56261 | duk_bool_t need_sort = 0; |
| 56262 | #endif |
| 56263 | duk_bool_t cond; |
| 56264 | |
| 56265 | /* Enumeration proceeds by inheritance level. Virtual |
| 56266 | * properties need to be handled specially, followed by |
| 56267 | * array part, and finally entry part. |
| 56268 | * |
| 56269 | * If there are array index keys in the entry part or any |
| 56270 | * other risk of the ES2015 [[OwnPropertyKeys]] order being |
| 56271 | * violated, need_sort is set and an explicit ES2015 sort is |
| 56272 | * done for the inheritance level. |
| 56273 | */ |
| 56274 | |
| 56275 | /* XXX: inheriting from proxy */ |
| 56276 | |
| 56277 | /* |
| 56278 | * Virtual properties. |
| 56279 | * |
| 56280 | * String and buffer indices are virtual and always enumerable, |
| 56281 | * 'length' is virtual and non-enumerable. Array and arguments |
| 56282 | * object props have special behavior but are concrete. |
| 56283 | * |
| 56284 | * String and buffer objects don't have an array part so as long |
| 56285 | * as virtual array index keys are enumerated first, we don't |
| 56286 | * need to set need_sort. |
| 56287 | */ |
| 56288 | |
| 56289 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 56290 | cond = DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) || DUK_HOBJECT_IS_BUFOBJ(curr); |
| 56291 | #else |
| 56292 | cond = DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr); |
| 56293 | #endif |
| 56294 | cond = cond && !(enum_flags & DUK_ENUM_EXCLUDE_STRINGS); |
| 56295 | if (cond) { |
| 56296 | duk_bool_t have_length = 1; |
| 56297 | |
| 56298 | /* String and buffer enumeration behavior is identical now, |
| 56299 | * so use shared handler. |
| 56300 | */ |
| 56301 | if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) { |
| 56302 | duk_hstring *h_val; |
| 56303 | h_val = duk_hobject_get_internal_value_string(thr->heap, curr); |
| 56304 | DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */ |
| 56305 | len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val); |
| 56306 | } |
| 56307 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 56308 | else { |
| 56309 | duk_hbufobj *h_bufobj; |
| 56310 | DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(curr)); |
| 56311 | h_bufobj = (duk_hbufobj *) curr; |
| 56312 | |
| 56313 | if (h_bufobj == NULL || !h_bufobj->is_typedarray) { |
| 56314 | /* Zero length seems like a good behavior for neutered buffers. |
| 56315 | * ArrayBuffer (non-view) and DataView don't have index properties |
| 56316 | * or .length property. |
| 56317 | */ |
| 56318 | len = 0; |
| 56319 | have_length = 0; |
| 56320 | } else { |
| 56321 | /* There's intentionally no check for |
| 56322 | * current underlying buffer length. |
| 56323 | */ |
| 56324 | len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift); |
| 56325 | } |
| 56326 | } |
| 56327 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 56328 | |
| 56329 | for (i = 0; i < len; i++) { |
| 56330 | duk_hstring *k; |
| 56331 | |
| 56332 | /* This is a bit fragile: the string is not |
| 56333 | * reachable until it is pushed by the helper. |
| 56334 | */ |
| 56335 | k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); |
| 56336 | DUK_ASSERT(k); |
| 56337 | |
| 56338 | duk__add_enum_key(thr, k); |
| 56339 | |
| 56340 | /* [enum_target res] */ |
| 56341 | } |
| 56342 | |
| 56343 | /* 'length' and other virtual properties are not |
| 56344 | * enumerable, but are included if non-enumerable |
| 56345 | * properties are requested. |
| 56346 | */ |
| 56347 | |
| 56348 | if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) { |
| 56349 | duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH); |
| 56350 | } |
| 56351 | } |
| 56352 | |
| 56353 | /* |
| 56354 | * Array part |
| 56355 | */ |
| 56356 | |
| 56357 | cond = !(enum_flags & DUK_ENUM_EXCLUDE_STRINGS); |
| 56358 | if (cond) { |
| 56359 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) { |
| 56360 | duk_hstring *k; |
| 56361 | duk_tval *tv; |
| 56362 | |
| 56363 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i); |
| 56364 | if (DUK_TVAL_IS_UNUSED(tv)) { |
| 56365 | continue; |
| 56366 | } |
| 56367 | k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); /* Fragile reachability. */ |
| 56368 | DUK_ASSERT(k); |
| 56369 | |
| 56370 | duk__add_enum_key(thr, k); |
| 56371 | |
| 56372 | /* [enum_target res] */ |
| 56373 | } |
| 56374 | |
| 56375 | if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) { |
| 56376 | /* Array .length comes after numeric indices. */ |
| 56377 | if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) { |
| 56378 | duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH); |
| 56379 | } |
| 56380 | } |
| 56381 | } |
| 56382 | |
| 56383 | /* |
| 56384 | * Entries part |
| 56385 | */ |
| 56386 | |
| 56387 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) { |
| 56388 | duk_hstring *k; |
| 56389 | |
| 56390 | k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i); |
| 56391 | if (!k) { |
| 56392 | continue; |
| 56393 | } |
| 56394 | if (!(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) && |
| 56395 | !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) { |
| 56396 | continue; |
| 56397 | } |
| 56398 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) { |
| 56399 | if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) && |
| 56400 | DUK_HSTRING_HAS_HIDDEN(k)) { |
| 56401 | continue; |
| 56402 | } |
| 56403 | if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) { |
| 56404 | continue; |
| 56405 | } |
| 56406 | #if !defined(DUK_USE_PREFER_SIZE) |
| 56407 | need_sort = 1; |
| 56408 | #endif |
| 56409 | } else { |
| 56410 | DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k)); /* would also have symbol flag */ |
| 56411 | if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) { |
| 56412 | continue; |
| 56413 | } |
| 56414 | } |
| 56415 | if (DUK_HSTRING_HAS_ARRIDX(k)) { |
| 56416 | /* This in currently only possible if the |
| 56417 | * object has no array part: the array part |
| 56418 | * is exhaustive when it is present. |
| 56419 | */ |
| 56420 | #if !defined(DUK_USE_PREFER_SIZE) |
| 56421 | need_sort = 1; |
| 56422 | #endif |
| 56423 | } else { |
| 56424 | if (enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) { |
| 56425 | continue; |
| 56426 | } |
| 56427 | } |
| 56428 | |
| 56429 | DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) || |
| 56430 | !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v)); |
| 56431 | |
| 56432 | duk__add_enum_key(thr, k); |
| 56433 | |
| 56434 | /* [enum_target res] */ |
| 56435 | } |
| 56436 | |
| 56437 | /* Sort enumerated keys according to ES2015 requirements for |
| 56438 | * the "inheritance level" just processed. This is far from |
| 56439 | * optimal, ES2015 semantics could be achieved more efficiently |
| 56440 | * by handling array index string keys (and symbol keys) |
| 56441 | * specially above in effect doing the sort inline. |
| 56442 | * |
| 56443 | * Skip the sort if array index sorting is requested because |
| 56444 | * we must consider all keys, also inherited, so an explicit |
| 56445 | * sort is done for the whole result after we're done with the |
| 56446 | * prototype chain. |
| 56447 | * |
| 56448 | * Also skip the sort if need_sort == 0, i.e. we know for |
| 56449 | * certain that the enumerated order is already correct. |
| 56450 | */ |
| 56451 | sort_end_index = DUK_HOBJECT_GET_ENEXT(res); |
| 56452 | |
| 56453 | if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) { |
| 56454 | #if defined(DUK_USE_PREFER_SIZE) |
| 56455 | duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index); |
| 56456 | #else |
| 56457 | if (need_sort) { |
| 56458 | DUK_DDD(DUK_DDDPRINT("need to sort" )); |
| 56459 | duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index); |
| 56460 | } else { |
| 56461 | DUK_DDD(DUK_DDDPRINT("no need to sort" )); |
| 56462 | } |
| 56463 | #endif |
| 56464 | } |
| 56465 | |
| 56466 | sort_start_index = sort_end_index; |
| 56467 | |
| 56468 | if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) { |
| 56469 | break; |
| 56470 | } |
| 56471 | |
| 56472 | curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); |
| 56473 | } |
| 56474 | |
| 56475 | /* [enum_target res] */ |
| 56476 | |
| 56477 | duk_remove_m2(thr); |
| 56478 | |
| 56479 | /* [res] */ |
| 56480 | |
| 56481 | if (enum_flags & DUK_ENUM_SORT_ARRAY_INDICES) { |
| 56482 | /* Some E5/E5.1 algorithms require that array indices are iterated |
| 56483 | * in a strictly ascending order. This is the case for e.g. |
| 56484 | * Array.prototype.forEach() and JSON.stringify() PropertyList |
| 56485 | * handling. The caller can request an explicit sort in these |
| 56486 | * cases. |
| 56487 | */ |
| 56488 | |
| 56489 | /* Sort to ES2015 order which works for pure array incides but |
| 56490 | * also for mixed keys. |
| 56491 | */ |
| 56492 | duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) DUK__ENUM_START_INDEX, (duk_int_fast32_t) DUK_HOBJECT_GET_ENEXT(res)); |
| 56493 | } |
| 56494 | |
| 56495 | #if defined(DUK_USE_ES6_PROXY) |
| 56496 | compact_and_return: |
| 56497 | #endif |
| 56498 | /* compact; no need to seal because object is internal */ |
| 56499 | duk_hobject_compact_props(thr, res); |
| 56500 | |
| 56501 | DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT" , (duk_tval *) duk_get_tval(thr, -1))); |
| 56502 | } |
| 56503 | |
| 56504 | /* |
| 56505 | * Returns non-zero if a key and/or value was enumerated, and: |
| 56506 | * |
| 56507 | * [enum] -> [key] (get_value == 0) |
| 56508 | * [enum] -> [key value] (get_value == 1) |
| 56509 | * |
| 56510 | * Returns zero without pushing anything on the stack otherwise. |
| 56511 | */ |
| 56512 | DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value) { |
| 56513 | duk_hobject *e; |
| 56514 | duk_hobject *enum_target; |
| 56515 | duk_hstring *res = NULL; |
| 56516 | duk_uint_fast32_t idx; |
| 56517 | duk_bool_t check_existence; |
| 56518 | |
| 56519 | DUK_ASSERT(thr != NULL); |
| 56520 | |
| 56521 | /* [... enum] */ |
| 56522 | |
| 56523 | e = duk_require_hobject(thr, -1); |
| 56524 | |
| 56525 | /* XXX use get tval ptr, more efficient */ |
| 56526 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_NEXT); |
| 56527 | idx = (duk_uint_fast32_t) duk_require_uint(thr, -1); |
| 56528 | duk_pop(thr); |
| 56529 | DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld" , (long) idx)); |
| 56530 | |
| 56531 | /* Enumeration keys are checked against the enumeration target (to see |
| 56532 | * that they still exist). In the proxy enumeration case _Target will |
| 56533 | * be the proxy, and checking key existence against the proxy is not |
| 56534 | * required (or sensible, as the keys may be fully virtual). |
| 56535 | */ |
| 56536 | duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_TARGET); |
| 56537 | enum_target = duk_require_hobject(thr, -1); |
| 56538 | DUK_ASSERT(enum_target != NULL); |
| 56539 | #if defined(DUK_USE_ES6_PROXY) |
| 56540 | check_existence = (!DUK_HOBJECT_IS_PROXY(enum_target)); |
| 56541 | #else |
| 56542 | check_existence = 1; |
| 56543 | #endif |
| 56544 | duk_pop(thr); /* still reachable */ |
| 56545 | |
| 56546 | DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT" , |
| 56547 | (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(thr, -1))); |
| 56548 | |
| 56549 | /* no array part */ |
| 56550 | for (;;) { |
| 56551 | duk_hstring *k; |
| 56552 | |
| 56553 | if (idx >= DUK_HOBJECT_GET_ENEXT(e)) { |
| 56554 | DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements" )); |
| 56555 | break; |
| 56556 | } |
| 56557 | |
| 56558 | /* we know these because enum objects are internally created */ |
| 56559 | k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx); |
| 56560 | DUK_ASSERT(k != NULL); |
| 56561 | DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx)); |
| 56562 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v)); |
| 56563 | |
| 56564 | idx++; |
| 56565 | |
| 56566 | /* recheck that the property still exists */ |
| 56567 | if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) { |
| 56568 | DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip" )); |
| 56569 | continue; |
| 56570 | } |
| 56571 | |
| 56572 | DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O" , (duk_heaphdr *) k)); |
| 56573 | res = k; |
| 56574 | break; |
| 56575 | } |
| 56576 | |
| 56577 | DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld" , (long) idx)); |
| 56578 | |
| 56579 | duk_push_u32(thr, (duk_uint32_t) idx); |
| 56580 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT); |
| 56581 | |
| 56582 | /* [... enum] */ |
| 56583 | |
| 56584 | if (res) { |
| 56585 | duk_push_hstring(thr, res); |
| 56586 | if (get_value) { |
| 56587 | duk_push_hobject(thr, enum_target); |
| 56588 | duk_dup_m2(thr); /* -> [... enum key enum_target key] */ |
| 56589 | duk_get_prop(thr, -2); /* -> [... enum key enum_target val] */ |
| 56590 | duk_remove_m2(thr); /* -> [... enum key val] */ |
| 56591 | duk_remove(thr, -3); /* -> [... key val] */ |
| 56592 | } else { |
| 56593 | duk_remove_m2(thr); /* -> [... key] */ |
| 56594 | } |
| 56595 | return 1; |
| 56596 | } else { |
| 56597 | duk_pop(thr); /* -> [...] */ |
| 56598 | return 0; |
| 56599 | } |
| 56600 | } |
| 56601 | |
| 56602 | /* |
| 56603 | * Get enumerated keys in an ECMAScript array. Matches Object.keys() behavior |
| 56604 | * described in E5 Section 15.2.3.14. |
| 56605 | */ |
| 56606 | |
| 56607 | DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags) { |
| 56608 | duk_hobject *e; |
| 56609 | duk_hstring **keys; |
| 56610 | duk_tval *tv; |
| 56611 | duk_uint_fast32_t count; |
| 56612 | |
| 56613 | DUK_ASSERT(thr != NULL); |
| 56614 | DUK_ASSERT(duk_get_hobject(thr, -1) != NULL); |
| 56615 | |
| 56616 | /* Create a temporary enumerator to get the (non-duplicated) key list; |
| 56617 | * the enumerator state is initialized without being needed, but that |
| 56618 | * has little impact. |
| 56619 | */ |
| 56620 | |
| 56621 | duk_hobject_enumerator_create(thr, enum_flags); |
| 56622 | e = duk_known_hobject(thr, -1); |
| 56623 | |
| 56624 | /* [enum_target enum res] */ |
| 56625 | |
| 56626 | /* Create dense result array to exact size. */ |
| 56627 | DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX); |
| 56628 | count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX); |
| 56629 | |
| 56630 | /* XXX: uninit would be OK */ |
| 56631 | tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count); |
| 56632 | DUK_ASSERT(count == 0 || tv != NULL); |
| 56633 | DUK_ASSERT(!duk_is_bare_object(thr, -1)); |
| 56634 | |
| 56635 | /* Fill result array, no side effects. */ |
| 56636 | |
| 56637 | keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, e); |
| 56638 | keys += DUK__ENUM_START_INDEX; |
| 56639 | |
| 56640 | while (count-- > 0) { |
| 56641 | duk_hstring *k; |
| 56642 | |
| 56643 | k = *keys++; |
| 56644 | DUK_ASSERT(k != NULL); /* enumerator must have no keys deleted */ |
| 56645 | |
| 56646 | DUK_TVAL_SET_STRING(tv, k); |
| 56647 | tv++; |
| 56648 | DUK_HSTRING_INCREF(thr, k); |
| 56649 | } |
| 56650 | |
| 56651 | /* [enum_target enum res] */ |
| 56652 | duk_remove_m2(thr); |
| 56653 | |
| 56654 | /* [enum_target res] */ |
| 56655 | |
| 56656 | return 1; /* return 1 to allow callers to tail call */ |
| 56657 | } |
| 56658 | |
| 56659 | /* automatic undefs */ |
| 56660 | #undef DUK__ENUM_START_INDEX |
| 56661 | #line 1 "duk_hobject_misc.c" |
| 56662 | /* |
| 56663 | * Misc support functions |
| 56664 | */ |
| 56665 | |
| 56666 | /* #include duk_internal.h -> already included */ |
| 56667 | |
| 56668 | DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) { |
| 56669 | duk_uint_t sanity; |
| 56670 | |
| 56671 | DUK_ASSERT(thr != NULL); |
| 56672 | |
| 56673 | /* False if the object is NULL or the prototype 'p' is NULL. |
| 56674 | * In particular, false if both are NULL (don't compare equal). |
| 56675 | */ |
| 56676 | if (h == NULL || p == NULL) { |
| 56677 | return 0; |
| 56678 | } |
| 56679 | |
| 56680 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 56681 | do { |
| 56682 | if (h == p) { |
| 56683 | return 1; |
| 56684 | } |
| 56685 | |
| 56686 | if (sanity-- == 0) { |
| 56687 | if (ignore_loop) { |
| 56688 | break; |
| 56689 | } else { |
| 56690 | DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); |
| 56691 | DUK_WO_NORETURN(return 0;); |
| 56692 | } |
| 56693 | } |
| 56694 | h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); |
| 56695 | } while (h); |
| 56696 | |
| 56697 | return 0; |
| 56698 | } |
| 56699 | |
| 56700 | DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) { |
| 56701 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 56702 | duk_hobject *tmp; |
| 56703 | |
| 56704 | DUK_ASSERT(h); |
| 56705 | tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); |
| 56706 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p); |
| 56707 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */ |
| 56708 | DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); |
| 56709 | #else |
| 56710 | DUK_ASSERT(h); |
| 56711 | DUK_UNREF(thr); |
| 56712 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p); |
| 56713 | #endif |
| 56714 | } |
| 56715 | #line 1 "duk_hobject_pc2line.c" |
| 56716 | /* |
| 56717 | * Helpers for creating and querying pc2line debug data, which |
| 56718 | * converts a bytecode program counter to a source line number. |
| 56719 | * |
| 56720 | * The run-time pc2line data is bit-packed, and documented in: |
| 56721 | * |
| 56722 | * doc/function-objects.rst |
| 56723 | */ |
| 56724 | |
| 56725 | /* #include duk_internal.h -> already included */ |
| 56726 | |
| 56727 | #if defined(DUK_USE_PC2LINE) |
| 56728 | |
| 56729 | /* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */ |
| 56730 | DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) { |
| 56731 | duk_hbuffer_dynamic *h_buf; |
| 56732 | duk_bitencoder_ctx be_ctx_alloc; |
| 56733 | duk_bitencoder_ctx *be_ctx = &be_ctx_alloc; |
| 56734 | duk_uint32_t *hdr; |
| 56735 | duk_size_t new_size; |
| 56736 | duk_uint_fast32_t ; |
| 56737 | duk_uint_fast32_t curr_offset; |
| 56738 | duk_int_fast32_t curr_line, next_line, diff_line; |
| 56739 | duk_uint_fast32_t curr_pc; |
| 56740 | duk_uint_fast32_t hdr_index; |
| 56741 | |
| 56742 | DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH); |
| 56743 | |
| 56744 | num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP; |
| 56745 | curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2); |
| 56746 | |
| 56747 | duk_push_dynamic_buffer(thr, (duk_size_t) curr_offset); |
| 56748 | h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1); |
| 56749 | DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)); |
| 56750 | |
| 56751 | hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf); |
| 56752 | DUK_ASSERT(hdr != NULL); |
| 56753 | hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */ |
| 56754 | |
| 56755 | curr_pc = 0U; |
| 56756 | while (curr_pc < length) { |
| 56757 | new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH); |
| 56758 | duk_hbuffer_resize(thr, h_buf, new_size); |
| 56759 | |
| 56760 | hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf); |
| 56761 | DUK_ASSERT(hdr != NULL); |
| 56762 | DUK_ASSERT(curr_pc < length); |
| 56763 | hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2; |
| 56764 | curr_line = (duk_int_fast32_t) instrs[curr_pc].line; |
| 56765 | hdr[hdr_index + 0] = (duk_uint32_t) curr_line; |
| 56766 | hdr[hdr_index + 1] = (duk_uint32_t) curr_offset; |
| 56767 | |
| 56768 | #if 0 |
| 56769 | DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld" , |
| 56770 | (long) (curr_pc / DUK_PC2LINE_SKIP), |
| 56771 | (long) curr_pc, |
| 56772 | (long) hdr[hdr_index + 0], |
| 56773 | (long) hdr[hdr_index + 1])); |
| 56774 | #endif |
| 56775 | |
| 56776 | duk_memzero(be_ctx, sizeof(*be_ctx)); |
| 56777 | be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset; |
| 56778 | be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH; |
| 56779 | |
| 56780 | for (;;) { |
| 56781 | curr_pc++; |
| 56782 | if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */ |
| 56783 | (curr_pc >= length) ) { /* end of bytecode */ |
| 56784 | break; |
| 56785 | } |
| 56786 | DUK_ASSERT(curr_pc < length); |
| 56787 | next_line = (duk_int32_t) instrs[curr_pc].line; |
| 56788 | diff_line = next_line - curr_line; |
| 56789 | |
| 56790 | #if 0 |
| 56791 | DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld" , |
| 56792 | (long) curr_line, (long) next_line, (long) diff_line)); |
| 56793 | #endif |
| 56794 | |
| 56795 | if (diff_line == 0) { |
| 56796 | /* 0 */ |
| 56797 | duk_be_encode(be_ctx, 0, 1); |
| 56798 | } else if (diff_line >= 1 && diff_line <= 4) { |
| 56799 | /* 1 0 <2 bits> */ |
| 56800 | duk_be_encode(be_ctx, (duk_uint32_t) ((0x02 << 2) + (diff_line - 1)), 4); |
| 56801 | } else if (diff_line >= -0x80 && diff_line <= 0x7f) { |
| 56802 | /* 1 1 0 <8 bits> */ |
| 56803 | DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff); |
| 56804 | duk_be_encode(be_ctx, (duk_uint32_t) ((0x06 << 8) + (diff_line + 0x80)), 11); |
| 56805 | } else { |
| 56806 | /* 1 1 1 <32 bits> |
| 56807 | * Encode in two parts to avoid bitencode 24-bit limitation |
| 56808 | */ |
| 56809 | duk_be_encode(be_ctx, (duk_uint32_t) ((0x07 << 16) + ((next_line >> 16) & 0xffff)), 19); |
| 56810 | duk_be_encode(be_ctx, (duk_uint32_t) (next_line & 0xffff), 16); |
| 56811 | } |
| 56812 | |
| 56813 | curr_line = next_line; |
| 56814 | } |
| 56815 | |
| 56816 | duk_be_finish(be_ctx); |
| 56817 | DUK_ASSERT(!be_ctx->truncated); |
| 56818 | |
| 56819 | /* be_ctx->offset == length of encoded bitstream */ |
| 56820 | curr_offset += (duk_uint_fast32_t) be_ctx->offset; |
| 56821 | } |
| 56822 | |
| 56823 | /* compact */ |
| 56824 | new_size = (duk_size_t) curr_offset; |
| 56825 | duk_hbuffer_resize(thr, h_buf, new_size); |
| 56826 | |
| 56827 | (void) duk_to_fixed_buffer(thr, -1, NULL); |
| 56828 | |
| 56829 | DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT" , |
| 56830 | (long) length, (long) new_size, (double) new_size * 8.0 / (double) length, |
| 56831 | (duk_tval *) duk_get_tval(thr, -1))); |
| 56832 | } |
| 56833 | |
| 56834 | /* PC is unsigned. If caller does PC arithmetic and gets a negative result, |
| 56835 | * it will map to a large PC which is out of bounds and causes a zero to be |
| 56836 | * returned. |
| 56837 | */ |
| 56838 | DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) { |
| 56839 | duk_bitdecoder_ctx bd_ctx_alloc; |
| 56840 | duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc; |
| 56841 | duk_uint32_t *hdr; |
| 56842 | duk_uint_fast32_t start_offset; |
| 56843 | duk_uint_fast32_t pc_limit; |
| 56844 | duk_uint_fast32_t hdr_index; |
| 56845 | duk_uint_fast32_t pc_base; |
| 56846 | duk_uint_fast32_t n; |
| 56847 | duk_uint_fast32_t curr_line; |
| 56848 | |
| 56849 | DUK_ASSERT(buf != NULL); |
| 56850 | DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf)); |
| 56851 | DUK_UNREF(thr); |
| 56852 | |
| 56853 | /* |
| 56854 | * Use the index in the header to find the right starting point |
| 56855 | */ |
| 56856 | |
| 56857 | hdr_index = pc / DUK_PC2LINE_SKIP; |
| 56858 | pc_base = hdr_index * DUK_PC2LINE_SKIP; |
| 56859 | n = pc - pc_base; |
| 56860 | |
| 56861 | if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) { |
| 56862 | DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header" )); |
| 56863 | goto pc2line_error; |
| 56864 | } |
| 56865 | |
| 56866 | hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf); |
| 56867 | pc_limit = hdr[0]; |
| 56868 | if (pc >= pc_limit) { |
| 56869 | /* Note: pc is unsigned and cannot be negative */ |
| 56870 | DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)" , |
| 56871 | (long) pc, (long) pc_limit)); |
| 56872 | goto pc2line_error; |
| 56873 | } |
| 56874 | |
| 56875 | curr_line = hdr[1 + hdr_index * 2]; |
| 56876 | start_offset = hdr[1 + hdr_index * 2 + 1]; |
| 56877 | if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) { |
| 56878 | DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)" , |
| 56879 | (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf))); |
| 56880 | goto pc2line_error; |
| 56881 | } |
| 56882 | |
| 56883 | /* |
| 56884 | * Iterate the bitstream (line diffs) until PC is reached |
| 56885 | */ |
| 56886 | |
| 56887 | duk_memzero(bd_ctx, sizeof(*bd_ctx)); |
| 56888 | bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset; |
| 56889 | bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset); |
| 56890 | |
| 56891 | #if 0 |
| 56892 | DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld" , |
| 56893 | (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset)); |
| 56894 | #endif |
| 56895 | |
| 56896 | while (n > 0) { |
| 56897 | #if 0 |
| 56898 | DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld" , (long) n, (long) curr_line)); |
| 56899 | #endif |
| 56900 | |
| 56901 | if (duk_bd_decode_flag(bd_ctx)) { |
| 56902 | if (duk_bd_decode_flag(bd_ctx)) { |
| 56903 | if (duk_bd_decode_flag(bd_ctx)) { |
| 56904 | /* 1 1 1 <32 bits> */ |
| 56905 | duk_uint_fast32_t t; |
| 56906 | t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */ |
| 56907 | t = (t << 16) + duk_bd_decode(bd_ctx, 16); |
| 56908 | curr_line = t; |
| 56909 | } else { |
| 56910 | /* 1 1 0 <8 bits> */ |
| 56911 | duk_uint_fast32_t t; |
| 56912 | t = duk_bd_decode(bd_ctx, 8); |
| 56913 | curr_line = curr_line + t - 0x80; |
| 56914 | } |
| 56915 | } else { |
| 56916 | /* 1 0 <2 bits> */ |
| 56917 | duk_uint_fast32_t t; |
| 56918 | t = duk_bd_decode(bd_ctx, 2); |
| 56919 | curr_line = curr_line + t + 1; |
| 56920 | } |
| 56921 | } else { |
| 56922 | /* 0: no change */ |
| 56923 | } |
| 56924 | |
| 56925 | n--; |
| 56926 | } |
| 56927 | |
| 56928 | DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld" , (long) pc, (long) curr_line)); |
| 56929 | return curr_line; |
| 56930 | |
| 56931 | pc2line_error: |
| 56932 | DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld" , (long) pc)); |
| 56933 | return 0; |
| 56934 | } |
| 56935 | |
| 56936 | DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc) { |
| 56937 | duk_hbuffer_fixed *pc2line; |
| 56938 | duk_uint_fast32_t line; |
| 56939 | |
| 56940 | /* XXX: now that pc2line is used by the debugger quite heavily in |
| 56941 | * checked execution, this should be optimized to avoid value stack |
| 56942 | * and perhaps also implement some form of pc2line caching (see |
| 56943 | * future work in debugger.rst). |
| 56944 | */ |
| 56945 | |
| 56946 | duk_xget_owndataprop_stridx_short(thr, idx_func, DUK_STRIDX_INT_PC2LINE); |
| 56947 | pc2line = (duk_hbuffer_fixed *) (void *) duk_get_hbuffer(thr, -1); |
| 56948 | if (pc2line != NULL) { |
| 56949 | DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line)); |
| 56950 | line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc); |
| 56951 | } else { |
| 56952 | line = 0; |
| 56953 | } |
| 56954 | duk_pop(thr); |
| 56955 | |
| 56956 | return line; |
| 56957 | } |
| 56958 | |
| 56959 | #endif /* DUK_USE_PC2LINE */ |
| 56960 | #line 1 "duk_hobject_props.c" |
| 56961 | /* |
| 56962 | * duk_hobject property access functionality. |
| 56963 | * |
| 56964 | * This is very central functionality for size, performance, and compliance. |
| 56965 | * It is also rather intricate; see hobject-algorithms.rst for discussion on |
| 56966 | * the algorithms and memory-management.rst for discussion on refcounts and |
| 56967 | * side effect issues. |
| 56968 | * |
| 56969 | * Notes: |
| 56970 | * |
| 56971 | * - It might be tempting to assert "refcount nonzero" for objects |
| 56972 | * being operated on, but that's not always correct: objects with |
| 56973 | * a zero refcount may be operated on by the refcount implementation |
| 56974 | * (finalization) for instance. Hence, no refcount assertions are made. |
| 56975 | * |
| 56976 | * - Many operations (memory allocation, identifier operations, etc) |
| 56977 | * may cause arbitrary side effects (e.g. through GC and finalization). |
| 56978 | * These side effects may invalidate duk_tval pointers which point to |
| 56979 | * areas subject to reallocation (like value stack). Heap objects |
| 56980 | * themselves have stable pointers. Holding heap object pointers or |
| 56981 | * duk_tval copies is not problematic with respect to side effects; |
| 56982 | * care must be taken when holding and using argument duk_tval pointers. |
| 56983 | * |
| 56984 | * - If a finalizer is executed, it may operate on the the same object |
| 56985 | * we're currently dealing with. For instance, the finalizer might |
| 56986 | * delete a certain property which has already been looked up and |
| 56987 | * confirmed to exist. Ideally finalizers would be disabled if GC |
| 56988 | * happens during property access. At the moment property table realloc |
| 56989 | * disables finalizers, and all DECREFs may cause arbitrary changes so |
| 56990 | * handle DECREF carefully. |
| 56991 | * |
| 56992 | * - The order of operations for a DECREF matters. When DECREF is executed, |
| 56993 | * the entire object graph must be consistent; note that a refzero may |
| 56994 | * lead to a mark-and-sweep through a refcount finalizer. Use NORZ macros |
| 56995 | * and an explicit DUK_REFZERO_CHECK_xxx() if achieving correct order is hard. |
| 56996 | */ |
| 56997 | |
| 56998 | /* |
| 56999 | * XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t |
| 57000 | * might be more appropriate. |
| 57001 | */ |
| 57002 | |
| 57003 | /* #include duk_internal.h -> already included */ |
| 57004 | |
| 57005 | /* |
| 57006 | * Local defines |
| 57007 | */ |
| 57008 | |
| 57009 | #define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX |
| 57010 | |
| 57011 | /* Marker values for hash part. */ |
| 57012 | #define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED |
| 57013 | #define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED |
| 57014 | |
| 57015 | /* Valstack space that suffices for all local calls, excluding any recursion |
| 57016 | * into ECMAScript or Duktape/C calls (Proxy, getters, etc). |
| 57017 | */ |
| 57018 | #define DUK__VALSTACK_SPACE 10 |
| 57019 | |
| 57020 | /* Valstack space allocated especially for proxy lookup which does a |
| 57021 | * recursive property lookup. |
| 57022 | */ |
| 57023 | #define DUK__VALSTACK_PROXY_LOOKUP 20 |
| 57024 | |
| 57025 | /* |
| 57026 | * Local prototypes |
| 57027 | */ |
| 57028 | |
| 57029 | DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc); |
| 57030 | DUK_LOCAL_DECL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag); |
| 57031 | DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc); |
| 57032 | |
| 57033 | DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr, duk_hobject *obj, duk_uint32_t old_len, duk_uint32_t new_len, duk_bool_t force_flag, duk_uint32_t *out_result_len); |
| 57034 | DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj); |
| 57035 | |
| 57036 | DUK_LOCAL_DECL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags); |
| 57037 | DUK_LOCAL_DECL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags); |
| 57038 | |
| 57039 | DUK_LOCAL_DECL void duk__abandon_array_part(duk_hthread *thr, duk_hobject *obj); |
| 57040 | DUK_LOCAL_DECL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx); |
| 57041 | |
| 57042 | /* |
| 57043 | * Misc helpers |
| 57044 | */ |
| 57045 | |
| 57046 | /* Convert a duk_tval number (caller checks) to a 32-bit index. Returns |
| 57047 | * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array |
| 57048 | * index. |
| 57049 | */ |
| 57050 | /* XXX: for fastints, could use a variant which assumes a double duk_tval |
| 57051 | * (and doesn't need to check for fastint again). |
| 57052 | */ |
| 57053 | DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) { |
| 57054 | duk_double_t dbl; |
| 57055 | duk_uint32_t idx; |
| 57056 | |
| 57057 | DUK_ASSERT(tv != NULL); |
| 57058 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 57059 | |
| 57060 | /* -0 is accepted here as index 0 because ToString(-0) == "0" which is |
| 57061 | * in canonical form and thus an array index. |
| 57062 | */ |
| 57063 | dbl = DUK_TVAL_GET_NUMBER(tv); |
| 57064 | idx = (duk_uint32_t) dbl; |
| 57065 | if (duk_double_equals((duk_double_t) idx, dbl)) { |
| 57066 | /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF, |
| 57067 | * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX. |
| 57068 | */ |
| 57069 | return idx; |
| 57070 | } |
| 57071 | return DUK__NO_ARRAY_INDEX; |
| 57072 | } |
| 57073 | |
| 57074 | #if defined(DUK_USE_FASTINT) |
| 57075 | /* Convert a duk_tval fastint (caller checks) to a 32-bit index. */ |
| 57076 | DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) { |
| 57077 | duk_int64_t t; |
| 57078 | |
| 57079 | DUK_ASSERT(tv != NULL); |
| 57080 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); |
| 57081 | |
| 57082 | t = DUK_TVAL_GET_FASTINT(tv); |
| 57083 | if (((duk_uint64_t) t & ~DUK_U64_CONSTANT(0xffffffff)) != 0) { |
| 57084 | /* Catches >0x100000000 and negative values. */ |
| 57085 | return DUK__NO_ARRAY_INDEX; |
| 57086 | } |
| 57087 | |
| 57088 | /* If the value happens to be 0xFFFFFFFF, it's not a valid array index |
| 57089 | * but will then match DUK__NO_ARRAY_INDEX. |
| 57090 | */ |
| 57091 | return (duk_uint32_t) t; |
| 57092 | } |
| 57093 | #endif /* DUK_USE_FASTINT */ |
| 57094 | |
| 57095 | /* Convert a duk_tval on the value stack (in a trusted index we don't validate) |
| 57096 | * to a string or symbol using ES2015 ToPropertyKey(): |
| 57097 | * http://www.ecma-international.org/ecma-262/6.0/#sec-topropertykey. |
| 57098 | * |
| 57099 | * Also check if it's a valid array index and return that (or DUK__NO_ARRAY_INDEX |
| 57100 | * if not). |
| 57101 | */ |
| 57102 | DUK_LOCAL duk_uint32_t duk__to_property_key(duk_hthread *thr, duk_idx_t idx, duk_hstring **out_h) { |
| 57103 | duk_uint32_t arr_idx; |
| 57104 | duk_hstring *h; |
| 57105 | duk_tval *tv_dst; |
| 57106 | |
| 57107 | DUK_ASSERT(thr != NULL); |
| 57108 | DUK_ASSERT(out_h != NULL); |
| 57109 | DUK_ASSERT(duk_is_valid_index(thr, idx)); |
| 57110 | DUK_ASSERT(idx < 0); |
| 57111 | |
| 57112 | /* XXX: The revised ES2015 ToPropertyKey() handling (ES5.1 was just |
| 57113 | * ToString()) involves a ToPrimitive(), a symbol check, and finally |
| 57114 | * a ToString(). Figure out the best way to have a good fast path |
| 57115 | * but still be compliant and share code. |
| 57116 | */ |
| 57117 | |
| 57118 | tv_dst = DUK_GET_TVAL_NEGIDX(thr, idx); /* intentionally unvalidated */ |
| 57119 | if (DUK_TVAL_IS_STRING(tv_dst)) { |
| 57120 | /* Most important path: strings and plain symbols are used as |
| 57121 | * is. For symbols the array index check below is unnecessary |
| 57122 | * (they're never valid array indices) but checking that the |
| 57123 | * string is a symbol would make the plain string path slower |
| 57124 | * unnecessarily. |
| 57125 | */ |
| 57126 | h = DUK_TVAL_GET_STRING(tv_dst); |
| 57127 | } else { |
| 57128 | h = duk_to_property_key_hstring(thr, idx); |
| 57129 | } |
| 57130 | DUK_ASSERT(h != NULL); |
| 57131 | *out_h = h; |
| 57132 | |
| 57133 | arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h); |
| 57134 | return arr_idx; |
| 57135 | } |
| 57136 | |
| 57137 | DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_hthread *thr, duk_tval *tv_key, duk_hstring **out_h) { |
| 57138 | duk_push_tval(thr, tv_key); /* XXX: could use an unsafe push here */ |
| 57139 | return duk__to_property_key(thr, -1, out_h); |
| 57140 | } |
| 57141 | |
| 57142 | /* String is an own (virtual) property of a plain buffer. */ |
| 57143 | DUK_LOCAL duk_bool_t duk__key_is_plain_buf_ownprop(duk_hthread *thr, duk_hbuffer *buf, duk_hstring *key, duk_uint32_t arr_idx) { |
| 57144 | DUK_UNREF(thr); |
| 57145 | |
| 57146 | /* Virtual index properties. Checking explicitly for |
| 57147 | * 'arr_idx != DUK__NO_ARRAY_INDEX' is not necessary |
| 57148 | * because DUK__NO_ARRAY_INDEXi is always larger than |
| 57149 | * maximum allowed buffer size. |
| 57150 | */ |
| 57151 | DUK_ASSERT(DUK__NO_ARRAY_INDEX >= DUK_HBUFFER_GET_SIZE(buf)); |
| 57152 | if (arr_idx < DUK_HBUFFER_GET_SIZE(buf)) { |
| 57153 | return 1; |
| 57154 | } |
| 57155 | |
| 57156 | /* Other virtual properties. */ |
| 57157 | return (key == DUK_HTHREAD_STRING_LENGTH(thr)); |
| 57158 | } |
| 57159 | |
| 57160 | /* |
| 57161 | * Helpers for managing property storage size |
| 57162 | */ |
| 57163 | |
| 57164 | /* Get default hash part size for a certain entry part size. */ |
| 57165 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 57166 | DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) { |
| 57167 | DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES); |
| 57168 | |
| 57169 | if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { |
| 57170 | duk_uint32_t res; |
| 57171 | duk_uint32_t tmp; |
| 57172 | |
| 57173 | /* Hash size should be 2^N where N is chosen so that 2^N is |
| 57174 | * larger than e_size. Extra shifting is used to ensure hash |
| 57175 | * is relatively sparse. |
| 57176 | */ |
| 57177 | tmp = e_size; |
| 57178 | res = 2; /* Result will be 2 ** (N + 1). */ |
| 57179 | while (tmp >= 0x40) { |
| 57180 | tmp >>= 6; |
| 57181 | res <<= 6; |
| 57182 | } |
| 57183 | while (tmp != 0) { |
| 57184 | tmp >>= 1; |
| 57185 | res <<= 1; |
| 57186 | } |
| 57187 | DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES); /* Won't wrap, even shifted by 2. */ |
| 57188 | DUK_ASSERT(res > e_size); |
| 57189 | return res; |
| 57190 | } else { |
| 57191 | return 0; |
| 57192 | } |
| 57193 | } |
| 57194 | #endif /* USE_PROP_HASH_PART */ |
| 57195 | |
| 57196 | /* Get minimum entry part growth for a certain size. */ |
| 57197 | DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) { |
| 57198 | duk_uint32_t res; |
| 57199 | |
| 57200 | res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR; |
| 57201 | DUK_ASSERT(res >= 1); /* important for callers */ |
| 57202 | return res; |
| 57203 | } |
| 57204 | |
| 57205 | /* Get minimum array part growth for a certain size. */ |
| 57206 | DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) { |
| 57207 | duk_uint32_t res; |
| 57208 | |
| 57209 | res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR; |
| 57210 | DUK_ASSERT(res >= 1); /* important for callers */ |
| 57211 | return res; |
| 57212 | } |
| 57213 | |
| 57214 | /* Count actually used entry part entries (non-NULL keys). */ |
| 57215 | DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) { |
| 57216 | duk_uint_fast32_t i; |
| 57217 | duk_uint_fast32_t n = 0; |
| 57218 | duk_hstring **e; |
| 57219 | |
| 57220 | DUK_ASSERT(obj != NULL); |
| 57221 | DUK_UNREF(thr); |
| 57222 | |
| 57223 | e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj); |
| 57224 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 57225 | if (*e++) { |
| 57226 | n++; |
| 57227 | } |
| 57228 | } |
| 57229 | return (duk_uint32_t) n; |
| 57230 | } |
| 57231 | |
| 57232 | /* Count actually used array part entries and array minimum size. |
| 57233 | * NOTE: 'out_min_size' can be computed much faster by starting from the |
| 57234 | * end and breaking out early when finding first used entry, but this is |
| 57235 | * not needed now. |
| 57236 | */ |
| 57237 | DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) { |
| 57238 | duk_uint_fast32_t i; |
| 57239 | duk_uint_fast32_t used = 0; |
| 57240 | duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1; /* see below */ |
| 57241 | duk_tval *a; |
| 57242 | |
| 57243 | DUK_ASSERT(obj != NULL); |
| 57244 | DUK_ASSERT(out_used != NULL); |
| 57245 | DUK_ASSERT(out_min_size != NULL); |
| 57246 | DUK_UNREF(thr); |
| 57247 | |
| 57248 | a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj); |
| 57249 | for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { |
| 57250 | duk_tval *tv = a++; |
| 57251 | if (!DUK_TVAL_IS_UNUSED(tv)) { |
| 57252 | used++; |
| 57253 | highest_idx = i; |
| 57254 | } |
| 57255 | } |
| 57256 | |
| 57257 | /* Initial value for highest_idx is -1 coerced to unsigned. This |
| 57258 | * is a bit odd, but (highest_idx + 1) will then wrap to 0 below |
| 57259 | * for out_min_size as intended. |
| 57260 | */ |
| 57261 | |
| 57262 | *out_used = (duk_uint32_t) used; |
| 57263 | *out_min_size = (duk_uint32_t) (highest_idx + 1); /* 0 if no used entries */ |
| 57264 | } |
| 57265 | |
| 57266 | /* Check array density and indicate whether or not the array part should be abandoned. */ |
| 57267 | DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) { |
| 57268 | /* |
| 57269 | * Array abandon check; abandon if: |
| 57270 | * |
| 57271 | * new_used / new_size < limit |
| 57272 | * new_used < limit * new_size || limit is 3 bits fixed point |
| 57273 | * new_used < limit' / 8 * new_size || *8 |
| 57274 | * 8*new_used < limit' * new_size || :8 |
| 57275 | * new_used < limit' * (new_size / 8) |
| 57276 | * |
| 57277 | * Here, new_used = a_used, new_size = a_size. |
| 57278 | * |
| 57279 | * Note: some callers use approximate values for a_used and/or a_size |
| 57280 | * (e.g. dropping a '+1' term). This doesn't affect the usefulness |
| 57281 | * of the check, but may confuse debugging. |
| 57282 | */ |
| 57283 | |
| 57284 | return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3)); |
| 57285 | } |
| 57286 | |
| 57287 | /* Fast check for extending array: check whether or not a slow density check is required. */ |
| 57288 | DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) { |
| 57289 | duk_uint32_t new_size_min; |
| 57290 | |
| 57291 | /* |
| 57292 | * In a fast check we assume old_size equals old_used (i.e., existing |
| 57293 | * array is fully dense). |
| 57294 | * |
| 57295 | * Slow check if: |
| 57296 | * |
| 57297 | * (new_size - old_size) / old_size > limit |
| 57298 | * new_size - old_size > limit * old_size |
| 57299 | * new_size > (1 + limit) * old_size || limit' is 3 bits fixed point |
| 57300 | * new_size > (1 + (limit' / 8)) * old_size || * 8 |
| 57301 | * 8 * new_size > (8 + limit') * old_size || : 8 |
| 57302 | * new_size > (8 + limit') * (old_size / 8) |
| 57303 | * new_size > limit'' * (old_size / 8) || limit'' = 9 -> max 25% increase |
| 57304 | * arr_idx + 1 > limit'' * (old_size / 8) |
| 57305 | * |
| 57306 | * This check doesn't work well for small values, so old_size is rounded |
| 57307 | * up for the check (and the '+ 1' of arr_idx can be ignored in practice): |
| 57308 | * |
| 57309 | * arr_idx > limit'' * ((old_size + 7) / 8) |
| 57310 | */ |
| 57311 | |
| 57312 | new_size_min = arr_idx + 1; |
| 57313 | return (new_size_min >= DUK_USE_HOBJECT_ARRAY_ABANDON_MINSIZE) && |
| 57314 | (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3)); |
| 57315 | } |
| 57316 | |
| 57317 | DUK_LOCAL duk_bool_t duk__abandon_array_check(duk_hthread *thr, duk_uint32_t arr_idx, duk_hobject *obj) { |
| 57318 | duk_uint32_t min_size; |
| 57319 | duk_uint32_t old_used; |
| 57320 | duk_uint32_t old_size; |
| 57321 | |
| 57322 | if (!duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(obj))) { |
| 57323 | DUK_DDD(DUK_DDDPRINT("=> fast resize is OK" )); |
| 57324 | return 0; |
| 57325 | } |
| 57326 | |
| 57327 | duk__compute_a_stats(thr, obj, &old_used, &old_size); |
| 57328 | |
| 57329 | DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld" , |
| 57330 | (long) old_used, (long) old_size, (long) arr_idx)); |
| 57331 | |
| 57332 | min_size = arr_idx + 1; |
| 57333 | #if defined(DUK_USE_OBJSIZES16) |
| 57334 | if (min_size > DUK_UINT16_MAX) { |
| 57335 | goto do_abandon; |
| 57336 | } |
| 57337 | #endif |
| 57338 | DUK_UNREF(min_size); |
| 57339 | |
| 57340 | /* Note: intentionally use approximations to shave a few instructions: |
| 57341 | * a_used = old_used (accurate: old_used + 1) |
| 57342 | * a_size = arr_idx (accurate: arr_idx + 1) |
| 57343 | */ |
| 57344 | if (duk__abandon_array_density_check(old_used, arr_idx)) { |
| 57345 | DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, " |
| 57346 | "decided to abandon array part (would become too sparse)" )); |
| 57347 | |
| 57348 | /* Abandoning requires a props allocation resize and |
| 57349 | * 'rechecks' the valstack, invalidating any existing |
| 57350 | * valstack value pointers. |
| 57351 | */ |
| 57352 | goto do_abandon; |
| 57353 | } |
| 57354 | |
| 57355 | DUK_DDD(DUK_DDDPRINT("=> decided to keep array part" )); |
| 57356 | return 0; |
| 57357 | |
| 57358 | do_abandon: |
| 57359 | duk__abandon_array_part(thr, obj); |
| 57360 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj)); |
| 57361 | return 1; |
| 57362 | } |
| 57363 | |
| 57364 | DUK_LOCAL duk_tval *duk__obtain_arridx_slot_slowpath(duk_hthread *thr, duk_uint32_t arr_idx, duk_hobject *obj) { |
| 57365 | /* |
| 57366 | * Array needs to grow, but we don't want it becoming too sparse. |
| 57367 | * If it were to become sparse, abandon array part, moving all |
| 57368 | * array entries into the entries part (for good). |
| 57369 | * |
| 57370 | * Since we don't keep track of actual density (used vs. size) of |
| 57371 | * the array part, we need to estimate somehow. The check is made |
| 57372 | * in two parts: |
| 57373 | * |
| 57374 | * - Check whether the resize need is small compared to the |
| 57375 | * current size (relatively); if so, resize without further |
| 57376 | * checking (essentially we assume that the original part is |
| 57377 | * "dense" so that the result would be dense enough). |
| 57378 | * |
| 57379 | * - Otherwise, compute the resize using an actual density |
| 57380 | * measurement based on counting the used array entries. |
| 57381 | */ |
| 57382 | |
| 57383 | DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a " |
| 57384 | "fast resize without abandon check (arr_idx=%ld, old_size=%ld)" , |
| 57385 | (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(obj))); |
| 57386 | |
| 57387 | if (DUK_UNLIKELY(duk__abandon_array_check(thr, arr_idx, obj) != 0)) { |
| 57388 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj)); |
| 57389 | return NULL; |
| 57390 | } |
| 57391 | |
| 57392 | DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, " |
| 57393 | "decided to extend current allocation" )); |
| 57394 | |
| 57395 | /* In principle it's possible to run out of memory extending the |
| 57396 | * array but with the allocation going through if we were to abandon |
| 57397 | * the array part and try again. In practice this should be rare |
| 57398 | * because abandoned arrays have a higher per-entry footprint. |
| 57399 | */ |
| 57400 | |
| 57401 | duk__grow_props_for_array_item(thr, obj, arr_idx); |
| 57402 | |
| 57403 | DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(obj)); |
| 57404 | DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj)); |
| 57405 | return DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx); |
| 57406 | } |
| 57407 | |
| 57408 | DUK_LOCAL DUK_INLINE duk_tval *duk__obtain_arridx_slot(duk_hthread *thr, duk_uint32_t arr_idx, duk_hobject *obj) { |
| 57409 | if (DUK_LIKELY(arr_idx < DUK_HOBJECT_GET_ASIZE(obj))) { |
| 57410 | return DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx); |
| 57411 | } else { |
| 57412 | return duk__obtain_arridx_slot_slowpath(thr, arr_idx, obj); |
| 57413 | } |
| 57414 | } |
| 57415 | |
| 57416 | /* |
| 57417 | * Proxy helpers |
| 57418 | */ |
| 57419 | |
| 57420 | #if defined(DUK_USE_ES6_PROXY) |
| 57421 | DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) { |
| 57422 | duk_hproxy *h_proxy; |
| 57423 | |
| 57424 | DUK_ASSERT(obj != NULL); |
| 57425 | DUK_ASSERT(out_target != NULL); |
| 57426 | DUK_ASSERT(out_handler != NULL); |
| 57427 | |
| 57428 | /* Caller doesn't need to check exotic proxy behavior (but does so for |
| 57429 | * some fast paths). |
| 57430 | */ |
| 57431 | if (DUK_LIKELY(!DUK_HOBJECT_IS_PROXY(obj))) { |
| 57432 | return 0; |
| 57433 | } |
| 57434 | h_proxy = (duk_hproxy *) obj; |
| 57435 | DUK_HPROXY_ASSERT_VALID(h_proxy); |
| 57436 | |
| 57437 | DUK_ASSERT(h_proxy->handler != NULL); |
| 57438 | DUK_ASSERT(h_proxy->target != NULL); |
| 57439 | *out_handler = h_proxy->handler; |
| 57440 | *out_target = h_proxy->target; |
| 57441 | |
| 57442 | return 1; |
| 57443 | } |
| 57444 | #endif /* DUK_USE_ES6_PROXY */ |
| 57445 | |
| 57446 | /* Get Proxy target object. If the argument is not a Proxy, return it as is. |
| 57447 | * If a Proxy is revoked, an error is thrown. |
| 57448 | */ |
| 57449 | #if defined(DUK_USE_ES6_PROXY) |
| 57450 | DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj) { |
| 57451 | DUK_ASSERT(obj != NULL); |
| 57452 | |
| 57453 | /* Resolve Proxy targets until Proxy chain ends. No explicit check for |
| 57454 | * a Proxy loop: user code cannot create such a loop (it would only be |
| 57455 | * possible by editing duk_hproxy references directly). |
| 57456 | */ |
| 57457 | |
| 57458 | while (DUK_HOBJECT_IS_PROXY(obj)) { |
| 57459 | duk_hproxy *h_proxy; |
| 57460 | |
| 57461 | h_proxy = (duk_hproxy *) obj; |
| 57462 | DUK_HPROXY_ASSERT_VALID(h_proxy); |
| 57463 | obj = h_proxy->target; |
| 57464 | DUK_ASSERT(obj != NULL); |
| 57465 | } |
| 57466 | |
| 57467 | DUK_ASSERT(obj != NULL); |
| 57468 | return obj; |
| 57469 | } |
| 57470 | #endif /* DUK_USE_ES6_PROXY */ |
| 57471 | |
| 57472 | #if defined(DUK_USE_ES6_PROXY) |
| 57473 | DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, duk_small_uint_t stridx_trap, duk_tval *tv_key, duk_hobject **out_target) { |
| 57474 | duk_hobject *h_handler; |
| 57475 | |
| 57476 | DUK_ASSERT(thr != NULL); |
| 57477 | DUK_ASSERT(obj != NULL); |
| 57478 | DUK_ASSERT(tv_key != NULL); |
| 57479 | DUK_ASSERT(out_target != NULL); |
| 57480 | |
| 57481 | if (!duk_hobject_proxy_check(obj, out_target, &h_handler)) { |
| 57482 | return 0; |
| 57483 | } |
| 57484 | DUK_ASSERT(*out_target != NULL); |
| 57485 | DUK_ASSERT(h_handler != NULL); |
| 57486 | |
| 57487 | /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a |
| 57488 | * normal property set/get which would allow a proxy handler to interfere with |
| 57489 | * such behavior and to get access to internal key strings. This is not a problem |
| 57490 | * as such because internal key strings can be created in other ways too (e.g. |
| 57491 | * through buffers). The best fix is to change Duktape internal lookups to |
| 57492 | * skip proxy behavior. Until that, internal property accesses bypass the |
| 57493 | * proxy and are applied to the target (as if the handler did not exist). |
| 57494 | * This has some side effects, see test-bi-proxy-internal-keys.js. |
| 57495 | */ |
| 57496 | |
| 57497 | if (DUK_TVAL_IS_STRING(tv_key)) { |
| 57498 | duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key); |
| 57499 | DUK_ASSERT(h_key != NULL); |
| 57500 | if (DUK_HSTRING_HAS_HIDDEN(h_key)) { |
| 57501 | /* Symbol accesses must go through proxy lookup in ES2015. |
| 57502 | * Hidden symbols behave like Duktape 1.x internal keys |
| 57503 | * and currently won't. |
| 57504 | */ |
| 57505 | DUK_DDD(DUK_DDDPRINT("hidden key, skip proxy handler and apply to target" )); |
| 57506 | return 0; |
| 57507 | } |
| 57508 | } |
| 57509 | |
| 57510 | /* The handler is looked up with a normal property lookup; it may be an |
| 57511 | * accessor or the handler object itself may be a proxy object. If the |
| 57512 | * handler is a proxy, we need to extend the valstack as we make a |
| 57513 | * recursive proxy check without a function call in between (in fact |
| 57514 | * there is no limit to the potential recursion here). |
| 57515 | * |
| 57516 | * (For sanity, proxy creation rejects another proxy object as either |
| 57517 | * the handler or the target at the moment so recursive proxy cases |
| 57518 | * are not realized now.) |
| 57519 | */ |
| 57520 | |
| 57521 | /* XXX: C recursion limit if proxies are allowed as handler/target values */ |
| 57522 | |
| 57523 | duk_require_stack(thr, DUK__VALSTACK_PROXY_LOOKUP); |
| 57524 | duk_push_hobject(thr, h_handler); |
| 57525 | if (duk_get_prop_stridx_short(thr, -1, stridx_trap)) { |
| 57526 | /* -> [ ... handler trap ] */ |
| 57527 | duk_insert(thr, -2); /* -> [ ... trap handler ] */ |
| 57528 | |
| 57529 | /* stack prepped for func call: [ ... trap handler ] */ |
| 57530 | return 1; |
| 57531 | } else { |
| 57532 | duk_pop_2_unsafe(thr); |
| 57533 | return 0; |
| 57534 | } |
| 57535 | } |
| 57536 | #endif /* DUK_USE_ES6_PROXY */ |
| 57537 | |
| 57538 | /* |
| 57539 | * Reallocate property allocation, moving properties to the new allocation. |
| 57540 | * |
| 57541 | * Includes key compaction, rehashing, and can also optionally abandon |
| 57542 | * the array part, 'migrating' array entries into the beginning of the |
| 57543 | * new entry part. |
| 57544 | * |
| 57545 | * There is no support for in-place reallocation or just compacting keys |
| 57546 | * without resizing the property allocation. This is intentional to keep |
| 57547 | * code size minimal, but would be useful future work. |
| 57548 | * |
| 57549 | * The implementation is relatively straightforward, except for the array |
| 57550 | * abandonment process. Array abandonment requires that new string keys |
| 57551 | * are interned, which may trigger GC. All keys interned so far must be |
| 57552 | * reachable for GC at all times and correctly refcounted for; valstack is |
| 57553 | * used for that now. |
| 57554 | * |
| 57555 | * Also, a GC triggered during this reallocation process must not interfere |
| 57556 | * with the object being resized. This is currently controlled by preventing |
| 57557 | * finalizers (as they may affect ANY object) and object compaction in |
| 57558 | * mark-and-sweep. It would suffice to protect only this particular object |
| 57559 | * from compaction, however. DECREF refzero cascades are side effect free |
| 57560 | * and OK. |
| 57561 | * |
| 57562 | * Note: because we need to potentially resize the valstack (as part |
| 57563 | * of abandoning the array part), any tval pointers to the valstack |
| 57564 | * will become invalid after this call. |
| 57565 | */ |
| 57566 | |
| 57567 | DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr, |
| 57568 | duk_hobject *obj, |
| 57569 | duk_uint32_t new_e_size, |
| 57570 | duk_uint32_t new_a_size, |
| 57571 | duk_uint32_t new_h_size, |
| 57572 | duk_bool_t abandon_array) { |
| 57573 | duk_small_uint_t prev_ms_base_flags; |
| 57574 | duk_uint32_t new_alloc_size; |
| 57575 | duk_uint32_t new_e_size_adjusted; |
| 57576 | duk_uint8_t *new_p; |
| 57577 | duk_hstring **new_e_k; |
| 57578 | duk_propvalue *new_e_pv; |
| 57579 | duk_uint8_t *new_e_f; |
| 57580 | duk_tval *new_a; |
| 57581 | duk_uint32_t *new_h; |
| 57582 | duk_uint32_t new_e_next; |
| 57583 | duk_uint_fast32_t i; |
| 57584 | duk_size_t array_copy_size; |
| 57585 | #if defined(DUK_USE_ASSERTIONS) |
| 57586 | duk_bool_t prev_error_not_allowed; |
| 57587 | #endif |
| 57588 | |
| 57589 | DUK_ASSERT(thr != NULL); |
| 57590 | DUK_ASSERT(obj != NULL); |
| 57591 | DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */ |
| 57592 | DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0)); |
| 57593 | DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); /* required to guarantee success of rehashing, |
| 57594 | * intentionally use unadjusted new_e_size |
| 57595 | */ |
| 57596 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); |
| 57597 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 57598 | |
| 57599 | DUK_STATS_INC(thr->heap, stats_object_realloc_props); |
| 57600 | |
| 57601 | /* |
| 57602 | * Pre resize assertions. |
| 57603 | */ |
| 57604 | |
| 57605 | #if defined(DUK_USE_ASSERTIONS) |
| 57606 | /* XXX: pre-checks (such as no duplicate keys) */ |
| 57607 | #endif |
| 57608 | |
| 57609 | /* |
| 57610 | * For property layout 1, tweak e_size to ensure that the whole entry |
| 57611 | * part (key + val + flags) is a suitable multiple for alignment |
| 57612 | * (platform specific). |
| 57613 | * |
| 57614 | * Property layout 2 does not require this tweaking and is preferred |
| 57615 | * on low RAM platforms requiring alignment. |
| 57616 | */ |
| 57617 | |
| 57618 | #if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3) |
| 57619 | DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld" , (long) new_e_size)); |
| 57620 | new_e_size_adjusted = new_e_size; |
| 57621 | #elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1) |
| 57622 | DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld" , (long) new_e_size)); |
| 57623 | new_e_size_adjusted = new_e_size; |
| 57624 | #elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8)) |
| 57625 | new_e_size_adjusted = (new_e_size + (duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U) & |
| 57626 | (~((duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U)); |
| 57627 | DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld" , |
| 57628 | (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted)); |
| 57629 | DUK_ASSERT(new_e_size_adjusted >= new_e_size); |
| 57630 | #else |
| 57631 | #error invalid hobject layout defines |
| 57632 | #endif |
| 57633 | |
| 57634 | /* |
| 57635 | * Debug logging after adjustment. |
| 57636 | */ |
| 57637 | |
| 57638 | DUK_DDD(DUK_DDDPRINT("attempt to resize hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to " |
| 57639 | "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld" , |
| 57640 | (void *) obj, |
| 57641 | (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), |
| 57642 | DUK_HOBJECT_GET_ASIZE(obj), |
| 57643 | DUK_HOBJECT_GET_HSIZE(obj)), |
| 57644 | (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size), |
| 57645 | (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj), |
| 57646 | (long) DUK_HOBJECT_GET_ESIZE(obj), |
| 57647 | (long) DUK_HOBJECT_GET_ENEXT(obj), |
| 57648 | (long) DUK_HOBJECT_GET_ASIZE(obj), |
| 57649 | (long) DUK_HOBJECT_GET_HSIZE(obj), |
| 57650 | (long) new_e_size_adjusted, |
| 57651 | (long) new_a_size, |
| 57652 | (long) new_h_size, |
| 57653 | (long) abandon_array, |
| 57654 | (long) new_e_size)); |
| 57655 | |
| 57656 | /* |
| 57657 | * Property count check. This is the only point where we ensure that |
| 57658 | * we don't get more (allocated) property space that we can handle. |
| 57659 | * There aren't hard limits as such, but some algorithms may fail |
| 57660 | * if we get too close to the 4G property limit. |
| 57661 | * |
| 57662 | * Since this works based on allocation size (not actually used size), |
| 57663 | * the limit is a bit approximate but good enough in practice. |
| 57664 | */ |
| 57665 | |
| 57666 | if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) { |
| 57667 | DUK_ERROR_ALLOC_FAILED(thr); |
| 57668 | DUK_WO_NORETURN(return;); |
| 57669 | } |
| 57670 | #if defined(DUK_USE_OBJSIZES16) |
| 57671 | if (new_e_size_adjusted > DUK_UINT16_MAX || new_a_size > DUK_UINT16_MAX) { |
| 57672 | /* If caller gave us sizes larger than what we can store, |
| 57673 | * fail memory safely with an internal error rather than |
| 57674 | * truncating the sizes. |
| 57675 | */ |
| 57676 | DUK_ERROR_INTERNAL(thr); |
| 57677 | DUK_WO_NORETURN(return;); |
| 57678 | } |
| 57679 | #endif |
| 57680 | |
| 57681 | /* |
| 57682 | * Compute new alloc size and alloc new area. |
| 57683 | * |
| 57684 | * The new area is not tracked in the heap at all, so it's critical |
| 57685 | * we get to free/keep it in a controlled manner. |
| 57686 | */ |
| 57687 | |
| 57688 | #if defined(DUK_USE_ASSERTIONS) |
| 57689 | /* Whole path must be error throw free, but we may be called from |
| 57690 | * within error handling so can't assert for error_not_allowed == 0. |
| 57691 | */ |
| 57692 | prev_error_not_allowed = thr->heap->error_not_allowed; |
| 57693 | thr->heap->error_not_allowed = 1; |
| 57694 | #endif |
| 57695 | prev_ms_base_flags = thr->heap->ms_base_flags; |
| 57696 | thr->heap->ms_base_flags |= |
| 57697 | DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* Avoid attempt to compact the current object (all objects really). */ |
| 57698 | thr->heap->pf_prevent_count++; /* Avoid finalizers. */ |
| 57699 | DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */ |
| 57700 | |
| 57701 | new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size); |
| 57702 | DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld" , (long) new_alloc_size)); |
| 57703 | if (new_alloc_size == 0) { |
| 57704 | DUK_ASSERT(new_e_size_adjusted == 0); |
| 57705 | DUK_ASSERT(new_a_size == 0); |
| 57706 | DUK_ASSERT(new_h_size == 0); |
| 57707 | new_p = NULL; |
| 57708 | } else { |
| 57709 | /* Alloc may trigger mark-and-sweep but no compaction, and |
| 57710 | * cannot throw. |
| 57711 | */ |
| 57712 | #if 0 /* XXX: inject test */ |
| 57713 | if (1) { |
| 57714 | new_p = NULL; |
| 57715 | goto alloc_failed; |
| 57716 | } |
| 57717 | #endif |
| 57718 | new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size); |
| 57719 | if (new_p == NULL) { |
| 57720 | /* NULL always indicates alloc failure because |
| 57721 | * new_alloc_size > 0. |
| 57722 | */ |
| 57723 | goto alloc_failed; |
| 57724 | } |
| 57725 | } |
| 57726 | |
| 57727 | /* Set up pointers to the new property area: this is hidden behind a macro |
| 57728 | * because it is memory layout specific. |
| 57729 | */ |
| 57730 | DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h, |
| 57731 | new_e_size_adjusted, new_a_size, new_h_size); |
| 57732 | DUK_UNREF(new_h); /* happens when hash part dropped */ |
| 57733 | new_e_next = 0; |
| 57734 | |
| 57735 | /* if new_p == NULL, all of these pointers are NULL */ |
| 57736 | DUK_ASSERT((new_p != NULL) || |
| 57737 | (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL && |
| 57738 | new_a == NULL && new_h == NULL)); |
| 57739 | |
| 57740 | DUK_DDD(DUK_DDDPRINT("new alloc size %ld, new_e_k=%p, new_e_pv=%p, new_e_f=%p, new_a=%p, new_h=%p" , |
| 57741 | (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f, |
| 57742 | (void *) new_a, (void *) new_h)); |
| 57743 | |
| 57744 | /* |
| 57745 | * Migrate array part to start of entries if requested. |
| 57746 | * |
| 57747 | * Note: from an enumeration perspective the order of entry keys matters. |
| 57748 | * Array keys should appear wherever they appeared before the array abandon |
| 57749 | * operation. (This no longer matters much because keys are ES2015 sorted.) |
| 57750 | */ |
| 57751 | |
| 57752 | if (abandon_array) { |
| 57753 | /* Assuming new_a_size == 0, and that entry part contains |
| 57754 | * no conflicting keys, refcounts do not need to be adjusted for |
| 57755 | * the values, as they remain exactly the same. |
| 57756 | * |
| 57757 | * The keys, however, need to be interned, incref'd, and be |
| 57758 | * reachable for GC. Any intern attempt may trigger a GC and |
| 57759 | * claim any non-reachable strings, so every key must be reachable |
| 57760 | * at all times. Refcounts must be correct to satisfy refcount |
| 57761 | * assertions. |
| 57762 | * |
| 57763 | * A longjmp must not occur here, as the new_p allocation would |
| 57764 | * leak. Refcounts would come out correctly as the interned |
| 57765 | * strings are valstack tracked. |
| 57766 | */ |
| 57767 | DUK_ASSERT(new_a_size == 0); |
| 57768 | |
| 57769 | DUK_STATS_INC(thr->heap, stats_object_abandon_array); |
| 57770 | |
| 57771 | for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { |
| 57772 | duk_tval *tv1; |
| 57773 | duk_tval *tv2; |
| 57774 | duk_hstring *key; |
| 57775 | |
| 57776 | DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); |
| 57777 | |
| 57778 | tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); |
| 57779 | if (DUK_TVAL_IS_UNUSED(tv1)) { |
| 57780 | continue; |
| 57781 | } |
| 57782 | |
| 57783 | DUK_ASSERT(new_p != NULL && new_e_k != NULL && |
| 57784 | new_e_pv != NULL && new_e_f != NULL); |
| 57785 | |
| 57786 | /* |
| 57787 | * Intern key via the valstack to ensure reachability behaves |
| 57788 | * properly. We must avoid longjmp's here so use non-checked |
| 57789 | * primitives. |
| 57790 | * |
| 57791 | * Note: duk_check_stack() potentially reallocs the valstack, |
| 57792 | * invalidating any duk_tval pointers to valstack. Callers |
| 57793 | * must be careful. |
| 57794 | */ |
| 57795 | |
| 57796 | #if 0 /* XXX: inject test */ |
| 57797 | if (1) { |
| 57798 | goto abandon_error; |
| 57799 | } |
| 57800 | #endif |
| 57801 | /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which |
| 57802 | * is generous. |
| 57803 | */ |
| 57804 | if (!duk_check_stack(thr, 1)) { |
| 57805 | goto abandon_error; |
| 57806 | } |
| 57807 | DUK_ASSERT_VALSTACK_SPACE(thr, 1); |
| 57808 | key = duk_heap_strtable_intern_u32(thr->heap, (duk_uint32_t) i); |
| 57809 | if (key == NULL) { |
| 57810 | goto abandon_error; |
| 57811 | } |
| 57812 | duk_push_hstring(thr, key); /* keep key reachable for GC etc; guaranteed not to fail */ |
| 57813 | |
| 57814 | /* Key is now reachable in the valstack, don't INCREF |
| 57815 | * the new allocation yet (we'll steal the refcounts |
| 57816 | * from the value stack once all keys are done). |
| 57817 | */ |
| 57818 | |
| 57819 | new_e_k[new_e_next] = key; |
| 57820 | tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */ |
| 57821 | DUK_TVAL_SET_TVAL(tv2, tv1); |
| 57822 | new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE | |
| 57823 | DUK_PROPDESC_FLAG_ENUMERABLE | |
| 57824 | DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 57825 | new_e_next++; |
| 57826 | |
| 57827 | /* Note: new_e_next matches pushed temp key count, and nothing can |
| 57828 | * fail above between the push and this point. |
| 57829 | */ |
| 57830 | } |
| 57831 | |
| 57832 | /* Steal refcounts from value stack. */ |
| 57833 | DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack" , (long) new_e_next)); |
| 57834 | duk_pop_n_nodecref_unsafe(thr, (duk_idx_t) new_e_next); |
| 57835 | } |
| 57836 | |
| 57837 | /* |
| 57838 | * Copy keys and values in the entry part (compacting them at the same time). |
| 57839 | */ |
| 57840 | |
| 57841 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 57842 | duk_hstring *key; |
| 57843 | |
| 57844 | DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL); |
| 57845 | |
| 57846 | key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); |
| 57847 | if (key == NULL) { |
| 57848 | continue; |
| 57849 | } |
| 57850 | |
| 57851 | DUK_ASSERT(new_p != NULL && new_e_k != NULL && |
| 57852 | new_e_pv != NULL && new_e_f != NULL); |
| 57853 | |
| 57854 | new_e_k[new_e_next] = key; |
| 57855 | new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i); |
| 57856 | new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i); |
| 57857 | new_e_next++; |
| 57858 | } |
| 57859 | /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */ |
| 57860 | |
| 57861 | /* |
| 57862 | * Copy array elements to new array part. If the new array part is |
| 57863 | * larger, initialize the unused entries as UNUSED because they are |
| 57864 | * GC reachable. |
| 57865 | */ |
| 57866 | |
| 57867 | #if defined(DUK_USE_ASSERTIONS) |
| 57868 | /* Caller must have decref'd values above new_a_size (if that is necessary). */ |
| 57869 | if (!abandon_array) { |
| 57870 | for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { |
| 57871 | duk_tval *tv; |
| 57872 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); |
| 57873 | DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); |
| 57874 | } |
| 57875 | } |
| 57876 | #endif |
| 57877 | if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) { |
| 57878 | array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj); |
| 57879 | } else { |
| 57880 | array_copy_size = sizeof(duk_tval) * new_a_size; |
| 57881 | } |
| 57882 | |
| 57883 | DUK_ASSERT(new_a != NULL || array_copy_size == 0U); |
| 57884 | DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || array_copy_size == 0U); |
| 57885 | DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0 || array_copy_size == 0U); |
| 57886 | duk_memcpy_unsafe((void *) new_a, |
| 57887 | (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), |
| 57888 | array_copy_size); |
| 57889 | |
| 57890 | for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) { |
| 57891 | duk_tval *tv = &new_a[i]; |
| 57892 | DUK_TVAL_SET_UNUSED(tv); |
| 57893 | } |
| 57894 | |
| 57895 | /* |
| 57896 | * Rebuild the hash part always from scratch (guaranteed to finish |
| 57897 | * as long as caller gave consistent parameters). |
| 57898 | * |
| 57899 | * Any resize of hash part requires rehashing. In addition, by rehashing |
| 57900 | * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical |
| 57901 | * to ensuring the hash part never fills up. |
| 57902 | */ |
| 57903 | |
| 57904 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 57905 | if (new_h_size == 0) { |
| 57906 | DUK_DDD(DUK_DDDPRINT("no hash part, no rehash" )); |
| 57907 | } else { |
| 57908 | duk_uint32_t mask; |
| 57909 | |
| 57910 | DUK_ASSERT(new_h != NULL); |
| 57911 | |
| 57912 | /* fill new_h with u32 0xff = UNUSED */ |
| 57913 | DUK_ASSERT(new_h_size > 0); |
| 57914 | duk_memset(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size); |
| 57915 | |
| 57916 | DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */ |
| 57917 | |
| 57918 | mask = new_h_size - 1; |
| 57919 | for (i = 0; i < new_e_next; i++) { |
| 57920 | duk_hstring *key = new_e_k[i]; |
| 57921 | duk_uint32_t j, step; |
| 57922 | |
| 57923 | DUK_ASSERT(key != NULL); |
| 57924 | j = DUK_HSTRING_GET_HASH(key) & mask; |
| 57925 | step = 1; /* Cache friendly but clustering prone. */ |
| 57926 | |
| 57927 | for (;;) { |
| 57928 | DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */ |
| 57929 | if (new_h[j] == DUK__HASH_UNUSED) { |
| 57930 | DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld" , (long) j, (long) i)); |
| 57931 | new_h[j] = (duk_uint32_t) i; |
| 57932 | break; |
| 57933 | } |
| 57934 | DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld" , (long) j, (long) step)); |
| 57935 | j = (j + step) & mask; |
| 57936 | |
| 57937 | /* Guaranteed to finish (hash is larger than #props). */ |
| 57938 | } |
| 57939 | } |
| 57940 | } |
| 57941 | #endif /* DUK_USE_HOBJECT_HASH_PART */ |
| 57942 | |
| 57943 | /* |
| 57944 | * Nice debug log. |
| 57945 | */ |
| 57946 | |
| 57947 | DUK_DD(DUK_DDPRINT("resized hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to " |
| 57948 | "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld" , |
| 57949 | (void *) obj, |
| 57950 | (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), |
| 57951 | DUK_HOBJECT_GET_ASIZE(obj), |
| 57952 | DUK_HOBJECT_GET_HSIZE(obj)), |
| 57953 | (long) new_alloc_size, |
| 57954 | (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj), |
| 57955 | (long) DUK_HOBJECT_GET_ESIZE(obj), |
| 57956 | (long) DUK_HOBJECT_GET_ENEXT(obj), |
| 57957 | (long) DUK_HOBJECT_GET_ASIZE(obj), |
| 57958 | (long) DUK_HOBJECT_GET_HSIZE(obj), |
| 57959 | (void *) new_p, |
| 57960 | (long) new_e_size_adjusted, |
| 57961 | (long) new_e_next, |
| 57962 | (long) new_a_size, |
| 57963 | (long) new_h_size, |
| 57964 | (long) abandon_array, |
| 57965 | (long) new_e_size)); |
| 57966 | |
| 57967 | /* |
| 57968 | * All done, switch properties ('p') allocation to new one. |
| 57969 | */ |
| 57970 | |
| 57971 | DUK_FREE_CHECKED(thr, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */ |
| 57972 | DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p); |
| 57973 | DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted); |
| 57974 | DUK_HOBJECT_SET_ENEXT(obj, new_e_next); |
| 57975 | DUK_HOBJECT_SET_ASIZE(obj, new_a_size); |
| 57976 | DUK_HOBJECT_SET_HSIZE(obj, new_h_size); |
| 57977 | |
| 57978 | /* Clear array part flag only after switching. */ |
| 57979 | if (abandon_array) { |
| 57980 | DUK_HOBJECT_CLEAR_ARRAY_PART(obj); |
| 57981 | } |
| 57982 | |
| 57983 | DUK_DDD(DUK_DDDPRINT("resize result: %!O" , (duk_heaphdr *) obj)); |
| 57984 | |
| 57985 | DUK_ASSERT(thr->heap->pf_prevent_count > 0); |
| 57986 | thr->heap->pf_prevent_count--; |
| 57987 | thr->heap->ms_base_flags = prev_ms_base_flags; |
| 57988 | #if defined(DUK_USE_ASSERTIONS) |
| 57989 | DUK_ASSERT(thr->heap->error_not_allowed == 1); |
| 57990 | thr->heap->error_not_allowed = prev_error_not_allowed; |
| 57991 | #endif |
| 57992 | |
| 57993 | /* |
| 57994 | * Post resize assertions. |
| 57995 | */ |
| 57996 | |
| 57997 | #if defined(DUK_USE_ASSERTIONS) |
| 57998 | /* XXX: post-checks (such as no duplicate keys) */ |
| 57999 | #endif |
| 58000 | return; |
| 58001 | |
| 58002 | /* |
| 58003 | * Abandon array failed. We don't need to DECREF anything |
| 58004 | * because the references in the new allocation are not |
| 58005 | * INCREF'd until abandon is complete. The string interned |
| 58006 | * keys are on the value stack and are handled normally by |
| 58007 | * unwind. |
| 58008 | */ |
| 58009 | |
| 58010 | abandon_error: |
| 58011 | alloc_failed: |
| 58012 | DUK_D(DUK_DPRINT("object property table resize failed" )); |
| 58013 | |
| 58014 | DUK_FREE_CHECKED(thr, new_p); /* OK for NULL. */ |
| 58015 | |
| 58016 | thr->heap->pf_prevent_count--; |
| 58017 | thr->heap->ms_base_flags = prev_ms_base_flags; |
| 58018 | #if defined(DUK_USE_ASSERTIONS) |
| 58019 | DUK_ASSERT(thr->heap->error_not_allowed == 1); |
| 58020 | thr->heap->error_not_allowed = prev_error_not_allowed; |
| 58021 | #endif |
| 58022 | |
| 58023 | DUK_ERROR_ALLOC_FAILED(thr); |
| 58024 | DUK_WO_NORETURN(return;); |
| 58025 | } |
| 58026 | |
| 58027 | /* |
| 58028 | * Helpers to resize properties allocation on specific needs. |
| 58029 | */ |
| 58030 | |
| 58031 | DUK_INTERNAL void duk_hobject_resize_entrypart(duk_hthread *thr, |
| 58032 | duk_hobject *obj, |
| 58033 | duk_uint32_t new_e_size) { |
| 58034 | duk_uint32_t old_e_size; |
| 58035 | duk_uint32_t new_a_size; |
| 58036 | duk_uint32_t new_h_size; |
| 58037 | |
| 58038 | DUK_ASSERT(thr != NULL); |
| 58039 | DUK_ASSERT(obj != NULL); |
| 58040 | |
| 58041 | old_e_size = DUK_HOBJECT_GET_ESIZE(obj); |
| 58042 | if (old_e_size > new_e_size) { |
| 58043 | new_e_size = old_e_size; |
| 58044 | } |
| 58045 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 58046 | new_h_size = duk__get_default_h_size(new_e_size); |
| 58047 | #else |
| 58048 | new_h_size = 0; |
| 58049 | #endif |
| 58050 | new_a_size = DUK_HOBJECT_GET_ASIZE(obj); |
| 58051 | |
| 58052 | duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0); |
| 58053 | } |
| 58054 | |
| 58055 | /* Grow entry part allocation for one additional entry. */ |
| 58056 | DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) { |
| 58057 | duk_uint32_t old_e_used; /* actually used, non-NULL entries */ |
| 58058 | duk_uint32_t new_e_size_minimum; |
| 58059 | duk_uint32_t new_e_size; |
| 58060 | duk_uint32_t new_a_size; |
| 58061 | duk_uint32_t new_h_size; |
| 58062 | |
| 58063 | DUK_ASSERT(thr != NULL); |
| 58064 | DUK_ASSERT(obj != NULL); |
| 58065 | |
| 58066 | /* Duktape 0.11.0 and prior tried to optimize the resize by not |
| 58067 | * counting the number of actually used keys prior to the resize. |
| 58068 | * This worked mostly well but also caused weird leak-like behavior |
| 58069 | * as in: test-bug-object-prop-alloc-unbounded.js. So, now we count |
| 58070 | * the keys explicitly to compute the new entry part size. |
| 58071 | */ |
| 58072 | |
| 58073 | old_e_used = duk__count_used_e_keys(thr, obj); |
| 58074 | new_e_size_minimum = old_e_used + 1; |
| 58075 | new_e_size = old_e_used + duk__get_min_grow_e(old_e_used); |
| 58076 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 58077 | new_h_size = duk__get_default_h_size(new_e_size); |
| 58078 | #else |
| 58079 | new_h_size = 0; |
| 58080 | #endif |
| 58081 | new_a_size = DUK_HOBJECT_GET_ASIZE(obj); |
| 58082 | |
| 58083 | #if defined(DUK_USE_OBJSIZES16) |
| 58084 | if (new_e_size > DUK_UINT16_MAX) { |
| 58085 | new_e_size = DUK_UINT16_MAX; |
| 58086 | } |
| 58087 | if (new_h_size > DUK_UINT16_MAX) { |
| 58088 | new_h_size = DUK_UINT16_MAX; |
| 58089 | } |
| 58090 | if (new_a_size > DUK_UINT16_MAX) { |
| 58091 | new_a_size = DUK_UINT16_MAX; |
| 58092 | } |
| 58093 | #endif |
| 58094 | DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); |
| 58095 | |
| 58096 | if (!(new_e_size >= new_e_size_minimum)) { |
| 58097 | DUK_ERROR_ALLOC_FAILED(thr); |
| 58098 | DUK_WO_NORETURN(return;); |
| 58099 | } |
| 58100 | |
| 58101 | duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0); |
| 58102 | } |
| 58103 | |
| 58104 | /* Grow array part for a new highest array index. */ |
| 58105 | DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) { |
| 58106 | duk_uint32_t new_e_size; |
| 58107 | duk_uint32_t new_a_size; |
| 58108 | duk_uint32_t new_a_size_minimum; |
| 58109 | duk_uint32_t new_h_size; |
| 58110 | |
| 58111 | DUK_ASSERT(thr != NULL); |
| 58112 | DUK_ASSERT(obj != NULL); |
| 58113 | DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)); |
| 58114 | |
| 58115 | new_e_size = DUK_HOBJECT_GET_ESIZE(obj); |
| 58116 | new_h_size = DUK_HOBJECT_GET_HSIZE(obj); |
| 58117 | new_a_size_minimum = highest_arr_idx + 1; |
| 58118 | new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx); |
| 58119 | DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */ |
| 58120 | |
| 58121 | #if defined(DUK_USE_OBJSIZES16) |
| 58122 | if (new_e_size > DUK_UINT16_MAX) { |
| 58123 | new_e_size = DUK_UINT16_MAX; |
| 58124 | } |
| 58125 | if (new_h_size > DUK_UINT16_MAX) { |
| 58126 | new_h_size = DUK_UINT16_MAX; |
| 58127 | } |
| 58128 | if (new_a_size > DUK_UINT16_MAX) { |
| 58129 | new_a_size = DUK_UINT16_MAX; |
| 58130 | } |
| 58131 | #endif |
| 58132 | |
| 58133 | if (!(new_a_size >= new_a_size_minimum)) { |
| 58134 | DUK_ERROR_ALLOC_FAILED(thr); |
| 58135 | DUK_WO_NORETURN(return;); |
| 58136 | } |
| 58137 | |
| 58138 | duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0); |
| 58139 | } |
| 58140 | |
| 58141 | /* Abandon array part, moving array entries into entries part. |
| 58142 | * This requires a props resize, which is a heavy operation. |
| 58143 | * We also compact the entries part while we're at it, although |
| 58144 | * this is not strictly required. |
| 58145 | */ |
| 58146 | DUK_LOCAL void duk__abandon_array_part(duk_hthread *thr, duk_hobject *obj) { |
| 58147 | duk_uint32_t new_e_size_minimum; |
| 58148 | duk_uint32_t new_e_size; |
| 58149 | duk_uint32_t new_a_size; |
| 58150 | duk_uint32_t new_h_size; |
| 58151 | duk_uint32_t e_used; /* actually used, non-NULL keys */ |
| 58152 | duk_uint32_t a_used; |
| 58153 | duk_uint32_t a_size; |
| 58154 | |
| 58155 | DUK_ASSERT(thr != NULL); |
| 58156 | DUK_ASSERT(obj != NULL); |
| 58157 | |
| 58158 | e_used = duk__count_used_e_keys(thr, obj); |
| 58159 | duk__compute_a_stats(thr, obj, &a_used, &a_size); |
| 58160 | |
| 58161 | /* |
| 58162 | * Must guarantee all actually used array entries will fit into |
| 58163 | * new entry part. Add one growth step to ensure we don't run out |
| 58164 | * of space right away. |
| 58165 | */ |
| 58166 | |
| 58167 | new_e_size_minimum = e_used + a_used; |
| 58168 | new_e_size = new_e_size_minimum + duk__get_min_grow_e(new_e_size_minimum); |
| 58169 | new_a_size = 0; |
| 58170 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 58171 | new_h_size = duk__get_default_h_size(new_e_size); |
| 58172 | #else |
| 58173 | new_h_size = 0; |
| 58174 | #endif |
| 58175 | |
| 58176 | #if defined(DUK_USE_OBJSIZES16) |
| 58177 | if (new_e_size > DUK_UINT16_MAX) { |
| 58178 | new_e_size = DUK_UINT16_MAX; |
| 58179 | } |
| 58180 | if (new_h_size > DUK_UINT16_MAX) { |
| 58181 | new_h_size = DUK_UINT16_MAX; |
| 58182 | } |
| 58183 | if (new_a_size > DUK_UINT16_MAX) { |
| 58184 | new_a_size = DUK_UINT16_MAX; |
| 58185 | } |
| 58186 | #endif |
| 58187 | |
| 58188 | if (!(new_e_size >= new_e_size_minimum)) { |
| 58189 | DUK_ERROR_ALLOC_FAILED(thr); |
| 58190 | DUK_WO_NORETURN(return;); |
| 58191 | } |
| 58192 | |
| 58193 | DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, " |
| 58194 | "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; " |
| 58195 | "resize to e_size=%ld, a_size=%ld, h_size=%ld" , |
| 58196 | (void *) obj, (long) e_used, (long) a_used, (long) a_size, |
| 58197 | (long) new_e_size, (long) new_a_size, (long) new_h_size)); |
| 58198 | |
| 58199 | duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1); |
| 58200 | } |
| 58201 | |
| 58202 | /* |
| 58203 | * Compact an object. Minimizes allocation size for objects which are |
| 58204 | * not likely to be extended. This is useful for internal and non- |
| 58205 | * extensible objects, but can also be called for non-extensible objects. |
| 58206 | * May abandon the array part if it is computed to be too sparse. |
| 58207 | * |
| 58208 | * This call is relatively expensive, as it needs to scan both the |
| 58209 | * entries and the array part. |
| 58210 | * |
| 58211 | * The call may fail due to allocation error. |
| 58212 | */ |
| 58213 | |
| 58214 | DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) { |
| 58215 | duk_uint32_t e_size; /* currently used -> new size */ |
| 58216 | duk_uint32_t a_size; /* currently required */ |
| 58217 | duk_uint32_t a_used; /* actually used */ |
| 58218 | duk_uint32_t h_size; |
| 58219 | duk_bool_t abandon_array; |
| 58220 | |
| 58221 | DUK_ASSERT(thr != NULL); |
| 58222 | DUK_ASSERT(obj != NULL); |
| 58223 | |
| 58224 | #if defined(DUK_USE_ROM_OBJECTS) |
| 58225 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { |
| 58226 | DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object" )); |
| 58227 | return; |
| 58228 | } |
| 58229 | #endif |
| 58230 | |
| 58231 | e_size = duk__count_used_e_keys(thr, obj); |
| 58232 | duk__compute_a_stats(thr, obj, &a_used, &a_size); |
| 58233 | |
| 58234 | DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, " |
| 58235 | "resized array density would be: %ld/%ld = %lf" , |
| 58236 | (long) e_size, (long) a_used, (long) a_size, |
| 58237 | (long) a_used, (long) a_size, |
| 58238 | (double) a_used / (double) a_size)); |
| 58239 | |
| 58240 | if (duk__abandon_array_density_check(a_used, a_size)) { |
| 58241 | DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld" , |
| 58242 | (long) a_used, (long) a_size)); |
| 58243 | abandon_array = 1; |
| 58244 | e_size += a_used; |
| 58245 | a_size = 0; |
| 58246 | } else { |
| 58247 | DUK_DD(DUK_DDPRINT("decided to keep array during compaction" )); |
| 58248 | abandon_array = 0; |
| 58249 | } |
| 58250 | |
| 58251 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 58252 | if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) { |
| 58253 | h_size = duk__get_default_h_size(e_size); |
| 58254 | } else { |
| 58255 | h_size = 0; |
| 58256 | } |
| 58257 | #else |
| 58258 | h_size = 0; |
| 58259 | #endif |
| 58260 | |
| 58261 | DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld" , |
| 58262 | (long) e_size, (long) a_size, (long) h_size, (long) abandon_array)); |
| 58263 | |
| 58264 | duk_hobject_realloc_props(thr, obj, e_size, a_size, h_size, abandon_array); |
| 58265 | } |
| 58266 | |
| 58267 | /* |
| 58268 | * Find an existing key from entry part either by linear scan or by |
| 58269 | * using the hash index (if it exists). |
| 58270 | * |
| 58271 | * Sets entry index (and possibly the hash index) to output variables, |
| 58272 | * which allows the caller to update the entry and hash entries in-place. |
| 58273 | * If entry is not found, both values are set to -1. If entry is found |
| 58274 | * but there is no hash part, h_idx is set to -1. |
| 58275 | */ |
| 58276 | |
| 58277 | DUK_INTERNAL duk_bool_t duk_hobject_find_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) { |
| 58278 | DUK_ASSERT(obj != NULL); |
| 58279 | DUK_ASSERT(key != NULL); |
| 58280 | DUK_ASSERT(e_idx != NULL); |
| 58281 | DUK_ASSERT(h_idx != NULL); |
| 58282 | DUK_UNREF(heap); |
| 58283 | |
| 58284 | if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0)) |
| 58285 | { |
| 58286 | /* Linear scan: more likely because most objects are small. |
| 58287 | * This is an important fast path. |
| 58288 | * |
| 58289 | * XXX: this might be worth inlining for property lookups. |
| 58290 | */ |
| 58291 | duk_uint_fast32_t i; |
| 58292 | duk_uint_fast32_t n; |
| 58293 | duk_hstring **h_keys_base; |
| 58294 | DUK_DDD(DUK_DDDPRINT("duk_hobject_find_entry() using linear scan for lookup" )); |
| 58295 | |
| 58296 | h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj); |
| 58297 | n = DUK_HOBJECT_GET_ENEXT(obj); |
| 58298 | for (i = 0; i < n; i++) { |
| 58299 | if (h_keys_base[i] == key) { |
| 58300 | *e_idx = (duk_int_t) i; |
| 58301 | *h_idx = -1; |
| 58302 | return 1; |
| 58303 | } |
| 58304 | } |
| 58305 | } |
| 58306 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 58307 | else |
| 58308 | { |
| 58309 | /* hash lookup */ |
| 58310 | duk_uint32_t n; |
| 58311 | duk_uint32_t i, step; |
| 58312 | duk_uint32_t *h_base; |
| 58313 | duk_uint32_t mask; |
| 58314 | |
| 58315 | DUK_DDD(DUK_DDDPRINT("duk_hobject_find_entry() using hash part for lookup" )); |
| 58316 | |
| 58317 | h_base = DUK_HOBJECT_H_GET_BASE(heap, obj); |
| 58318 | n = DUK_HOBJECT_GET_HSIZE(obj); |
| 58319 | mask = n - 1; |
| 58320 | i = DUK_HSTRING_GET_HASH(key) & mask; |
| 58321 | step = 1; /* Cache friendly but clustering prone. */ |
| 58322 | |
| 58323 | for (;;) { |
| 58324 | duk_uint32_t t; |
| 58325 | |
| 58326 | DUK_ASSERT_DISABLE(i >= 0); /* unsigned */ |
| 58327 | DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj)); |
| 58328 | t = h_base[i]; |
| 58329 | DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED || |
| 58330 | (t < DUK_HOBJECT_GET_ESIZE(obj))); /* t >= 0 always true, unsigned */ |
| 58331 | |
| 58332 | if (t == DUK__HASH_UNUSED) { |
| 58333 | break; |
| 58334 | } else if (t == DUK__HASH_DELETED) { |
| 58335 | DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld" , |
| 58336 | (long) i, (long) t)); |
| 58337 | } else { |
| 58338 | DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj)); |
| 58339 | if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) { |
| 58340 | DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p" , |
| 58341 | (long) i, (long) t, (void *) key)); |
| 58342 | *e_idx = (duk_int_t) t; |
| 58343 | *h_idx = (duk_int_t) i; |
| 58344 | return 1; |
| 58345 | } |
| 58346 | DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld" , |
| 58347 | (long) i, (long) t)); |
| 58348 | } |
| 58349 | i = (i + step) & mask; |
| 58350 | |
| 58351 | /* Guaranteed to finish (hash is larger than #props). */ |
| 58352 | } |
| 58353 | } |
| 58354 | #endif /* DUK_USE_HOBJECT_HASH_PART */ |
| 58355 | |
| 58356 | /* Not found, leave e_idx and h_idx unset. */ |
| 58357 | return 0; |
| 58358 | } |
| 58359 | |
| 58360 | /* For internal use: get non-accessor entry value */ |
| 58361 | DUK_INTERNAL duk_tval *duk_hobject_find_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) { |
| 58362 | duk_int_t e_idx; |
| 58363 | duk_int_t h_idx; |
| 58364 | |
| 58365 | DUK_ASSERT(obj != NULL); |
| 58366 | DUK_ASSERT(key != NULL); |
| 58367 | DUK_UNREF(heap); |
| 58368 | |
| 58369 | if (duk_hobject_find_entry(heap, obj, key, &e_idx, &h_idx)) { |
| 58370 | DUK_ASSERT(e_idx >= 0); |
| 58371 | if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) { |
| 58372 | return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx); |
| 58373 | } |
| 58374 | } |
| 58375 | return NULL; |
| 58376 | } |
| 58377 | |
| 58378 | DUK_INTERNAL duk_tval *duk_hobject_find_entry_tval_ptr_stridx(duk_heap *heap, duk_hobject *obj, duk_small_uint_t stridx) { |
| 58379 | return duk_hobject_find_entry_tval_ptr(heap, obj, DUK_HEAP_GET_STRING(heap, stridx)); |
| 58380 | } |
| 58381 | |
| 58382 | /* For internal use: get non-accessor entry value and attributes */ |
| 58383 | DUK_INTERNAL duk_tval *duk_hobject_find_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs) { |
| 58384 | duk_int_t e_idx; |
| 58385 | duk_int_t h_idx; |
| 58386 | |
| 58387 | DUK_ASSERT(obj != NULL); |
| 58388 | DUK_ASSERT(key != NULL); |
| 58389 | DUK_ASSERT(out_attrs != NULL); |
| 58390 | DUK_UNREF(heap); |
| 58391 | |
| 58392 | if (duk_hobject_find_entry(heap, obj, key, &e_idx, &h_idx)) { |
| 58393 | DUK_ASSERT(e_idx >= 0); |
| 58394 | if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) { |
| 58395 | *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx); |
| 58396 | return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx); |
| 58397 | } |
| 58398 | } |
| 58399 | /* If not found, out_attrs is left unset. */ |
| 58400 | return NULL; |
| 58401 | } |
| 58402 | |
| 58403 | /* For internal use: get array part value */ |
| 58404 | DUK_INTERNAL duk_tval *duk_hobject_find_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) { |
| 58405 | duk_tval *tv; |
| 58406 | |
| 58407 | DUK_ASSERT(obj != NULL); |
| 58408 | DUK_UNREF(heap); |
| 58409 | |
| 58410 | if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) { |
| 58411 | return NULL; |
| 58412 | } |
| 58413 | if (i >= DUK_HOBJECT_GET_ASIZE(obj)) { |
| 58414 | return NULL; |
| 58415 | } |
| 58416 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i); |
| 58417 | return tv; |
| 58418 | } |
| 58419 | |
| 58420 | /* |
| 58421 | * Allocate and initialize a new entry, resizing the properties allocation |
| 58422 | * if necessary. Returns entry index (e_idx) or throws an error if alloc fails. |
| 58423 | * |
| 58424 | * Sets the key of the entry (increasing the key's refcount), and updates |
| 58425 | * the hash part if it exists. Caller must set value and flags, and update |
| 58426 | * the entry value refcount. A decref for the previous value is not necessary. |
| 58427 | */ |
| 58428 | |
| 58429 | DUK_LOCAL duk_int_t duk__hobject_alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) { |
| 58430 | duk_uint32_t idx; |
| 58431 | |
| 58432 | DUK_ASSERT(thr != NULL); |
| 58433 | DUK_ASSERT(obj != NULL); |
| 58434 | DUK_ASSERT(key != NULL); |
| 58435 | DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj)); |
| 58436 | |
| 58437 | #if defined(DUK_USE_ASSERTIONS) |
| 58438 | /* key must not already exist in entry part */ |
| 58439 | { |
| 58440 | duk_uint_fast32_t i; |
| 58441 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 58442 | DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key); |
| 58443 | } |
| 58444 | } |
| 58445 | #endif |
| 58446 | |
| 58447 | if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) { |
| 58448 | /* only need to guarantee 1 more slot, but allocation growth is in chunks */ |
| 58449 | DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry" )); |
| 58450 | duk__grow_props_for_new_entry_item(thr, obj); |
| 58451 | } |
| 58452 | DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj)); |
| 58453 | idx = DUK_HOBJECT_POSTINC_ENEXT(obj); |
| 58454 | |
| 58455 | /* previous value is assumed to be garbage, so don't touch it */ |
| 58456 | DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key); |
| 58457 | DUK_HSTRING_INCREF(thr, key); |
| 58458 | |
| 58459 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 58460 | if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) { |
| 58461 | duk_uint32_t n, mask; |
| 58462 | duk_uint32_t i, step; |
| 58463 | duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); |
| 58464 | |
| 58465 | n = DUK_HOBJECT_GET_HSIZE(obj); |
| 58466 | mask = n - 1; |
| 58467 | i = DUK_HSTRING_GET_HASH(key) & mask; |
| 58468 | step = 1; /* Cache friendly but clustering prone. */ |
| 58469 | |
| 58470 | for (;;) { |
| 58471 | duk_uint32_t t = h_base[i]; |
| 58472 | if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) { |
| 58473 | DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() inserted key into hash part, %ld -> %ld" , |
| 58474 | (long) i, (long) idx)); |
| 58475 | DUK_ASSERT_DISABLE(i >= 0); /* unsigned */ |
| 58476 | DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj)); |
| 58477 | DUK_ASSERT_DISABLE(idx >= 0); |
| 58478 | DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj)); |
| 58479 | h_base[i] = idx; |
| 58480 | break; |
| 58481 | } |
| 58482 | DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() miss %ld" , (long) i)); |
| 58483 | i = (i + step) & mask; |
| 58484 | |
| 58485 | /* Guaranteed to finish (hash is larger than #props). */ |
| 58486 | } |
| 58487 | } |
| 58488 | #endif /* DUK_USE_HOBJECT_HASH_PART */ |
| 58489 | |
| 58490 | /* Note: we could return the hash index here too, but it's not |
| 58491 | * needed right now. |
| 58492 | */ |
| 58493 | |
| 58494 | DUK_ASSERT_DISABLE(idx >= 0); |
| 58495 | DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj)); |
| 58496 | DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj)); |
| 58497 | return (duk_int_t) idx; |
| 58498 | } |
| 58499 | |
| 58500 | /* |
| 58501 | * Object internal value |
| 58502 | * |
| 58503 | * Returned value is guaranteed to be reachable / incref'd, caller does not need |
| 58504 | * to incref OR decref. No proxies or accessors are invoked, no prototype walk. |
| 58505 | */ |
| 58506 | |
| 58507 | DUK_INTERNAL duk_tval *duk_hobject_get_internal_value_tval_ptr(duk_heap *heap, duk_hobject *obj) { |
| 58508 | return duk_hobject_find_entry_tval_ptr_stridx(heap, obj, DUK_STRIDX_INT_VALUE); |
| 58509 | } |
| 58510 | |
| 58511 | DUK_LOCAL duk_heaphdr *duk_hobject_get_internal_value_heaphdr(duk_heap *heap, duk_hobject *obj) { |
| 58512 | duk_tval *tv; |
| 58513 | |
| 58514 | DUK_ASSERT(heap != NULL); |
| 58515 | DUK_ASSERT(obj != NULL); |
| 58516 | |
| 58517 | tv = duk_hobject_get_internal_value_tval_ptr(heap, obj); |
| 58518 | if (tv != NULL) { |
| 58519 | duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv); |
| 58520 | DUK_ASSERT(h != NULL); |
| 58521 | return h; |
| 58522 | } |
| 58523 | |
| 58524 | return NULL; |
| 58525 | } |
| 58526 | |
| 58527 | DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) { |
| 58528 | duk_hstring *h; |
| 58529 | |
| 58530 | h = (duk_hstring *) duk_hobject_get_internal_value_heaphdr(heap, obj); |
| 58531 | if (h != NULL) { |
| 58532 | DUK_ASSERT(DUK_HEAPHDR_IS_STRING((duk_heaphdr *) h)); |
| 58533 | } |
| 58534 | return h; |
| 58535 | } |
| 58536 | |
| 58537 | DUK_LOCAL duk_hobject *duk__hobject_get_entry_object_stridx(duk_heap *heap, duk_hobject *obj, duk_small_uint_t stridx) { |
| 58538 | duk_tval *tv; |
| 58539 | duk_hobject *h; |
| 58540 | |
| 58541 | tv = duk_hobject_find_entry_tval_ptr_stridx(heap, obj, stridx); |
| 58542 | if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { |
| 58543 | h = DUK_TVAL_GET_OBJECT(tv); |
| 58544 | DUK_ASSERT(h != NULL); |
| 58545 | return h; |
| 58546 | } |
| 58547 | return NULL; |
| 58548 | } |
| 58549 | |
| 58550 | DUK_INTERNAL duk_harray *duk_hobject_get_formals(duk_hthread *thr, duk_hobject *obj) { |
| 58551 | duk_harray *h; |
| 58552 | |
| 58553 | h = (duk_harray *) duk__hobject_get_entry_object_stridx(thr->heap, obj, DUK_STRIDX_INT_FORMALS); |
| 58554 | if (h != NULL) { |
| 58555 | DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h)); |
| 58556 | DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h)); |
| 58557 | } |
| 58558 | return h; |
| 58559 | } |
| 58560 | |
| 58561 | DUK_INTERNAL duk_hobject *duk_hobject_get_varmap(duk_hthread *thr, duk_hobject *obj) { |
| 58562 | duk_hobject *h; |
| 58563 | |
| 58564 | h = duk__hobject_get_entry_object_stridx(thr->heap, obj, DUK_STRIDX_INT_VARMAP); |
| 58565 | return h; |
| 58566 | } |
| 58567 | |
| 58568 | /* |
| 58569 | * Arguments handling helpers (argument map mainly). |
| 58570 | * |
| 58571 | * An arguments object has exotic behavior for some numeric indices. |
| 58572 | * Accesses may translate to identifier operations which may have |
| 58573 | * arbitrary side effects (potentially invalidating any duk_tval |
| 58574 | * pointers). |
| 58575 | */ |
| 58576 | |
| 58577 | /* Lookup 'key' from arguments internal 'map', perform a variable lookup |
| 58578 | * if mapped, and leave the result on top of stack (and return non-zero). |
| 58579 | * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]]. |
| 58580 | */ |
| 58581 | DUK_LOCAL |
| 58582 | duk_bool_t duk__lookup_arguments_map(duk_hthread *thr, |
| 58583 | duk_hobject *obj, |
| 58584 | duk_hstring *key, |
| 58585 | duk_propdesc *temp_desc, |
| 58586 | duk_hobject **out_map, |
| 58587 | duk_hobject **out_varenv) { |
| 58588 | duk_hobject *map; |
| 58589 | duk_hobject *varenv; |
| 58590 | duk_bool_t rc; |
| 58591 | |
| 58592 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 58593 | |
| 58594 | DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p " |
| 58595 | "(obj -> %!O, key -> %!O)" , |
| 58596 | (void *) thr, (void *) obj, (void *) key, (void *) temp_desc, |
| 58597 | (duk_heaphdr *) obj, (duk_heaphdr *) key)); |
| 58598 | |
| 58599 | if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 58600 | DUK_DDD(DUK_DDDPRINT("-> no 'map'" )); |
| 58601 | return 0; |
| 58602 | } |
| 58603 | |
| 58604 | map = duk_require_hobject(thr, -1); |
| 58605 | DUK_ASSERT(map != NULL); |
| 58606 | duk_pop_unsafe(thr); /* map is reachable through obj */ |
| 58607 | |
| 58608 | if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 58609 | DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map" )); |
| 58610 | return 0; |
| 58611 | } |
| 58612 | |
| 58613 | /* [... varname] */ |
| 58614 | DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T" , |
| 58615 | (duk_tval *) duk_get_tval(thr, -1))); |
| 58616 | DUK_ASSERT(duk_is_string(thr, -1)); /* guaranteed when building arguments */ |
| 58617 | |
| 58618 | /* get varenv for varname (callee's declarative lexical environment) */ |
| 58619 | rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE); |
| 58620 | DUK_UNREF(rc); |
| 58621 | DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */ |
| 58622 | varenv = duk_require_hobject(thr, -1); |
| 58623 | DUK_ASSERT(varenv != NULL); |
| 58624 | duk_pop_unsafe(thr); /* varenv remains reachable through 'obj' */ |
| 58625 | |
| 58626 | DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO" , (duk_heaphdr *) varenv)); |
| 58627 | |
| 58628 | /* success: leave varname in stack */ |
| 58629 | *out_map = map; |
| 58630 | *out_varenv = varenv; |
| 58631 | return 1; /* [... varname] */ |
| 58632 | } |
| 58633 | |
| 58634 | /* Lookup 'key' from arguments internal 'map', and leave replacement value |
| 58635 | * on stack top if mapped (and return non-zero). |
| 58636 | * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]). |
| 58637 | */ |
| 58638 | DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) { |
| 58639 | duk_hobject *map; |
| 58640 | duk_hobject *varenv; |
| 58641 | duk_hstring *varname; |
| 58642 | |
| 58643 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 58644 | |
| 58645 | if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) { |
| 58646 | DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior" )); |
| 58647 | return 0; |
| 58648 | } |
| 58649 | |
| 58650 | /* [... varname] */ |
| 58651 | |
| 58652 | varname = duk_require_hstring(thr, -1); |
| 58653 | DUK_ASSERT(varname != NULL); |
| 58654 | duk_pop_unsafe(thr); /* varname is still reachable */ |
| 58655 | |
| 58656 | DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; " |
| 58657 | "key=%!O, varname=%!O" , |
| 58658 | (duk_heaphdr *) key, |
| 58659 | (duk_heaphdr *) varname)); |
| 58660 | |
| 58661 | (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/); |
| 58662 | |
| 58663 | /* [... value this_binding] */ |
| 58664 | |
| 58665 | duk_pop_unsafe(thr); |
| 58666 | |
| 58667 | /* leave result on stack top */ |
| 58668 | return 1; |
| 58669 | } |
| 58670 | |
| 58671 | /* Lookup 'key' from arguments internal 'map', perform a variable write if mapped. |
| 58672 | * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]). |
| 58673 | * Assumes stack top contains 'put' value (which is NOT popped). |
| 58674 | */ |
| 58675 | DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag) { |
| 58676 | duk_hobject *map; |
| 58677 | duk_hobject *varenv; |
| 58678 | duk_hstring *varname; |
| 58679 | |
| 58680 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 58681 | |
| 58682 | if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) { |
| 58683 | DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior" )); |
| 58684 | return; |
| 58685 | } |
| 58686 | |
| 58687 | /* [... put_value varname] */ |
| 58688 | |
| 58689 | varname = duk_require_hstring(thr, -1); |
| 58690 | DUK_ASSERT(varname != NULL); |
| 58691 | duk_pop_unsafe(thr); /* varname is still reachable */ |
| 58692 | |
| 58693 | DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; " |
| 58694 | "key=%!O, varname=%!O, value=%!T" , |
| 58695 | (duk_heaphdr *) key, |
| 58696 | (duk_heaphdr *) varname, |
| 58697 | (duk_tval *) duk_require_tval(thr, -1))); |
| 58698 | |
| 58699 | /* [... put_value] */ |
| 58700 | |
| 58701 | /* |
| 58702 | * Note: although arguments object variable mappings are only established |
| 58703 | * for non-strict functions (and a call to a non-strict function created |
| 58704 | * the arguments object in question), an inner strict function may be doing |
| 58705 | * the actual property write. Hence the throw_flag applied here comes from |
| 58706 | * the property write call. |
| 58707 | */ |
| 58708 | |
| 58709 | duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, -1), throw_flag); |
| 58710 | |
| 58711 | /* [... put_value] */ |
| 58712 | } |
| 58713 | |
| 58714 | /* Lookup 'key' from arguments internal 'map', delete mapping if found. |
| 58715 | * Used in E5 Section 10.6 algorithm for [[Delete]]. Note that the |
| 58716 | * variable/argument itself (where the map points) is not deleted. |
| 58717 | */ |
| 58718 | DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) { |
| 58719 | duk_hobject *map; |
| 58720 | |
| 58721 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 58722 | |
| 58723 | if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 58724 | DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior" )); |
| 58725 | return; |
| 58726 | } |
| 58727 | |
| 58728 | map = duk_require_hobject(thr, -1); |
| 58729 | DUK_ASSERT(map != NULL); |
| 58730 | duk_pop_unsafe(thr); /* map is reachable through obj */ |
| 58731 | |
| 58732 | DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result" , |
| 58733 | (duk_heaphdr *) key)); |
| 58734 | |
| 58735 | /* Note: no recursion issue, we can trust 'map' to behave */ |
| 58736 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map)); |
| 58737 | DUK_DDD(DUK_DDDPRINT("map before deletion: %!O" , (duk_heaphdr *) map)); |
| 58738 | (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */ |
| 58739 | DUK_DDD(DUK_DDDPRINT("map after deletion: %!O" , (duk_heaphdr *) map)); |
| 58740 | } |
| 58741 | |
| 58742 | /* |
| 58743 | * ECMAScript compliant [[GetOwnProperty]](P), for internal use only. |
| 58744 | * |
| 58745 | * If property is found: |
| 58746 | * - Fills descriptor fields to 'out_desc' |
| 58747 | * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the |
| 58748 | * property onto the stack ('undefined' for accessor properties). |
| 58749 | * - Returns non-zero |
| 58750 | * |
| 58751 | * If property is not found: |
| 58752 | * - 'out_desc' is left in untouched state (possibly garbage) |
| 58753 | * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE |
| 58754 | * set) |
| 58755 | * - Returns zero |
| 58756 | * |
| 58757 | * Notes: |
| 58758 | * |
| 58759 | * - Getting a property descriptor may cause an allocation (and hence |
| 58760 | * GC) to take place, hence reachability and refcount of all related |
| 58761 | * values matter. Reallocation of value stack, properties, etc may |
| 58762 | * invalidate many duk_tval pointers (concretely, those which reside |
| 58763 | * in memory areas subject to reallocation). However, heap object |
| 58764 | * pointers are never affected (heap objects have stable pointers). |
| 58765 | * |
| 58766 | * - The value of a plain property is always reachable and has a non-zero |
| 58767 | * reference count. |
| 58768 | * |
| 58769 | * - The value of a virtual property is not necessarily reachable from |
| 58770 | * elsewhere and may have a refcount of zero. Hence we push it onto |
| 58771 | * the valstack for the caller, which ensures it remains reachable |
| 58772 | * while it is needed. |
| 58773 | * |
| 58774 | * - There are no virtual accessor properties. Hence, all getters and |
| 58775 | * setters are always related to concretely stored properties, which |
| 58776 | * ensures that the get/set functions in the resulting descriptor are |
| 58777 | * reachable and have non-zero refcounts. Should there be virtual |
| 58778 | * accessor properties later, this would need to change. |
| 58779 | */ |
| 58780 | |
| 58781 | DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags) { |
| 58782 | duk_tval *tv; |
| 58783 | |
| 58784 | DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, " |
| 58785 | "arr_idx=%ld (obj -> %!O, key -> %!O)" , |
| 58786 | (void *) thr, (void *) obj, (void *) key, (void *) out_desc, |
| 58787 | (long) flags, (long) arr_idx, |
| 58788 | (duk_heaphdr *) obj, (duk_heaphdr *) key)); |
| 58789 | |
| 58790 | DUK_ASSERT(thr != NULL); |
| 58791 | DUK_ASSERT(thr->heap != NULL); |
| 58792 | DUK_ASSERT(obj != NULL); |
| 58793 | DUK_ASSERT(key != NULL); |
| 58794 | DUK_ASSERT(out_desc != NULL); |
| 58795 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 58796 | |
| 58797 | DUK_STATS_INC(thr->heap, stats_getownpropdesc_count); |
| 58798 | |
| 58799 | /* Each code path returning 1 (= found) must fill in all the output |
| 58800 | * descriptor fields. We don't do it beforehand because it'd be |
| 58801 | * unnecessary work if the property isn't found and would happen |
| 58802 | * multiple times for an inheritance chain. |
| 58803 | */ |
| 58804 | DUK_ASSERT_SET_GARBAGE(out_desc, sizeof(*out_desc)); |
| 58805 | #if 0 |
| 58806 | out_desc->flags = 0; |
| 58807 | out_desc->get = NULL; |
| 58808 | out_desc->set = NULL; |
| 58809 | out_desc->e_idx = -1; |
| 58810 | out_desc->h_idx = -1; |
| 58811 | out_desc->a_idx = -1; |
| 58812 | #endif |
| 58813 | |
| 58814 | /* |
| 58815 | * Try entries part first because it's the common case. |
| 58816 | * |
| 58817 | * Array part lookups are usually handled by the array fast path, and |
| 58818 | * are not usually inherited. Array and entry parts never contain the |
| 58819 | * same keys so the entry part vs. array part order doesn't matter. |
| 58820 | */ |
| 58821 | |
| 58822 | if (duk_hobject_find_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx)) { |
| 58823 | duk_int_t e_idx = out_desc->e_idx; |
| 58824 | DUK_ASSERT(out_desc->e_idx >= 0); |
| 58825 | out_desc->a_idx = -1; |
| 58826 | out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx); |
| 58827 | out_desc->get = NULL; |
| 58828 | out_desc->set = NULL; |
| 58829 | if (DUK_UNLIKELY(out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR)) { |
| 58830 | DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part" )); |
| 58831 | out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx); |
| 58832 | out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx); |
| 58833 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 58834 | /* a dummy undefined value is pushed to make valstack |
| 58835 | * behavior uniform for caller |
| 58836 | */ |
| 58837 | duk_push_undefined(thr); |
| 58838 | } |
| 58839 | } else { |
| 58840 | DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part" )); |
| 58841 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx); |
| 58842 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 58843 | duk_push_tval(thr, tv); |
| 58844 | } |
| 58845 | } |
| 58846 | goto prop_found; |
| 58847 | } |
| 58848 | |
| 58849 | /* |
| 58850 | * Try array part. |
| 58851 | */ |
| 58852 | |
| 58853 | if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) { |
| 58854 | if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) { |
| 58855 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx); |
| 58856 | if (!DUK_TVAL_IS_UNUSED(tv)) { |
| 58857 | DUK_DDD(DUK_DDDPRINT("-> found in array part" )); |
| 58858 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 58859 | duk_push_tval(thr, tv); |
| 58860 | } |
| 58861 | /* implicit attributes */ |
| 58862 | out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE | |
| 58863 | DUK_PROPDESC_FLAG_CONFIGURABLE | |
| 58864 | DUK_PROPDESC_FLAG_ENUMERABLE; |
| 58865 | out_desc->get = NULL; |
| 58866 | out_desc->set = NULL; |
| 58867 | out_desc->e_idx = -1; |
| 58868 | out_desc->h_idx = -1; |
| 58869 | out_desc->a_idx = (duk_int_t) arr_idx; /* XXX: limit 2G due to being signed */ |
| 58870 | goto prop_found; |
| 58871 | } |
| 58872 | } |
| 58873 | } |
| 58874 | |
| 58875 | DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property" )); |
| 58876 | |
| 58877 | /* |
| 58878 | * Not found as a concrete property, check for virtual properties. |
| 58879 | */ |
| 58880 | |
| 58881 | if (!DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(obj)) { |
| 58882 | /* Quick skip. */ |
| 58883 | goto prop_not_found; |
| 58884 | } |
| 58885 | |
| 58886 | if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { |
| 58887 | duk_harray *a; |
| 58888 | |
| 58889 | DUK_DDD(DUK_DDDPRINT("array object exotic property get for key: %!O, arr_idx: %ld" , |
| 58890 | (duk_heaphdr *) key, (long) arr_idx)); |
| 58891 | |
| 58892 | a = (duk_harray *) obj; |
| 58893 | DUK_HARRAY_ASSERT_VALID(a); |
| 58894 | |
| 58895 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 58896 | DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior" )); |
| 58897 | |
| 58898 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 58899 | duk_push_uint(thr, (duk_uint_t) a->length); |
| 58900 | } |
| 58901 | out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; |
| 58902 | if (DUK_HARRAY_LENGTH_WRITABLE(a)) { |
| 58903 | out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE; |
| 58904 | } |
| 58905 | out_desc->get = NULL; |
| 58906 | out_desc->set = NULL; |
| 58907 | out_desc->e_idx = -1; |
| 58908 | out_desc->h_idx = -1; |
| 58909 | out_desc->a_idx = -1; |
| 58910 | |
| 58911 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); |
| 58912 | goto prop_found_noexotic; /* cannot be arguments exotic */ |
| 58913 | } |
| 58914 | } else if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) { |
| 58915 | DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld" , |
| 58916 | (duk_heaphdr *) key, (long) arr_idx)); |
| 58917 | |
| 58918 | /* XXX: charlen; avoid multiple lookups? */ |
| 58919 | |
| 58920 | if (arr_idx != DUK__NO_ARRAY_INDEX) { |
| 58921 | duk_hstring *h_val; |
| 58922 | |
| 58923 | DUK_DDD(DUK_DDDPRINT("array index exists" )); |
| 58924 | |
| 58925 | h_val = duk_hobject_get_internal_value_string(thr->heap, obj); |
| 58926 | DUK_ASSERT(h_val); |
| 58927 | if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) { |
| 58928 | DUK_DDD(DUK_DDDPRINT("-> found, array index inside string" )); |
| 58929 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 58930 | duk_push_hstring(thr, h_val); |
| 58931 | duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */ |
| 58932 | } |
| 58933 | out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */ |
| 58934 | DUK_PROPDESC_FLAG_VIRTUAL; |
| 58935 | out_desc->get = NULL; |
| 58936 | out_desc->set = NULL; |
| 58937 | out_desc->e_idx = -1; |
| 58938 | out_desc->h_idx = -1; |
| 58939 | out_desc->a_idx = -1; |
| 58940 | |
| 58941 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); |
| 58942 | goto prop_found_noexotic; /* cannot be arguments exotic */ |
| 58943 | } else { |
| 58944 | /* index is above internal string length -> property is fully normal */ |
| 58945 | DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property" )); |
| 58946 | } |
| 58947 | } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 58948 | duk_hstring *h_val; |
| 58949 | |
| 58950 | DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior" )); |
| 58951 | |
| 58952 | h_val = duk_hobject_get_internal_value_string(thr->heap, obj); |
| 58953 | DUK_ASSERT(h_val != NULL); |
| 58954 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 58955 | duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val)); |
| 58956 | } |
| 58957 | out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */ |
| 58958 | out_desc->get = NULL; |
| 58959 | out_desc->set = NULL; |
| 58960 | out_desc->e_idx = -1; |
| 58961 | out_desc->h_idx = -1; |
| 58962 | out_desc->a_idx = -1; |
| 58963 | |
| 58964 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); |
| 58965 | goto prop_found_noexotic; /* cannot be arguments exotic */ |
| 58966 | } |
| 58967 | } |
| 58968 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 58969 | else if (DUK_HOBJECT_IS_BUFOBJ(obj)) { |
| 58970 | duk_hbufobj *h_bufobj; |
| 58971 | duk_uint_t byte_off; |
| 58972 | duk_small_uint_t elem_size; |
| 58973 | |
| 58974 | h_bufobj = (duk_hbufobj *) obj; |
| 58975 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 58976 | DUK_DDD(DUK_DDDPRINT("bufobj property get for key: %!O, arr_idx: %ld" , |
| 58977 | (duk_heaphdr *) key, (long) arr_idx)); |
| 58978 | |
| 58979 | if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { |
| 58980 | DUK_DDD(DUK_DDDPRINT("array index exists" )); |
| 58981 | |
| 58982 | /* Careful with wrapping: arr_idx upshift may easily wrap, whereas |
| 58983 | * length downshift won't. |
| 58984 | */ |
| 58985 | if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) { |
| 58986 | byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ |
| 58987 | elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); |
| 58988 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 58989 | duk_uint8_t *data; |
| 58990 | |
| 58991 | if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { |
| 58992 | data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; |
| 58993 | duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size); |
| 58994 | } else { |
| 58995 | DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)" )); |
| 58996 | duk_push_uint(thr, 0); |
| 58997 | } |
| 58998 | } |
| 58999 | out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE | |
| 59000 | DUK_PROPDESC_FLAG_VIRTUAL; |
| 59001 | if (DUK_HOBJECT_GET_CLASS_NUMBER(obj) != DUK_HOBJECT_CLASS_ARRAYBUFFER) { |
| 59002 | /* ArrayBuffer indices are non-standard and are |
| 59003 | * non-enumerable to avoid their serialization. |
| 59004 | */ |
| 59005 | out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE; |
| 59006 | } |
| 59007 | out_desc->get = NULL; |
| 59008 | out_desc->set = NULL; |
| 59009 | out_desc->e_idx = -1; |
| 59010 | out_desc->h_idx = -1; |
| 59011 | out_desc->a_idx = -1; |
| 59012 | |
| 59013 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); |
| 59014 | goto prop_found_noexotic; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */ |
| 59015 | } else { |
| 59016 | /* index is above internal buffer length -> property is fully normal */ |
| 59017 | DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property" )); |
| 59018 | } |
| 59019 | } else if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { |
| 59020 | DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior" )); |
| 59021 | |
| 59022 | if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) { |
| 59023 | /* Length in elements: take into account shift, but |
| 59024 | * intentionally don't check the underlying buffer here. |
| 59025 | */ |
| 59026 | duk_push_uint(thr, h_bufobj->length >> h_bufobj->shift); |
| 59027 | } |
| 59028 | out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; |
| 59029 | out_desc->get = NULL; |
| 59030 | out_desc->set = NULL; |
| 59031 | out_desc->e_idx = -1; |
| 59032 | out_desc->h_idx = -1; |
| 59033 | out_desc->a_idx = -1; |
| 59034 | |
| 59035 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)); |
| 59036 | goto prop_found_noexotic; /* cannot be arguments exotic */ |
| 59037 | } |
| 59038 | } |
| 59039 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 59040 | |
| 59041 | /* Array properties have exotic behavior but they are concrete, |
| 59042 | * so no special handling here. |
| 59043 | * |
| 59044 | * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]] |
| 59045 | * is only relevant as a post-check implemented below; hence no |
| 59046 | * check here. |
| 59047 | */ |
| 59048 | |
| 59049 | /* |
| 59050 | * Not found as concrete or virtual. |
| 59051 | */ |
| 59052 | |
| 59053 | prop_not_found: |
| 59054 | DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)" )); |
| 59055 | DUK_STATS_INC(thr->heap, stats_getownpropdesc_miss); |
| 59056 | return 0; |
| 59057 | |
| 59058 | /* |
| 59059 | * Found. |
| 59060 | * |
| 59061 | * Arguments object has exotic post-processing, see E5 Section 10.6, |
| 59062 | * description of [[GetOwnProperty]] variant for arguments. |
| 59063 | */ |
| 59064 | |
| 59065 | prop_found: |
| 59066 | DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior" )); |
| 59067 | |
| 59068 | /* Notes: |
| 59069 | * - Only numbered indices are relevant, so arr_idx fast reject is good |
| 59070 | * (this is valid unless there are more than 4**32-1 arguments). |
| 59071 | * - Since variable lookup has no side effects, this can be skipped if |
| 59072 | * DUK_GETDESC_FLAG_PUSH_VALUE is not set. |
| 59073 | */ |
| 59074 | |
| 59075 | if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) && |
| 59076 | arr_idx != DUK__NO_ARRAY_INDEX && |
| 59077 | (flags & DUK_GETDESC_FLAG_PUSH_VALUE))) { |
| 59078 | duk_propdesc temp_desc; |
| 59079 | |
| 59080 | /* Magically bound variable cannot be an accessor. However, |
| 59081 | * there may be an accessor property (or a plain property) in |
| 59082 | * place with magic behavior removed. This happens e.g. when |
| 59083 | * a magic property is redefined with defineProperty(). |
| 59084 | * Cannot assert for "not accessor" here. |
| 59085 | */ |
| 59086 | |
| 59087 | /* replaces top of stack with new value if necessary */ |
| 59088 | DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0); |
| 59089 | |
| 59090 | /* This can perform a variable lookup but only into a declarative |
| 59091 | * environment which has no side effects. |
| 59092 | */ |
| 59093 | if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) { |
| 59094 | DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T" , |
| 59095 | (duk_tval *) duk_get_tval(thr, -2), |
| 59096 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59097 | /* [... old_result result] -> [... result] */ |
| 59098 | duk_remove_m2(thr); |
| 59099 | } |
| 59100 | } |
| 59101 | |
| 59102 | prop_found_noexotic: |
| 59103 | DUK_STATS_INC(thr->heap, stats_getownpropdesc_hit); |
| 59104 | return 1; |
| 59105 | } |
| 59106 | |
| 59107 | DUK_INTERNAL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags) { |
| 59108 | DUK_ASSERT(thr != NULL); |
| 59109 | DUK_ASSERT(obj != NULL); |
| 59110 | DUK_ASSERT(key != NULL); |
| 59111 | DUK_ASSERT(out_desc != NULL); |
| 59112 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 59113 | |
| 59114 | return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags); |
| 59115 | } |
| 59116 | |
| 59117 | /* |
| 59118 | * ECMAScript compliant [[GetProperty]](P), for internal use only. |
| 59119 | * |
| 59120 | * If property is found: |
| 59121 | * - Fills descriptor fields to 'out_desc' |
| 59122 | * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the |
| 59123 | * property onto the stack ('undefined' for accessor properties). |
| 59124 | * - Returns non-zero |
| 59125 | * |
| 59126 | * If property is not found: |
| 59127 | * - 'out_desc' is left in untouched state (possibly garbage) |
| 59128 | * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE |
| 59129 | * set) |
| 59130 | * - Returns zero |
| 59131 | * |
| 59132 | * May cause arbitrary side effects and invalidate (most) duk_tval |
| 59133 | * pointers. |
| 59134 | */ |
| 59135 | |
| 59136 | DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags) { |
| 59137 | duk_hobject *curr; |
| 59138 | duk_uint32_t arr_idx; |
| 59139 | duk_uint_t sanity; |
| 59140 | |
| 59141 | DUK_ASSERT(thr != NULL); |
| 59142 | DUK_ASSERT(thr->heap != NULL); |
| 59143 | DUK_ASSERT(obj != NULL); |
| 59144 | DUK_ASSERT(key != NULL); |
| 59145 | DUK_ASSERT(out_desc != NULL); |
| 59146 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 59147 | |
| 59148 | DUK_STATS_INC(thr->heap, stats_getpropdesc_count); |
| 59149 | |
| 59150 | arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key); |
| 59151 | |
| 59152 | DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, " |
| 59153 | "arr_idx=%ld (obj -> %!O, key -> %!O)" , |
| 59154 | (void *) thr, (void *) obj, (void *) key, (void *) out_desc, |
| 59155 | (long) flags, (long) arr_idx, |
| 59156 | (duk_heaphdr *) obj, (duk_heaphdr *) key)); |
| 59157 | |
| 59158 | curr = obj; |
| 59159 | DUK_ASSERT(curr != NULL); |
| 59160 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 59161 | do { |
| 59162 | if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) { |
| 59163 | /* stack contains value (if requested), 'out_desc' is set */ |
| 59164 | DUK_STATS_INC(thr->heap, stats_getpropdesc_hit); |
| 59165 | return 1; |
| 59166 | } |
| 59167 | |
| 59168 | /* not found in 'curr', next in prototype chain; impose max depth */ |
| 59169 | if (DUK_UNLIKELY(sanity-- == 0)) { |
| 59170 | if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) { |
| 59171 | /* treat like property not found */ |
| 59172 | break; |
| 59173 | } else { |
| 59174 | DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); |
| 59175 | DUK_WO_NORETURN(return 0;); |
| 59176 | } |
| 59177 | } |
| 59178 | curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); |
| 59179 | } while (curr != NULL); |
| 59180 | |
| 59181 | /* out_desc is left untouched (possibly garbage), caller must use return |
| 59182 | * value to determine whether out_desc can be looked up |
| 59183 | */ |
| 59184 | |
| 59185 | DUK_STATS_INC(thr->heap, stats_getpropdesc_miss); |
| 59186 | return 0; |
| 59187 | } |
| 59188 | |
| 59189 | /* |
| 59190 | * Shallow fast path checks for accessing array elements with numeric |
| 59191 | * indices. The goal is to try to avoid coercing an array index to an |
| 59192 | * (interned) string for the most common lookups, in particular, for |
| 59193 | * standard Array objects. |
| 59194 | * |
| 59195 | * Interning is avoided but only for a very narrow set of cases: |
| 59196 | * - Object has array part, index is within array allocation, and |
| 59197 | * value is not unused (= key exists) |
| 59198 | * - Object has no interfering exotic behavior (e.g. arguments or |
| 59199 | * string object exotic behaviors interfere, array exotic |
| 59200 | * behavior does not). |
| 59201 | * |
| 59202 | * Current shortcoming: if key does not exist (even if it is within |
| 59203 | * the array allocation range) a slow path lookup with interning is |
| 59204 | * always required. This can probably be fixed so that there is a |
| 59205 | * quick fast path for non-existent elements as well, at least for |
| 59206 | * standard Array objects. |
| 59207 | */ |
| 59208 | |
| 59209 | #if defined(DUK_USE_ARRAY_PROP_FASTPATH) |
| 59210 | DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) { |
| 59211 | duk_tval *tv; |
| 59212 | duk_uint32_t idx; |
| 59213 | |
| 59214 | DUK_UNREF(thr); |
| 59215 | |
| 59216 | if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) && |
| 59217 | !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) && |
| 59218 | !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) && |
| 59219 | !DUK_HOBJECT_IS_BUFOBJ(obj) && |
| 59220 | !DUK_HOBJECT_IS_PROXY(obj))) { |
| 59221 | /* Must have array part and no conflicting exotic behaviors. |
| 59222 | * Doesn't need to have array special behavior, e.g. Arguments |
| 59223 | * object has array part. |
| 59224 | */ |
| 59225 | return NULL; |
| 59226 | } |
| 59227 | |
| 59228 | /* Arrays never have other exotic behaviors. */ |
| 59229 | |
| 59230 | DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer " |
| 59231 | "behavior, object has array part)" )); |
| 59232 | |
| 59233 | #if defined(DUK_USE_FASTINT) |
| 59234 | if (DUK_TVAL_IS_FASTINT(tv_key)) { |
| 59235 | idx = duk__tval_fastint_to_arr_idx(tv_key); |
| 59236 | } else |
| 59237 | #endif |
| 59238 | if (DUK_TVAL_IS_DOUBLE(tv_key)) { |
| 59239 | idx = duk__tval_number_to_arr_idx(tv_key); |
| 59240 | } else { |
| 59241 | DUK_DDD(DUK_DDDPRINT("key is not a number" )); |
| 59242 | return NULL; |
| 59243 | } |
| 59244 | |
| 59245 | /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which |
| 59246 | * is 0xffffffffUL. We don't need to check for that explicitly |
| 59247 | * because 0xffffffffUL will never be inside object 'a_size'. |
| 59248 | */ |
| 59249 | |
| 59250 | if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { |
| 59251 | DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part" )); |
| 59252 | return NULL; |
| 59253 | } |
| 59254 | DUK_ASSERT(idx != 0xffffffffUL); |
| 59255 | DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); |
| 59256 | |
| 59257 | /* XXX: for array instances we could take a shortcut here and assume |
| 59258 | * Array.prototype doesn't contain an array index property. |
| 59259 | */ |
| 59260 | |
| 59261 | DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part" )); |
| 59262 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx); |
| 59263 | if (!DUK_TVAL_IS_UNUSED(tv)) { |
| 59264 | DUK_DDD(DUK_DDDPRINT("-> fast path successful" )); |
| 59265 | return tv; |
| 59266 | } |
| 59267 | |
| 59268 | DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path" )); |
| 59269 | return NULL; |
| 59270 | } |
| 59271 | |
| 59272 | DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) { |
| 59273 | duk_tval *tv; |
| 59274 | duk_harray *a; |
| 59275 | duk_uint32_t idx; |
| 59276 | duk_uint32_t old_len, new_len; |
| 59277 | |
| 59278 | if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) && |
| 59279 | DUK_HOBJECT_HAS_ARRAY_PART(obj) && |
| 59280 | DUK_HOBJECT_HAS_EXTENSIBLE(obj))) { |
| 59281 | return 0; |
| 59282 | } |
| 59283 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */ |
| 59284 | |
| 59285 | a = (duk_harray *) obj; |
| 59286 | DUK_HARRAY_ASSERT_VALID(a); |
| 59287 | |
| 59288 | #if defined(DUK_USE_FASTINT) |
| 59289 | if (DUK_TVAL_IS_FASTINT(tv_key)) { |
| 59290 | idx = duk__tval_fastint_to_arr_idx(tv_key); |
| 59291 | } else |
| 59292 | #endif |
| 59293 | if (DUK_TVAL_IS_DOUBLE(tv_key)) { |
| 59294 | idx = duk__tval_number_to_arr_idx(tv_key); |
| 59295 | } else { |
| 59296 | DUK_DDD(DUK_DDDPRINT("key is not a number" )); |
| 59297 | return 0; |
| 59298 | } |
| 59299 | |
| 59300 | /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which |
| 59301 | * is 0xffffffffUL. We don't need to check for that explicitly |
| 59302 | * because 0xffffffffUL will never be inside object 'a_size'. |
| 59303 | */ |
| 59304 | |
| 59305 | if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { /* for resizing of array part, use slow path */ |
| 59306 | return 0; |
| 59307 | } |
| 59308 | DUK_ASSERT(idx != 0xffffffffUL); |
| 59309 | DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); |
| 59310 | |
| 59311 | old_len = a->length; |
| 59312 | |
| 59313 | if (idx >= old_len) { |
| 59314 | DUK_DDD(DUK_DDDPRINT("write new array entry requires length update " |
| 59315 | "(arr_idx=%ld, old_len=%ld)" , |
| 59316 | (long) idx, (long) old_len)); |
| 59317 | if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) { |
| 59318 | /* The correct behavior here is either a silent error |
| 59319 | * or a TypeError, depending on strictness. Fall back |
| 59320 | * to the slow path to handle the situation. |
| 59321 | */ |
| 59322 | return 0; |
| 59323 | } |
| 59324 | new_len = idx + 1; |
| 59325 | |
| 59326 | ((duk_harray *) obj)->length = new_len; |
| 59327 | } |
| 59328 | |
| 59329 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx); |
| 59330 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */ |
| 59331 | |
| 59332 | DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld" , (long) idx)); |
| 59333 | return 1; |
| 59334 | } |
| 59335 | #endif /* DUK_USE_ARRAY_PROP_FASTPATH */ |
| 59336 | |
| 59337 | /* |
| 59338 | * Fast path for bufobj getprop/putprop |
| 59339 | */ |
| 59340 | |
| 59341 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 59342 | DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) { |
| 59343 | duk_uint32_t idx; |
| 59344 | duk_hbufobj *h_bufobj; |
| 59345 | duk_uint_t byte_off; |
| 59346 | duk_small_uint_t elem_size; |
| 59347 | duk_uint8_t *data; |
| 59348 | |
| 59349 | if (!DUK_HOBJECT_IS_BUFOBJ(obj)) { |
| 59350 | return 0; |
| 59351 | } |
| 59352 | h_bufobj = (duk_hbufobj *) obj; |
| 59353 | if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { |
| 59354 | return 0; |
| 59355 | } |
| 59356 | |
| 59357 | #if defined(DUK_USE_FASTINT) |
| 59358 | if (DUK_TVAL_IS_FASTINT(tv_key)) { |
| 59359 | idx = duk__tval_fastint_to_arr_idx(tv_key); |
| 59360 | } else |
| 59361 | #endif |
| 59362 | if (DUK_TVAL_IS_DOUBLE(tv_key)) { |
| 59363 | idx = duk__tval_number_to_arr_idx(tv_key); |
| 59364 | } else { |
| 59365 | return 0; |
| 59366 | } |
| 59367 | |
| 59368 | /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which |
| 59369 | * is 0xffffffffUL. We don't need to check for that explicitly |
| 59370 | * because 0xffffffffUL will never be inside bufobj length. |
| 59371 | */ |
| 59372 | |
| 59373 | /* Careful with wrapping (left shifting idx would be unsafe). */ |
| 59374 | if (idx >= (h_bufobj->length >> h_bufobj->shift)) { |
| 59375 | return 0; |
| 59376 | } |
| 59377 | DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); |
| 59378 | |
| 59379 | byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ |
| 59380 | elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); |
| 59381 | |
| 59382 | if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { |
| 59383 | data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; |
| 59384 | duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size); |
| 59385 | } else { |
| 59386 | DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)" )); |
| 59387 | duk_push_uint(thr, 0); |
| 59388 | } |
| 59389 | |
| 59390 | return 1; |
| 59391 | } |
| 59392 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 59393 | |
| 59394 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 59395 | DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) { |
| 59396 | duk_uint32_t idx; |
| 59397 | duk_hbufobj *h_bufobj; |
| 59398 | duk_uint_t byte_off; |
| 59399 | duk_small_uint_t elem_size; |
| 59400 | duk_uint8_t *data; |
| 59401 | |
| 59402 | if (!(DUK_HOBJECT_IS_BUFOBJ(obj) && |
| 59403 | DUK_TVAL_IS_NUMBER(tv_val))) { |
| 59404 | return 0; |
| 59405 | } |
| 59406 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufobjs now */ |
| 59407 | |
| 59408 | h_bufobj = (duk_hbufobj *) obj; |
| 59409 | if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { |
| 59410 | return 0; |
| 59411 | } |
| 59412 | |
| 59413 | #if defined(DUK_USE_FASTINT) |
| 59414 | if (DUK_TVAL_IS_FASTINT(tv_key)) { |
| 59415 | idx = duk__tval_fastint_to_arr_idx(tv_key); |
| 59416 | } else |
| 59417 | #endif |
| 59418 | if (DUK_TVAL_IS_DOUBLE(tv_key)) { |
| 59419 | idx = duk__tval_number_to_arr_idx(tv_key); |
| 59420 | } else { |
| 59421 | return 0; |
| 59422 | } |
| 59423 | |
| 59424 | /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which |
| 59425 | * is 0xffffffffUL. We don't need to check for that explicitly |
| 59426 | * because 0xffffffffUL will never be inside bufobj length. |
| 59427 | */ |
| 59428 | |
| 59429 | /* Careful with wrapping (left shifting idx would be unsafe). */ |
| 59430 | if (idx >= (h_bufobj->length >> h_bufobj->shift)) { |
| 59431 | return 0; |
| 59432 | } |
| 59433 | DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX); |
| 59434 | |
| 59435 | byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ |
| 59436 | elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); |
| 59437 | |
| 59438 | /* Value is required to be a number in the fast path so there |
| 59439 | * are no side effects in write coercion. |
| 59440 | */ |
| 59441 | duk_push_tval(thr, tv_val); |
| 59442 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 59443 | |
| 59444 | if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { |
| 59445 | data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; |
| 59446 | duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size); |
| 59447 | } else { |
| 59448 | DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)" )); |
| 59449 | } |
| 59450 | |
| 59451 | duk_pop_unsafe(thr); |
| 59452 | return 1; |
| 59453 | } |
| 59454 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 59455 | |
| 59456 | /* |
| 59457 | * GETPROP: ECMAScript property read. |
| 59458 | */ |
| 59459 | |
| 59460 | DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) { |
| 59461 | duk_tval tv_obj_copy; |
| 59462 | duk_tval tv_key_copy; |
| 59463 | duk_hobject *curr = NULL; |
| 59464 | duk_hstring *key = NULL; |
| 59465 | duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX; |
| 59466 | duk_propdesc desc; |
| 59467 | duk_uint_t sanity; |
| 59468 | |
| 59469 | DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)" , |
| 59470 | (void *) thr, (void *) tv_obj, (void *) tv_key, |
| 59471 | (duk_tval *) tv_obj, (duk_tval *) tv_key)); |
| 59472 | |
| 59473 | DUK_ASSERT(thr != NULL); |
| 59474 | DUK_ASSERT(thr->heap != NULL); |
| 59475 | DUK_ASSERT(tv_obj != NULL); |
| 59476 | DUK_ASSERT(tv_key != NULL); |
| 59477 | |
| 59478 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 59479 | |
| 59480 | DUK_STATS_INC(thr->heap, stats_getprop_all); |
| 59481 | |
| 59482 | /* |
| 59483 | * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of |
| 59484 | * them being invalidated by a valstack resize. |
| 59485 | * |
| 59486 | * XXX: this is now an overkill for many fast paths. Rework this |
| 59487 | * to be faster (although switching to a valstack discipline might |
| 59488 | * be a better solution overall). |
| 59489 | */ |
| 59490 | |
| 59491 | DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj); |
| 59492 | DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key); |
| 59493 | tv_obj = &tv_obj_copy; |
| 59494 | tv_key = &tv_key_copy; |
| 59495 | |
| 59496 | /* |
| 59497 | * Coercion and fast path processing |
| 59498 | */ |
| 59499 | |
| 59500 | switch (DUK_TVAL_GET_TAG(tv_obj)) { |
| 59501 | case DUK_TAG_UNDEFINED: |
| 59502 | case DUK_TAG_NULL: { |
| 59503 | /* Note: unconditional throw */ |
| 59504 | DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject" )); |
| 59505 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 59506 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); |
| 59507 | #else |
| 59508 | DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s" , |
| 59509 | duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); |
| 59510 | #endif |
| 59511 | DUK_WO_NORETURN(return 0;); |
| 59512 | break; |
| 59513 | } |
| 59514 | |
| 59515 | case DUK_TAG_BOOLEAN: { |
| 59516 | DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype" )); |
| 59517 | curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]; |
| 59518 | break; |
| 59519 | } |
| 59520 | |
| 59521 | case DUK_TAG_STRING: { |
| 59522 | duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); |
| 59523 | duk_int_t pop_count; |
| 59524 | |
| 59525 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 59526 | /* Symbols (ES2015 or hidden) don't have virtual properties. */ |
| 59527 | DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype" )); |
| 59528 | curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; |
| 59529 | break; |
| 59530 | } |
| 59531 | |
| 59532 | #if defined(DUK_USE_FASTINT) |
| 59533 | if (DUK_TVAL_IS_FASTINT(tv_key)) { |
| 59534 | arr_idx = duk__tval_fastint_to_arr_idx(tv_key); |
| 59535 | DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld" , (long) arr_idx)); |
| 59536 | pop_count = 0; |
| 59537 | } else |
| 59538 | #endif |
| 59539 | if (DUK_TVAL_IS_NUMBER(tv_key)) { |
| 59540 | arr_idx = duk__tval_number_to_arr_idx(tv_key); |
| 59541 | DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld" , (long) arr_idx)); |
| 59542 | pop_count = 0; |
| 59543 | } else { |
| 59544 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59545 | DUK_ASSERT(key != NULL); |
| 59546 | DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after " |
| 59547 | "coercion key is %!T, arr_idx %ld" , |
| 59548 | (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); |
| 59549 | pop_count = 1; |
| 59550 | } |
| 59551 | |
| 59552 | if (arr_idx != DUK__NO_ARRAY_INDEX && |
| 59553 | arr_idx < DUK_HSTRING_GET_CHARLEN(h)) { |
| 59554 | duk_pop_n_unsafe(thr, pop_count); |
| 59555 | duk_push_hstring(thr, h); |
| 59556 | duk_substring(thr, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */ |
| 59557 | |
| 59558 | DUK_STATS_INC(thr->heap, stats_getprop_stringidx); |
| 59559 | DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length " |
| 59560 | "after coercion -> return char)" , |
| 59561 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59562 | return 1; |
| 59563 | } |
| 59564 | |
| 59565 | if (pop_count == 0) { |
| 59566 | /* This is a pretty awkward control flow, but we need to recheck the |
| 59567 | * key coercion here. |
| 59568 | */ |
| 59569 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59570 | DUK_ASSERT(key != NULL); |
| 59571 | DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after " |
| 59572 | "coercion key is %!T, arr_idx %ld" , |
| 59573 | (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); |
| 59574 | } |
| 59575 | |
| 59576 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 59577 | duk_pop_unsafe(thr); /* [key] -> [] */ |
| 59578 | duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */ |
| 59579 | |
| 59580 | DUK_STATS_INC(thr->heap, stats_getprop_stringlen); |
| 59581 | DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> " |
| 59582 | "return string length)" , |
| 59583 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59584 | return 1; |
| 59585 | } |
| 59586 | |
| 59587 | DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype" )); |
| 59588 | curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE]; |
| 59589 | goto lookup; /* avoid double coercion */ |
| 59590 | } |
| 59591 | |
| 59592 | case DUK_TAG_OBJECT: { |
| 59593 | #if defined(DUK_USE_ARRAY_PROP_FASTPATH) |
| 59594 | duk_tval *tmp; |
| 59595 | #endif |
| 59596 | |
| 59597 | curr = DUK_TVAL_GET_OBJECT(tv_obj); |
| 59598 | DUK_ASSERT(curr != NULL); |
| 59599 | |
| 59600 | /* XXX: array .length fast path (important in e.g. loops)? */ |
| 59601 | |
| 59602 | #if defined(DUK_USE_ARRAY_PROP_FASTPATH) |
| 59603 | tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key); |
| 59604 | if (tmp) { |
| 59605 | duk_push_tval(thr, tmp); |
| 59606 | |
| 59607 | DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part " |
| 59608 | "fast path)" , |
| 59609 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59610 | DUK_STATS_INC(thr->heap, stats_getprop_arrayidx); |
| 59611 | return 1; |
| 59612 | } |
| 59613 | #endif |
| 59614 | |
| 59615 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 59616 | if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) { |
| 59617 | /* Read value pushed on stack. */ |
| 59618 | DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufobj " |
| 59619 | "fast path)" , |
| 59620 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59621 | DUK_STATS_INC(thr->heap, stats_getprop_bufobjidx); |
| 59622 | return 1; |
| 59623 | } |
| 59624 | #endif |
| 59625 | |
| 59626 | #if defined(DUK_USE_ES6_PROXY) |
| 59627 | if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(curr))) { |
| 59628 | duk_hobject *h_target; |
| 59629 | |
| 59630 | if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) { |
| 59631 | /* -> [ ... trap handler ] */ |
| 59632 | DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T" , (duk_tval *) tv_key)); |
| 59633 | DUK_STATS_INC(thr->heap, stats_getprop_proxy); |
| 59634 | duk_push_hobject(thr, h_target); /* target */ |
| 59635 | duk_push_tval(thr, tv_key); /* P */ |
| 59636 | duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */ |
| 59637 | duk_call_method(thr, 3 /*nargs*/); |
| 59638 | |
| 59639 | /* Target object must be checked for a conflicting |
| 59640 | * non-configurable property. |
| 59641 | */ |
| 59642 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59643 | DUK_ASSERT(key != NULL); |
| 59644 | |
| 59645 | if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 59646 | duk_tval *tv_hook = duk_require_tval(thr, -3); /* value from hook */ |
| 59647 | duk_tval *tv_targ = duk_require_tval(thr, -1); /* value from target */ |
| 59648 | duk_bool_t datadesc_reject; |
| 59649 | duk_bool_t accdesc_reject; |
| 59650 | |
| 59651 | DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for " |
| 59652 | "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, " |
| 59653 | "desc.get=%p, desc.set=%p" , |
| 59654 | (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ, |
| 59655 | (unsigned long) desc.flags, |
| 59656 | (void *) desc.get, (void *) desc.set)); |
| 59657 | |
| 59658 | datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && |
| 59659 | !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && |
| 59660 | !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) && |
| 59661 | !duk_js_samevalue(tv_hook, tv_targ); |
| 59662 | accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && |
| 59663 | !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && |
| 59664 | (desc.get == NULL) && |
| 59665 | !DUK_TVAL_IS_UNDEFINED(tv_hook); |
| 59666 | if (datadesc_reject || accdesc_reject) { |
| 59667 | DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); |
| 59668 | DUK_WO_NORETURN(return 0;); |
| 59669 | } |
| 59670 | |
| 59671 | duk_pop_2_unsafe(thr); |
| 59672 | } else { |
| 59673 | duk_pop_unsafe(thr); |
| 59674 | } |
| 59675 | return 1; /* return value */ |
| 59676 | } |
| 59677 | |
| 59678 | curr = h_target; /* resume lookup from target */ |
| 59679 | DUK_TVAL_SET_OBJECT(tv_obj, curr); |
| 59680 | } |
| 59681 | #endif /* DUK_USE_ES6_PROXY */ |
| 59682 | |
| 59683 | if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) { |
| 59684 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59685 | DUK_ASSERT(key != NULL); |
| 59686 | |
| 59687 | DUK_STATS_INC(thr->heap, stats_getprop_arguments); |
| 59688 | if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) { |
| 59689 | DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, " |
| 59690 | "key matches magically bound property -> skip standard " |
| 59691 | "Get with replacement value)" , |
| 59692 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59693 | |
| 59694 | /* no need for 'caller' post-check, because 'key' must be an array index */ |
| 59695 | |
| 59696 | duk_remove_m2(thr); /* [key result] -> [result] */ |
| 59697 | return 1; |
| 59698 | } |
| 59699 | |
| 59700 | goto lookup; /* avoid double coercion */ |
| 59701 | } |
| 59702 | break; |
| 59703 | } |
| 59704 | |
| 59705 | /* Buffer has virtual properties similar to string, but indexed values |
| 59706 | * are numbers, not 1-byte buffers/strings which would perform badly. |
| 59707 | */ |
| 59708 | case DUK_TAG_BUFFER: { |
| 59709 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj); |
| 59710 | duk_int_t pop_count; |
| 59711 | |
| 59712 | /* |
| 59713 | * Because buffer values are often looped over, a number fast path |
| 59714 | * is important. |
| 59715 | */ |
| 59716 | |
| 59717 | #if defined(DUK_USE_FASTINT) |
| 59718 | if (DUK_TVAL_IS_FASTINT(tv_key)) { |
| 59719 | arr_idx = duk__tval_fastint_to_arr_idx(tv_key); |
| 59720 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld" , (long) arr_idx)); |
| 59721 | pop_count = 0; |
| 59722 | } |
| 59723 | else |
| 59724 | #endif |
| 59725 | if (DUK_TVAL_IS_NUMBER(tv_key)) { |
| 59726 | arr_idx = duk__tval_number_to_arr_idx(tv_key); |
| 59727 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld" , (long) arr_idx)); |
| 59728 | pop_count = 0; |
| 59729 | } else { |
| 59730 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59731 | DUK_ASSERT(key != NULL); |
| 59732 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " |
| 59733 | "coercion key is %!T, arr_idx %ld" , |
| 59734 | (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); |
| 59735 | pop_count = 1; |
| 59736 | } |
| 59737 | |
| 59738 | if (arr_idx != DUK__NO_ARRAY_INDEX && |
| 59739 | arr_idx < DUK_HBUFFER_GET_SIZE(h)) { |
| 59740 | duk_pop_n_unsafe(thr, pop_count); |
| 59741 | duk_push_uint(thr, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]); |
| 59742 | DUK_STATS_INC(thr->heap, stats_getprop_bufferidx); |
| 59743 | DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length " |
| 59744 | "after coercion -> return byte as number)" , |
| 59745 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59746 | return 1; |
| 59747 | } |
| 59748 | |
| 59749 | if (pop_count == 0) { |
| 59750 | /* This is a pretty awkward control flow, but we need to recheck the |
| 59751 | * key coercion here. |
| 59752 | */ |
| 59753 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59754 | DUK_ASSERT(key != NULL); |
| 59755 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " |
| 59756 | "coercion key is %!T, arr_idx %ld" , |
| 59757 | (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); |
| 59758 | } |
| 59759 | |
| 59760 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 59761 | duk_pop_unsafe(thr); /* [key] -> [] */ |
| 59762 | duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */ |
| 59763 | DUK_STATS_INC(thr->heap, stats_getprop_bufferlen); |
| 59764 | |
| 59765 | DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' " |
| 59766 | "after coercion -> return buffer length)" , |
| 59767 | (duk_tval *) duk_get_tval(thr, -1))); |
| 59768 | return 1; |
| 59769 | } |
| 59770 | |
| 59771 | DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype" )); |
| 59772 | curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; |
| 59773 | goto lookup; /* avoid double coercion */ |
| 59774 | } |
| 59775 | |
| 59776 | case DUK_TAG_POINTER: { |
| 59777 | DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype" )); |
| 59778 | curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE]; |
| 59779 | break; |
| 59780 | } |
| 59781 | |
| 59782 | case DUK_TAG_LIGHTFUNC: { |
| 59783 | /* Lightfuncs inherit getter .name and .length from %NativeFunctionPrototype%. */ |
| 59784 | DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype" )); |
| 59785 | curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE]; |
| 59786 | break; |
| 59787 | } |
| 59788 | |
| 59789 | #if defined(DUK_USE_FASTINT) |
| 59790 | case DUK_TAG_FASTINT: |
| 59791 | #endif |
| 59792 | default: { |
| 59793 | /* number */ |
| 59794 | DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype" )); |
| 59795 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj)); |
| 59796 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj)); |
| 59797 | curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]; |
| 59798 | break; |
| 59799 | } |
| 59800 | } |
| 59801 | |
| 59802 | /* key coercion (unless already coerced above) */ |
| 59803 | DUK_ASSERT(key == NULL); |
| 59804 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59805 | DUK_ASSERT(key != NULL); |
| 59806 | /* |
| 59807 | * Property lookup |
| 59808 | */ |
| 59809 | |
| 59810 | lookup: |
| 59811 | /* [key] (coerced) */ |
| 59812 | DUK_ASSERT(curr != NULL); |
| 59813 | DUK_ASSERT(key != NULL); |
| 59814 | |
| 59815 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 59816 | do { |
| 59817 | if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 59818 | goto next_in_chain; |
| 59819 | } |
| 59820 | |
| 59821 | if (desc.get != NULL) { |
| 59822 | /* accessor with defined getter */ |
| 59823 | DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0); |
| 59824 | |
| 59825 | duk_pop_unsafe(thr); /* [key undefined] -> [key] */ |
| 59826 | duk_push_hobject(thr, desc.get); |
| 59827 | duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */ |
| 59828 | #if defined(DUK_USE_NONSTD_GETTER_KEY_ARGUMENT) |
| 59829 | duk_dup_m3(thr); |
| 59830 | duk_call_method(thr, 1); /* [key getter this key] -> [key retval] */ |
| 59831 | #else |
| 59832 | duk_call_method(thr, 0); /* [key getter this] -> [key retval] */ |
| 59833 | #endif |
| 59834 | } else { |
| 59835 | /* [key value] or [key undefined] */ |
| 59836 | |
| 59837 | /* data property or accessor without getter */ |
| 59838 | DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) || |
| 59839 | (desc.get == NULL)); |
| 59840 | |
| 59841 | /* if accessor without getter, return value is undefined */ |
| 59842 | DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) || |
| 59843 | duk_is_undefined(thr, -1)); |
| 59844 | |
| 59845 | /* Note: for an accessor without getter, falling through to |
| 59846 | * check for "caller" exotic behavior is unnecessary as |
| 59847 | * "undefined" will never activate the behavior. But it does |
| 59848 | * no harm, so we'll do it anyway. |
| 59849 | */ |
| 59850 | } |
| 59851 | |
| 59852 | goto found; /* [key result] */ |
| 59853 | |
| 59854 | next_in_chain: |
| 59855 | /* XXX: option to pretend property doesn't exist if sanity limit is |
| 59856 | * hit might be useful. |
| 59857 | */ |
| 59858 | if (DUK_UNLIKELY(sanity-- == 0)) { |
| 59859 | DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); |
| 59860 | DUK_WO_NORETURN(return 0;); |
| 59861 | } |
| 59862 | curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); |
| 59863 | } while (curr != NULL); |
| 59864 | |
| 59865 | /* |
| 59866 | * Not found |
| 59867 | */ |
| 59868 | |
| 59869 | duk_to_undefined(thr, -1); /* [key] -> [undefined] (default value) */ |
| 59870 | |
| 59871 | DUK_DDD(DUK_DDDPRINT("-> %!T (not found)" , (duk_tval *) duk_get_tval(thr, -1))); |
| 59872 | return 0; |
| 59873 | |
| 59874 | /* |
| 59875 | * Found; post-processing (Function and arguments objects) |
| 59876 | */ |
| 59877 | |
| 59878 | found: |
| 59879 | /* [key result] */ |
| 59880 | |
| 59881 | #if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 59882 | /* Special behavior for 'caller' property of (non-bound) function objects |
| 59883 | * and non-strict Arguments objects: if 'caller' -value- (!) is a strict |
| 59884 | * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6). |
| 59885 | * Quite interestingly, a non-strict function with no formal arguments |
| 59886 | * will get an arguments object -without- special 'caller' behavior! |
| 59887 | * |
| 59888 | * The E5.1 spec is a bit ambiguous if this special behavior applies when |
| 59889 | * a bound function is the base value (not the 'caller' value): Section |
| 59890 | * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions |
| 59891 | * matches that of Section 15.3.5.4 ([[Get]] for Function instances). |
| 59892 | * However, Section 13.3.5.4 has "NOTE: Function objects created using |
| 59893 | * Function.prototype.bind use the default [[Get]] internal method." |
| 59894 | * The current implementation assumes this means that bound functions |
| 59895 | * should not have the special [[Get]] behavior. |
| 59896 | * |
| 59897 | * The E5.1 spec is also a bit unclear if the TypeError throwing is |
| 59898 | * applied if the 'caller' value is a strict bound function. The |
| 59899 | * current implementation will throw even for both strict non-bound |
| 59900 | * and strict bound functions. |
| 59901 | * |
| 59902 | * See test-dev-strict-func-as-caller-prop-value.js for quite extensive |
| 59903 | * tests. |
| 59904 | * |
| 59905 | * This exotic behavior is disabled when the non-standard 'caller' property |
| 59906 | * is enabled, as it conflicts with the free use of 'caller'. |
| 59907 | */ |
| 59908 | if (key == DUK_HTHREAD_STRING_CALLER(thr) && |
| 59909 | DUK_TVAL_IS_OBJECT(tv_obj)) { |
| 59910 | duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj); |
| 59911 | DUK_ASSERT(orig != NULL); |
| 59912 | |
| 59913 | if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) || |
| 59914 | DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) { |
| 59915 | duk_hobject *h; |
| 59916 | |
| 59917 | /* XXX: The TypeError is currently not applied to bound |
| 59918 | * functions because the 'strict' flag is not copied by |
| 59919 | * bind(). This may or may not be correct, the specification |
| 59920 | * only refers to the value being a "strict mode Function |
| 59921 | * object" which is ambiguous. |
| 59922 | */ |
| 59923 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(orig)); |
| 59924 | |
| 59925 | h = duk_get_hobject(thr, -1); /* NULL if not an object */ |
| 59926 | if (h && |
| 59927 | DUK_HOBJECT_IS_FUNCTION(h) && |
| 59928 | DUK_HOBJECT_HAS_STRICT(h)) { |
| 59929 | /* XXX: sufficient to check 'strict', assert for 'is function' */ |
| 59930 | DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ); |
| 59931 | DUK_WO_NORETURN(return 0;); |
| 59932 | } |
| 59933 | } |
| 59934 | } |
| 59935 | #endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */ |
| 59936 | |
| 59937 | duk_remove_m2(thr); /* [key result] -> [result] */ |
| 59938 | |
| 59939 | DUK_DDD(DUK_DDDPRINT("-> %!T (found)" , (duk_tval *) duk_get_tval(thr, -1))); |
| 59940 | return 1; |
| 59941 | } |
| 59942 | |
| 59943 | /* |
| 59944 | * HASPROP: ECMAScript property existence check ("in" operator). |
| 59945 | * |
| 59946 | * Interestingly, the 'in' operator does not do any coercion of |
| 59947 | * the target object. |
| 59948 | */ |
| 59949 | |
| 59950 | DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) { |
| 59951 | duk_tval tv_key_copy; |
| 59952 | duk_hobject *obj; |
| 59953 | duk_hstring *key; |
| 59954 | duk_uint32_t arr_idx; |
| 59955 | duk_bool_t rc; |
| 59956 | duk_propdesc desc; |
| 59957 | |
| 59958 | DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)" , |
| 59959 | (void *) thr, (void *) tv_obj, (void *) tv_key, |
| 59960 | (duk_tval *) tv_obj, (duk_tval *) tv_key)); |
| 59961 | |
| 59962 | DUK_ASSERT(thr != NULL); |
| 59963 | DUK_ASSERT(thr->heap != NULL); |
| 59964 | DUK_ASSERT(tv_obj != NULL); |
| 59965 | DUK_ASSERT(tv_key != NULL); |
| 59966 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 59967 | |
| 59968 | DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key); |
| 59969 | tv_key = &tv_key_copy; |
| 59970 | |
| 59971 | /* |
| 59972 | * The 'in' operator requires an object as its right hand side, |
| 59973 | * throwing a TypeError unconditionally if this is not the case. |
| 59974 | * |
| 59975 | * However, lightfuncs need to behave like fully fledged objects |
| 59976 | * here to be maximally transparent, so we need to handle them |
| 59977 | * here. Same goes for plain buffers which behave like ArrayBuffers. |
| 59978 | */ |
| 59979 | |
| 59980 | /* XXX: Refactor key coercion so that it's only called once. It can't |
| 59981 | * be trivially lifted here because the object must be type checked |
| 59982 | * first. |
| 59983 | */ |
| 59984 | |
| 59985 | if (DUK_TVAL_IS_OBJECT(tv_obj)) { |
| 59986 | obj = DUK_TVAL_GET_OBJECT(tv_obj); |
| 59987 | DUK_ASSERT(obj != NULL); |
| 59988 | |
| 59989 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59990 | } else if (DUK_TVAL_IS_BUFFER(tv_obj)) { |
| 59991 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59992 | if (duk__key_is_plain_buf_ownprop(thr, DUK_TVAL_GET_BUFFER(tv_obj), key, arr_idx)) { |
| 59993 | rc = 1; |
| 59994 | goto pop_and_return; |
| 59995 | } |
| 59996 | obj = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; |
| 59997 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) { |
| 59998 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 59999 | |
| 60000 | /* If not found, resume existence check from %NativeFunctionPrototype%. |
| 60001 | * We can just substitute the value in this case; nothing will |
| 60002 | * need the original base value (as would be the case with e.g. |
| 60003 | * setters/getters. |
| 60004 | */ |
| 60005 | obj = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE]; |
| 60006 | } else { |
| 60007 | /* Note: unconditional throw */ |
| 60008 | DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject" )); |
| 60009 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); |
| 60010 | DUK_WO_NORETURN(return 0;); |
| 60011 | } |
| 60012 | |
| 60013 | /* XXX: fast path for arrays? */ |
| 60014 | |
| 60015 | DUK_ASSERT(key != NULL); |
| 60016 | DUK_ASSERT(obj != NULL); |
| 60017 | DUK_UNREF(arr_idx); |
| 60018 | |
| 60019 | #if defined(DUK_USE_ES6_PROXY) |
| 60020 | if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) { |
| 60021 | duk_hobject *h_target; |
| 60022 | duk_bool_t tmp_bool; |
| 60023 | |
| 60024 | /* XXX: the key in 'key in obj' is string coerced before we're called |
| 60025 | * (which is the required behavior in E5/E5.1/E6) so the key is a string |
| 60026 | * here already. |
| 60027 | */ |
| 60028 | |
| 60029 | if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) { |
| 60030 | /* [ ... key trap handler ] */ |
| 60031 | DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T" , (duk_tval *) tv_key)); |
| 60032 | duk_push_hobject(thr, h_target); /* target */ |
| 60033 | duk_push_tval(thr, tv_key); /* P */ |
| 60034 | duk_call_method(thr, 2 /*nargs*/); |
| 60035 | tmp_bool = duk_to_boolean_top_pop(thr); |
| 60036 | if (!tmp_bool) { |
| 60037 | /* Target object must be checked for a conflicting |
| 60038 | * non-configurable property. |
| 60039 | */ |
| 60040 | |
| 60041 | if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ |
| 60042 | DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for " |
| 60043 | "conflicting property; desc.flags=0x%08lx, " |
| 60044 | "desc.get=%p, desc.set=%p" , |
| 60045 | (duk_heaphdr *) key, (unsigned long) desc.flags, |
| 60046 | (void *) desc.get, (void *) desc.set)); |
| 60047 | /* XXX: Extensibility check for target uses IsExtensible(). If we |
| 60048 | * implemented the isExtensible trap and didn't reject proxies as |
| 60049 | * proxy targets, it should be respected here. |
| 60050 | */ |
| 60051 | if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */ |
| 60052 | DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */ |
| 60053 | DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); |
| 60054 | DUK_WO_NORETURN(return 0;); |
| 60055 | } |
| 60056 | } |
| 60057 | } |
| 60058 | |
| 60059 | duk_pop_unsafe(thr); /* [ key ] -> [] */ |
| 60060 | return tmp_bool; |
| 60061 | } |
| 60062 | |
| 60063 | obj = h_target; /* resume check from proxy target */ |
| 60064 | } |
| 60065 | #endif /* DUK_USE_ES6_PROXY */ |
| 60066 | |
| 60067 | /* XXX: inline into a prototype walking loop? */ |
| 60068 | |
| 60069 | rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/); /* don't push value */ |
| 60070 | /* fall through */ |
| 60071 | |
| 60072 | pop_and_return: |
| 60073 | duk_pop_unsafe(thr); /* [ key ] -> [] */ |
| 60074 | return rc; |
| 60075 | } |
| 60076 | |
| 60077 | /* |
| 60078 | * HASPROP variant used internally. |
| 60079 | * |
| 60080 | * This primitive must never throw an error, callers rely on this. |
| 60081 | * In particular, don't throw an error for prototype loops; instead, |
| 60082 | * pretend like the property doesn't exist if a prototype sanity limit |
| 60083 | * is reached. |
| 60084 | * |
| 60085 | * Does not implement proxy behavior: if applied to a proxy object, |
| 60086 | * returns key existence on the proxy object itself. |
| 60087 | */ |
| 60088 | |
| 60089 | DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) { |
| 60090 | duk_propdesc dummy; |
| 60091 | |
| 60092 | DUK_ASSERT(thr != NULL); |
| 60093 | DUK_ASSERT(thr->heap != NULL); |
| 60094 | DUK_ASSERT(obj != NULL); |
| 60095 | DUK_ASSERT(key != NULL); |
| 60096 | |
| 60097 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 60098 | |
| 60099 | return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP); /* don't push value */ |
| 60100 | } |
| 60101 | |
| 60102 | /* |
| 60103 | * Helper: handle Array object 'length' write which automatically |
| 60104 | * deletes properties, see E5 Section 15.4.5.1, step 3. This is |
| 60105 | * quite tricky to get right. |
| 60106 | * |
| 60107 | * Used by duk_hobject_putprop(). |
| 60108 | */ |
| 60109 | |
| 60110 | /* Coerce a new .length candidate to a number and check that it's a valid |
| 60111 | * .length. |
| 60112 | */ |
| 60113 | DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tval *tv) { |
| 60114 | duk_uint32_t res; |
| 60115 | duk_double_t d; |
| 60116 | |
| 60117 | #if !defined(DUK_USE_PREFER_SIZE) |
| 60118 | #if defined(DUK_USE_FASTINT) |
| 60119 | /* When fastints are enabled, the most interesting case is assigning |
| 60120 | * a fastint to .length (e.g. arr.length = 0). |
| 60121 | */ |
| 60122 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 60123 | /* Very common case. */ |
| 60124 | duk_int64_t fi; |
| 60125 | fi = DUK_TVAL_GET_FASTINT(tv); |
| 60126 | if (fi < 0 || fi > DUK_I64_CONSTANT(0xffffffff)) { |
| 60127 | goto fail_range; |
| 60128 | } |
| 60129 | return (duk_uint32_t) fi; |
| 60130 | } |
| 60131 | #else /* DUK_USE_FASTINT */ |
| 60132 | /* When fastints are not enabled, the most interesting case is any |
| 60133 | * number. |
| 60134 | */ |
| 60135 | if (DUK_TVAL_IS_DOUBLE(tv)) { |
| 60136 | d = DUK_TVAL_GET_NUMBER(tv); |
| 60137 | } |
| 60138 | #endif /* DUK_USE_FASTINT */ |
| 60139 | else |
| 60140 | #endif /* !DUK_USE_PREFER_SIZE */ |
| 60141 | { |
| 60142 | /* In all other cases, and when doing a size optimized build, |
| 60143 | * fall back to the comprehensive handler. |
| 60144 | */ |
| 60145 | d = duk_js_tonumber(thr, tv); |
| 60146 | } |
| 60147 | |
| 60148 | /* Refuse to update an Array's 'length' to a value outside the |
| 60149 | * 32-bit range. Negative zero is accepted as zero. |
| 60150 | */ |
| 60151 | res = duk_double_to_uint32_t(d); |
| 60152 | if (!duk_double_equals((duk_double_t) res, d)) { |
| 60153 | goto fail_range; |
| 60154 | } |
| 60155 | |
| 60156 | return res; |
| 60157 | |
| 60158 | fail_range: |
| 60159 | DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH); |
| 60160 | DUK_WO_NORETURN(return 0;); |
| 60161 | } |
| 60162 | |
| 60163 | /* Delete elements required by a smaller length, taking into account |
| 60164 | * potentially non-configurable elements. Returns non-zero if all |
| 60165 | * elements could be deleted, and zero if all or some elements could |
| 60166 | * not be deleted. Also writes final "target length" to 'out_result_len'. |
| 60167 | * This is the length value that should go into the 'length' property |
| 60168 | * (must be set by the caller). Never throws an error. |
| 60169 | */ |
| 60170 | DUK_LOCAL |
| 60171 | duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr, |
| 60172 | duk_hobject *obj, |
| 60173 | duk_uint32_t old_len, |
| 60174 | duk_uint32_t new_len, |
| 60175 | duk_bool_t force_flag, |
| 60176 | duk_uint32_t *out_result_len) { |
| 60177 | duk_uint32_t target_len; |
| 60178 | duk_uint_fast32_t i; |
| 60179 | duk_uint32_t arr_idx; |
| 60180 | duk_hstring *key; |
| 60181 | duk_tval *tv; |
| 60182 | duk_bool_t rc; |
| 60183 | |
| 60184 | DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), " |
| 60185 | "probably need to remove elements" , |
| 60186 | (long) old_len, (long) new_len)); |
| 60187 | |
| 60188 | /* |
| 60189 | * New length is smaller than old length, need to delete properties above |
| 60190 | * the new length. |
| 60191 | * |
| 60192 | * If array part exists, this is straightforward: array entries cannot |
| 60193 | * be non-configurable so this is guaranteed to work. |
| 60194 | * |
| 60195 | * If array part does not exist, array-indexed values are scattered |
| 60196 | * in the entry part, and some may not be configurable (preventing length |
| 60197 | * from becoming lower than their index + 1). To handle the algorithm |
| 60198 | * in E5 Section 15.4.5.1, step l correctly, we scan the entire property |
| 60199 | * set twice. |
| 60200 | */ |
| 60201 | |
| 60202 | DUK_ASSERT(thr != NULL); |
| 60203 | DUK_ASSERT(obj != NULL); |
| 60204 | DUK_ASSERT(new_len < old_len); |
| 60205 | DUK_ASSERT(out_result_len != NULL); |
| 60206 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 60207 | |
| 60208 | DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); |
| 60209 | DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj)); |
| 60210 | |
| 60211 | if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) { |
| 60212 | /* |
| 60213 | * All defined array-indexed properties are in the array part |
| 60214 | * (we assume the array part is comprehensive), and all array |
| 60215 | * entries are writable, configurable, and enumerable. Thus, |
| 60216 | * nothing can prevent array entries from being deleted. |
| 60217 | */ |
| 60218 | |
| 60219 | DUK_DDD(DUK_DDDPRINT("have array part, easy case" )); |
| 60220 | |
| 60221 | if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) { |
| 60222 | /* XXX: assertion that entries >= old_len are already unused */ |
| 60223 | i = old_len; |
| 60224 | } else { |
| 60225 | i = DUK_HOBJECT_GET_ASIZE(obj); |
| 60226 | } |
| 60227 | DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj)); |
| 60228 | |
| 60229 | while (i > new_len) { |
| 60230 | i--; |
| 60231 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); |
| 60232 | DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */ |
| 60233 | } |
| 60234 | |
| 60235 | *out_result_len = new_len; |
| 60236 | return 1; |
| 60237 | } else { |
| 60238 | /* |
| 60239 | * Entries part is a bit more complex. |
| 60240 | */ |
| 60241 | |
| 60242 | /* Stage 1: find highest preventing non-configurable entry (if any). |
| 60243 | * When forcing, ignore non-configurability. |
| 60244 | */ |
| 60245 | |
| 60246 | DUK_DDD(DUK_DDDPRINT("no array part, slow case" )); |
| 60247 | |
| 60248 | DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len " |
| 60249 | "(highest preventing non-configurable entry (if any))" )); |
| 60250 | |
| 60251 | target_len = new_len; |
| 60252 | if (force_flag) { |
| 60253 | DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1" )); |
| 60254 | goto skip_stage1; |
| 60255 | } |
| 60256 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 60257 | key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); |
| 60258 | if (!key) { |
| 60259 | DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key" , (long) i)); |
| 60260 | continue; |
| 60261 | } |
| 60262 | if (!DUK_HSTRING_HAS_ARRIDX(key)) { |
| 60263 | DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index" , (long) i)); |
| 60264 | continue; |
| 60265 | } |
| 60266 | |
| 60267 | DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */ |
| 60268 | arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); |
| 60269 | DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); |
| 60270 | DUK_ASSERT(arr_idx < old_len); /* consistency requires this */ |
| 60271 | |
| 60272 | if (arr_idx < new_len) { |
| 60273 | DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len" , |
| 60274 | (long) i, (long) arr_idx)); |
| 60275 | continue; |
| 60276 | } |
| 60277 | if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) { |
| 60278 | DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable" , |
| 60279 | (long) i, (long) arr_idx)); |
| 60280 | continue; |
| 60281 | } |
| 60282 | |
| 60283 | /* relevant array index is non-configurable, blocks write */ |
| 60284 | if (arr_idx >= target_len) { |
| 60285 | DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, " |
| 60286 | "update target_len %ld -> %ld" , |
| 60287 | (long) i, (long) arr_idx, (long) target_len, |
| 60288 | (long) (arr_idx + 1))); |
| 60289 | target_len = arr_idx + 1; |
| 60290 | } |
| 60291 | } |
| 60292 | skip_stage1: |
| 60293 | |
| 60294 | /* stage 2: delete configurable entries above target length */ |
| 60295 | |
| 60296 | DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld" , |
| 60297 | (long) old_len, (long) new_len, (long) target_len)); |
| 60298 | |
| 60299 | DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove " |
| 60300 | "entries >= target_len" )); |
| 60301 | |
| 60302 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 60303 | key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i); |
| 60304 | if (!key) { |
| 60305 | DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key" , (long) i)); |
| 60306 | continue; |
| 60307 | } |
| 60308 | if (!DUK_HSTRING_HAS_ARRIDX(key)) { |
| 60309 | DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index" , (long) i)); |
| 60310 | continue; |
| 60311 | } |
| 60312 | |
| 60313 | DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */ |
| 60314 | arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); |
| 60315 | DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); |
| 60316 | DUK_ASSERT(arr_idx < old_len); /* consistency requires this */ |
| 60317 | |
| 60318 | if (arr_idx < target_len) { |
| 60319 | DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len" , |
| 60320 | (long) i, (long) arr_idx)); |
| 60321 | continue; |
| 60322 | } |
| 60323 | DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)); /* stage 1 guarantees */ |
| 60324 | |
| 60325 | DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld" , |
| 60326 | (long) i, (long) arr_idx)); |
| 60327 | |
| 60328 | /* |
| 60329 | * Slow delete, but we don't care as we're already in a very slow path. |
| 60330 | * The delete always succeeds: key has no exotic behavior, property |
| 60331 | * is configurable, and no resize occurs. |
| 60332 | */ |
| 60333 | rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0); |
| 60334 | DUK_UNREF(rc); |
| 60335 | DUK_ASSERT(rc != 0); |
| 60336 | } |
| 60337 | |
| 60338 | /* stage 3: update length (done by caller), decide return code */ |
| 60339 | |
| 60340 | DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)" )); |
| 60341 | |
| 60342 | *out_result_len = target_len; |
| 60343 | |
| 60344 | if (target_len == new_len) { |
| 60345 | DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success" )); |
| 60346 | return 1; |
| 60347 | } |
| 60348 | DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented " |
| 60349 | "full length adjustment), return error" )); |
| 60350 | return 0; |
| 60351 | } |
| 60352 | |
| 60353 | DUK_UNREACHABLE(); |
| 60354 | } |
| 60355 | |
| 60356 | /* XXX: is valstack top best place for argument? */ |
| 60357 | DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) { |
| 60358 | duk_harray *a; |
| 60359 | duk_uint32_t old_len; |
| 60360 | duk_uint32_t new_len; |
| 60361 | duk_uint32_t result_len; |
| 60362 | duk_bool_t rc; |
| 60363 | |
| 60364 | DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, " |
| 60365 | "new val: %!T" , |
| 60366 | (duk_tval *) duk_get_tval(thr, -1))); |
| 60367 | |
| 60368 | DUK_ASSERT(thr != NULL); |
| 60369 | DUK_ASSERT(obj != NULL); |
| 60370 | |
| 60371 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 60372 | |
| 60373 | DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); |
| 60374 | DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj)); |
| 60375 | a = (duk_harray *) obj; |
| 60376 | DUK_HARRAY_ASSERT_VALID(a); |
| 60377 | |
| 60378 | DUK_ASSERT(duk_is_valid_index(thr, -1)); |
| 60379 | |
| 60380 | /* |
| 60381 | * Get old and new length |
| 60382 | */ |
| 60383 | |
| 60384 | old_len = a->length; |
| 60385 | new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1)); |
| 60386 | DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld" , (long) old_len, (long) new_len)); |
| 60387 | |
| 60388 | /* |
| 60389 | * Writability check |
| 60390 | */ |
| 60391 | |
| 60392 | if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) { |
| 60393 | DUK_DDD(DUK_DDDPRINT("length is not writable, fail" )); |
| 60394 | return 0; |
| 60395 | } |
| 60396 | |
| 60397 | /* |
| 60398 | * New length not lower than old length => no changes needed |
| 60399 | * (not even array allocation). |
| 60400 | */ |
| 60401 | |
| 60402 | if (new_len >= old_len) { |
| 60403 | DUK_DDD(DUK_DDDPRINT("new length is same or higher than old length, just update length, no deletions" )); |
| 60404 | a->length = new_len; |
| 60405 | return 1; |
| 60406 | } |
| 60407 | |
| 60408 | DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries" )); |
| 60409 | |
| 60410 | /* |
| 60411 | * New length lower than old length => delete elements, then |
| 60412 | * update length. |
| 60413 | * |
| 60414 | * Note: even though a bunch of elements have been deleted, the 'desc' is |
| 60415 | * still valid as properties haven't been resized (and entries compacted). |
| 60416 | */ |
| 60417 | |
| 60418 | rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len); |
| 60419 | DUK_ASSERT(result_len >= new_len && result_len <= old_len); |
| 60420 | |
| 60421 | a->length = result_len; |
| 60422 | |
| 60423 | /* XXX: shrink array allocation or entries compaction here? */ |
| 60424 | |
| 60425 | return rc; |
| 60426 | } |
| 60427 | |
| 60428 | /* |
| 60429 | * PUTPROP: ECMAScript property write. |
| 60430 | * |
| 60431 | * Unlike ECMAScript primitive which returns nothing, returns 1 to indicate |
| 60432 | * success and 0 to indicate failure (assuming throw is not set). |
| 60433 | * |
| 60434 | * This is an extremely tricky function. Some examples: |
| 60435 | * |
| 60436 | * * Currently a decref may trigger a GC, which may compact an object's |
| 60437 | * property allocation. Consequently, any entry indices (e_idx) will |
| 60438 | * be potentially invalidated by a decref. |
| 60439 | * |
| 60440 | * * Exotic behaviors (strings, arrays, arguments object) require, |
| 60441 | * among other things: |
| 60442 | * |
| 60443 | * - Preprocessing before and postprocessing after an actual property |
| 60444 | * write. For example, array index write requires pre-checking the |
| 60445 | * array 'length' property for access control, and may require an |
| 60446 | * array 'length' update after the actual write has succeeded (but |
| 60447 | * not if it fails). |
| 60448 | * |
| 60449 | * - Deletion of multiple entries, as a result of array 'length' write. |
| 60450 | * |
| 60451 | * * Input values are taken as pointers which may point to the valstack. |
| 60452 | * If valstack is resized because of the put (this may happen at least |
| 60453 | * when the array part is abandoned), the pointers can be invalidated. |
| 60454 | * (We currently make a copy of all of the input values to avoid issues.) |
| 60455 | */ |
| 60456 | |
| 60457 | DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag) { |
| 60458 | duk_tval tv_obj_copy; |
| 60459 | duk_tval tv_key_copy; |
| 60460 | duk_tval tv_val_copy; |
| 60461 | duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */ |
| 60462 | duk_hobject *curr; |
| 60463 | duk_hstring *key = NULL; |
| 60464 | duk_propdesc desc; |
| 60465 | duk_tval *tv; |
| 60466 | duk_uint32_t arr_idx; |
| 60467 | duk_bool_t rc; |
| 60468 | duk_int_t e_idx; |
| 60469 | duk_uint_t sanity; |
| 60470 | duk_uint32_t new_array_length = 0; /* 0 = no update */ |
| 60471 | |
| 60472 | DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld " |
| 60473 | "(obj -> %!T, key -> %!T, val -> %!T)" , |
| 60474 | (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val, |
| 60475 | (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val)); |
| 60476 | |
| 60477 | DUK_ASSERT(thr != NULL); |
| 60478 | DUK_ASSERT(thr->heap != NULL); |
| 60479 | DUK_ASSERT(tv_obj != NULL); |
| 60480 | DUK_ASSERT(tv_key != NULL); |
| 60481 | DUK_ASSERT(tv_val != NULL); |
| 60482 | |
| 60483 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 60484 | |
| 60485 | DUK_STATS_INC(thr->heap, stats_putprop_all); |
| 60486 | |
| 60487 | /* |
| 60488 | * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of |
| 60489 | * them being invalidated by a valstack resize. |
| 60490 | * |
| 60491 | * XXX: this is an overkill for some paths, so optimize this later |
| 60492 | * (or maybe switch to a stack arguments model entirely). |
| 60493 | */ |
| 60494 | |
| 60495 | DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj); |
| 60496 | DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key); |
| 60497 | DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val); |
| 60498 | tv_obj = &tv_obj_copy; |
| 60499 | tv_key = &tv_key_copy; |
| 60500 | tv_val = &tv_val_copy; |
| 60501 | |
| 60502 | /* |
| 60503 | * Coercion and fast path processing. |
| 60504 | */ |
| 60505 | |
| 60506 | switch (DUK_TVAL_GET_TAG(tv_obj)) { |
| 60507 | case DUK_TAG_UNDEFINED: |
| 60508 | case DUK_TAG_NULL: { |
| 60509 | /* Note: unconditional throw */ |
| 60510 | DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)" , |
| 60511 | (duk_tval *) tv_obj)); |
| 60512 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 60513 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); |
| 60514 | #else |
| 60515 | DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s" , |
| 60516 | duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); |
| 60517 | #endif |
| 60518 | DUK_WO_NORETURN(return 0;); |
| 60519 | break; |
| 60520 | } |
| 60521 | |
| 60522 | case DUK_TAG_BOOLEAN: { |
| 60523 | DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype" )); |
| 60524 | curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]; |
| 60525 | break; |
| 60526 | } |
| 60527 | |
| 60528 | case DUK_TAG_STRING: { |
| 60529 | duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); |
| 60530 | |
| 60531 | /* |
| 60532 | * Note: currently no fast path for array index writes. |
| 60533 | * They won't be possible anyway as strings are immutable. |
| 60534 | */ |
| 60535 | |
| 60536 | DUK_ASSERT(key == NULL); |
| 60537 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 60538 | DUK_ASSERT(key != NULL); |
| 60539 | |
| 60540 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 60541 | /* Symbols (ES2015 or hidden) don't have virtual properties. */ |
| 60542 | curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE]; |
| 60543 | goto lookup; |
| 60544 | } |
| 60545 | |
| 60546 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 60547 | goto fail_not_writable; |
| 60548 | } |
| 60549 | |
| 60550 | if (arr_idx != DUK__NO_ARRAY_INDEX && |
| 60551 | arr_idx < DUK_HSTRING_GET_CHARLEN(h)) { |
| 60552 | goto fail_not_writable; |
| 60553 | } |
| 60554 | |
| 60555 | DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype" )); |
| 60556 | curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE]; |
| 60557 | goto lookup; /* avoid double coercion */ |
| 60558 | } |
| 60559 | |
| 60560 | case DUK_TAG_OBJECT: { |
| 60561 | orig = DUK_TVAL_GET_OBJECT(tv_obj); |
| 60562 | DUK_ASSERT(orig != NULL); |
| 60563 | |
| 60564 | #if defined(DUK_USE_ROM_OBJECTS) |
| 60565 | /* With this check in place fast paths won't need read-only |
| 60566 | * object checks. This is technically incorrect if there are |
| 60567 | * setters that cause no writes to ROM objects, but current |
| 60568 | * built-ins don't have such setters. |
| 60569 | */ |
| 60570 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) { |
| 60571 | DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object" )); |
| 60572 | goto fail_not_writable_no_pop; /* Must avoid duk_pop() in exit path */ |
| 60573 | } |
| 60574 | #endif |
| 60575 | |
| 60576 | /* The fast path for array property put is not fully compliant: |
| 60577 | * If one places conflicting number-indexed properties into |
| 60578 | * Array.prototype (for example, a non-writable Array.prototype[7]) |
| 60579 | * the fast path will incorrectly ignore them. |
| 60580 | * |
| 60581 | * This fast path could be made compliant by falling through |
| 60582 | * to the slow path if the previous value was UNUSED. This would |
| 60583 | * also remove the need to check for extensibility. Right now a |
| 60584 | * non-extensible array is slower than an extensible one as far |
| 60585 | * as writes are concerned. |
| 60586 | * |
| 60587 | * The fast path behavior is documented in more detail here: |
| 60588 | * tests/ecmascript/test-misc-array-fast-write.js |
| 60589 | */ |
| 60590 | |
| 60591 | /* XXX: array .length? */ |
| 60592 | |
| 60593 | #if defined(DUK_USE_ARRAY_PROP_FASTPATH) |
| 60594 | if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val) != 0) { |
| 60595 | DUK_DDD(DUK_DDDPRINT("array fast path success" )); |
| 60596 | DUK_STATS_INC(thr->heap, stats_putprop_arrayidx); |
| 60597 | return 1; |
| 60598 | } |
| 60599 | #endif |
| 60600 | |
| 60601 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 60602 | if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) { |
| 60603 | DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufobj fast path" )); |
| 60604 | DUK_STATS_INC(thr->heap, stats_putprop_bufobjidx); |
| 60605 | return 1; |
| 60606 | } |
| 60607 | #endif |
| 60608 | |
| 60609 | #if defined(DUK_USE_ES6_PROXY) |
| 60610 | if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(orig))) { |
| 60611 | duk_hobject *h_target; |
| 60612 | duk_bool_t tmp_bool; |
| 60613 | |
| 60614 | if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) { |
| 60615 | /* -> [ ... trap handler ] */ |
| 60616 | DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T" , (duk_tval *) tv_key)); |
| 60617 | DUK_STATS_INC(thr->heap, stats_putprop_proxy); |
| 60618 | duk_push_hobject(thr, h_target); /* target */ |
| 60619 | duk_push_tval(thr, tv_key); /* P */ |
| 60620 | duk_push_tval(thr, tv_val); /* V */ |
| 60621 | duk_push_tval(thr, tv_obj); /* Receiver: Proxy object */ |
| 60622 | duk_call_method(thr, 4 /*nargs*/); |
| 60623 | tmp_bool = duk_to_boolean_top_pop(thr); |
| 60624 | if (!tmp_bool) { |
| 60625 | goto fail_proxy_rejected; |
| 60626 | } |
| 60627 | |
| 60628 | /* Target object must be checked for a conflicting |
| 60629 | * non-configurable property. |
| 60630 | */ |
| 60631 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 60632 | DUK_ASSERT(key != NULL); |
| 60633 | |
| 60634 | if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 60635 | duk_tval *tv_targ = duk_require_tval(thr, -1); |
| 60636 | duk_bool_t datadesc_reject; |
| 60637 | duk_bool_t accdesc_reject; |
| 60638 | |
| 60639 | DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for " |
| 60640 | "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, " |
| 60641 | "desc.get=%p, desc.set=%p" , |
| 60642 | (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ, |
| 60643 | (unsigned long) desc.flags, |
| 60644 | (void *) desc.get, (void *) desc.set)); |
| 60645 | |
| 60646 | datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && |
| 60647 | !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && |
| 60648 | !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) && |
| 60649 | !duk_js_samevalue(tv_val, tv_targ); |
| 60650 | accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) && |
| 60651 | !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && |
| 60652 | (desc.set == NULL); |
| 60653 | if (datadesc_reject || accdesc_reject) { |
| 60654 | DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); |
| 60655 | DUK_WO_NORETURN(return 0;); |
| 60656 | } |
| 60657 | |
| 60658 | duk_pop_2_unsafe(thr); |
| 60659 | } else { |
| 60660 | duk_pop_unsafe(thr); |
| 60661 | } |
| 60662 | return 1; /* success */ |
| 60663 | } |
| 60664 | |
| 60665 | orig = h_target; /* resume write to target */ |
| 60666 | DUK_TVAL_SET_OBJECT(tv_obj, orig); |
| 60667 | } |
| 60668 | #endif /* DUK_USE_ES6_PROXY */ |
| 60669 | |
| 60670 | curr = orig; |
| 60671 | break; |
| 60672 | } |
| 60673 | |
| 60674 | case DUK_TAG_BUFFER: { |
| 60675 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj); |
| 60676 | duk_int_t pop_count = 0; |
| 60677 | |
| 60678 | /* |
| 60679 | * Because buffer values may be looped over and read/written |
| 60680 | * from, an array index fast path is important. |
| 60681 | */ |
| 60682 | |
| 60683 | #if defined(DUK_USE_FASTINT) |
| 60684 | if (DUK_TVAL_IS_FASTINT(tv_key)) { |
| 60685 | arr_idx = duk__tval_fastint_to_arr_idx(tv_key); |
| 60686 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld" , (long) arr_idx)); |
| 60687 | pop_count = 0; |
| 60688 | } else |
| 60689 | #endif |
| 60690 | if (DUK_TVAL_IS_NUMBER(tv_key)) { |
| 60691 | arr_idx = duk__tval_number_to_arr_idx(tv_key); |
| 60692 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld" , (long) arr_idx)); |
| 60693 | pop_count = 0; |
| 60694 | } else { |
| 60695 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 60696 | DUK_ASSERT(key != NULL); |
| 60697 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " |
| 60698 | "coercion key is %!T, arr_idx %ld" , |
| 60699 | (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); |
| 60700 | pop_count = 1; |
| 60701 | } |
| 60702 | |
| 60703 | if (arr_idx != DUK__NO_ARRAY_INDEX && |
| 60704 | arr_idx < DUK_HBUFFER_GET_SIZE(h)) { |
| 60705 | duk_uint8_t *data; |
| 60706 | DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld" , (long) arr_idx)); |
| 60707 | data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); |
| 60708 | |
| 60709 | /* XXX: duk_to_int() ensures we'll get 8 lowest bits as |
| 60710 | * as input is within duk_int_t range (capped outside it). |
| 60711 | */ |
| 60712 | #if defined(DUK_USE_FASTINT) |
| 60713 | /* Buffer writes are often integers. */ |
| 60714 | if (DUK_TVAL_IS_FASTINT(tv_val)) { |
| 60715 | data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val); |
| 60716 | } |
| 60717 | else |
| 60718 | #endif |
| 60719 | { |
| 60720 | duk_push_tval(thr, tv_val); |
| 60721 | data[arr_idx] = (duk_uint8_t) duk_to_uint32(thr, -1); |
| 60722 | pop_count++; |
| 60723 | } |
| 60724 | |
| 60725 | duk_pop_n_unsafe(thr, pop_count); |
| 60726 | DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)" )); |
| 60727 | DUK_STATS_INC(thr->heap, stats_putprop_bufferidx); |
| 60728 | return 1; |
| 60729 | } |
| 60730 | |
| 60731 | if (pop_count == 0) { |
| 60732 | /* This is a pretty awkward control flow, but we need to recheck the |
| 60733 | * key coercion here. |
| 60734 | */ |
| 60735 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 60736 | DUK_ASSERT(key != NULL); |
| 60737 | DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after " |
| 60738 | "coercion key is %!T, arr_idx %ld" , |
| 60739 | (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx)); |
| 60740 | } |
| 60741 | |
| 60742 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 60743 | goto fail_not_writable; |
| 60744 | } |
| 60745 | |
| 60746 | DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype" )); |
| 60747 | curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; |
| 60748 | goto lookup; /* avoid double coercion */ |
| 60749 | } |
| 60750 | |
| 60751 | case DUK_TAG_POINTER: { |
| 60752 | DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype" )); |
| 60753 | curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE]; |
| 60754 | break; |
| 60755 | } |
| 60756 | |
| 60757 | case DUK_TAG_LIGHTFUNC: { |
| 60758 | /* Lightfuncs have no own properties and are considered non-extensible. |
| 60759 | * However, the write may be captured by an inherited setter which |
| 60760 | * means we can't stop the lookup here. |
| 60761 | */ |
| 60762 | DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype" )); |
| 60763 | curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE]; |
| 60764 | break; |
| 60765 | } |
| 60766 | |
| 60767 | #if defined(DUK_USE_FASTINT) |
| 60768 | case DUK_TAG_FASTINT: |
| 60769 | #endif |
| 60770 | default: { |
| 60771 | /* number */ |
| 60772 | DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype" )); |
| 60773 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj)); |
| 60774 | curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]; |
| 60775 | break; |
| 60776 | } |
| 60777 | } |
| 60778 | |
| 60779 | DUK_ASSERT(key == NULL); |
| 60780 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 60781 | DUK_ASSERT(key != NULL); |
| 60782 | |
| 60783 | lookup: |
| 60784 | |
| 60785 | /* |
| 60786 | * Check whether the property already exists in the prototype chain. |
| 60787 | * Note that the actual write goes into the original base object |
| 60788 | * (except if an accessor property captures the write). |
| 60789 | */ |
| 60790 | |
| 60791 | /* [key] */ |
| 60792 | |
| 60793 | DUK_ASSERT(curr != NULL); |
| 60794 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 60795 | do { |
| 60796 | if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ |
| 60797 | goto next_in_chain; |
| 60798 | } |
| 60799 | |
| 60800 | if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 60801 | /* |
| 60802 | * Found existing accessor property (own or inherited). |
| 60803 | * Call setter with 'this' set to orig, and value as the only argument. |
| 60804 | * Setter calls are OK even for ROM objects. |
| 60805 | * |
| 60806 | * Note: no exotic arguments object behavior, because [[Put]] never |
| 60807 | * calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b). |
| 60808 | */ |
| 60809 | |
| 60810 | duk_hobject *setter; |
| 60811 | |
| 60812 | DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter" )); |
| 60813 | |
| 60814 | setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx); |
| 60815 | if (!setter) { |
| 60816 | goto fail_no_setter; |
| 60817 | } |
| 60818 | duk_push_hobject(thr, setter); |
| 60819 | duk_push_tval(thr, tv_obj); /* note: original, uncoerced base */ |
| 60820 | duk_push_tval(thr, tv_val); /* [key setter this val] */ |
| 60821 | #if defined(DUK_USE_NONSTD_SETTER_KEY_ARGUMENT) |
| 60822 | duk_dup_m4(thr); |
| 60823 | duk_call_method(thr, 2); /* [key setter this val key] -> [key retval] */ |
| 60824 | #else |
| 60825 | duk_call_method(thr, 1); /* [key setter this val] -> [key retval] */ |
| 60826 | #endif |
| 60827 | duk_pop_unsafe(thr); /* ignore retval -> [key] */ |
| 60828 | goto success_no_arguments_exotic; |
| 60829 | } |
| 60830 | |
| 60831 | if (orig == NULL) { |
| 60832 | /* |
| 60833 | * Found existing own or inherited plain property, but original |
| 60834 | * base is a primitive value. |
| 60835 | */ |
| 60836 | DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object" )); |
| 60837 | goto fail_base_primitive; |
| 60838 | } |
| 60839 | |
| 60840 | if (curr != orig) { |
| 60841 | /* |
| 60842 | * Found existing inherited plain property. |
| 60843 | * Do an access control check, and if OK, write |
| 60844 | * new property to 'orig'. |
| 60845 | */ |
| 60846 | if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) { |
| 60847 | DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible" )); |
| 60848 | goto fail_not_extensible; |
| 60849 | } |
| 60850 | if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) { |
| 60851 | DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable" )); |
| 60852 | goto fail_not_writable; |
| 60853 | } |
| 60854 | DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable" )); |
| 60855 | goto create_new; |
| 60856 | } else { |
| 60857 | /* |
| 60858 | * Found existing own (non-inherited) plain property. |
| 60859 | * Do an access control check and update in place. |
| 60860 | */ |
| 60861 | |
| 60862 | if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) { |
| 60863 | DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable" )); |
| 60864 | goto fail_not_writable; |
| 60865 | } |
| 60866 | if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) { |
| 60867 | DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable" )); |
| 60868 | |
| 60869 | if (DUK_HOBJECT_IS_ARRAY(curr)) { |
| 60870 | /* |
| 60871 | * Write to 'length' of an array is a very complex case |
| 60872 | * handled in a helper which updates both the array elements |
| 60873 | * and writes the new 'length'. The write may result in an |
| 60874 | * unconditional RangeError or a partial write (indicated |
| 60875 | * by a return code). |
| 60876 | * |
| 60877 | * Note: the helper has an unnecessary writability check |
| 60878 | * for 'length', we already know it is writable. |
| 60879 | */ |
| 60880 | DUK_ASSERT(key == DUK_HTHREAD_STRING_LENGTH(thr)); /* only virtual array property */ |
| 60881 | |
| 60882 | DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper" )); |
| 60883 | |
| 60884 | /* XXX: the helper currently assumes stack top contains new |
| 60885 | * 'length' value and the whole calling convention is not very |
| 60886 | * compatible with what we need. |
| 60887 | */ |
| 60888 | |
| 60889 | duk_push_tval(thr, tv_val); /* [key val] */ |
| 60890 | rc = duk__handle_put_array_length(thr, orig); |
| 60891 | duk_pop_unsafe(thr); /* [key val] -> [key] */ |
| 60892 | if (!rc) { |
| 60893 | goto fail_array_length_partial; |
| 60894 | } |
| 60895 | |
| 60896 | /* key is 'length', cannot match argument exotic behavior */ |
| 60897 | goto success_no_arguments_exotic; |
| 60898 | } |
| 60899 | #if defined(DUK_USE_BUFFEROBJECT_SUPPORT) |
| 60900 | else if (DUK_HOBJECT_IS_BUFOBJ(curr)) { |
| 60901 | duk_hbufobj *h_bufobj; |
| 60902 | duk_uint_t byte_off; |
| 60903 | duk_small_uint_t elem_size; |
| 60904 | |
| 60905 | h_bufobj = (duk_hbufobj *) curr; |
| 60906 | DUK_HBUFOBJ_ASSERT_VALID(h_bufobj); |
| 60907 | |
| 60908 | DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object" )); |
| 60909 | |
| 60910 | /* Careful with wrapping: arr_idx upshift may easily wrap, whereas |
| 60911 | * length downshift won't. |
| 60912 | */ |
| 60913 | if (arr_idx < (h_bufobj->length >> h_bufobj->shift) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) { |
| 60914 | duk_uint8_t *data; |
| 60915 | DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld" , (long) arr_idx)); |
| 60916 | |
| 60917 | DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */ |
| 60918 | byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */ |
| 60919 | elem_size = (duk_small_uint_t) (1U << h_bufobj->shift); |
| 60920 | |
| 60921 | /* Coerce to number before validating pointers etc so that the |
| 60922 | * number coercions in duk_hbufobj_validated_write() are |
| 60923 | * guaranteed to be side effect free and not invalidate the |
| 60924 | * pointer checks we do here. |
| 60925 | */ |
| 60926 | duk_push_tval(thr, tv_val); |
| 60927 | (void) duk_to_number_m1(thr); |
| 60928 | |
| 60929 | if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) { |
| 60930 | data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off; |
| 60931 | duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size); |
| 60932 | } else { |
| 60933 | DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)" )); |
| 60934 | } |
| 60935 | duk_pop_unsafe(thr); |
| 60936 | goto success_no_arguments_exotic; |
| 60937 | } |
| 60938 | } |
| 60939 | #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */ |
| 60940 | |
| 60941 | DUK_D(DUK_DPRINT("should not happen, key %!O" , key)); |
| 60942 | goto fail_internal; /* should not happen */ |
| 60943 | } |
| 60944 | DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable" )); |
| 60945 | goto update_old; |
| 60946 | } |
| 60947 | DUK_UNREACHABLE(); |
| 60948 | |
| 60949 | next_in_chain: |
| 60950 | /* XXX: option to pretend property doesn't exist if sanity limit is |
| 60951 | * hit might be useful. |
| 60952 | */ |
| 60953 | if (DUK_UNLIKELY(sanity-- == 0)) { |
| 60954 | DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); |
| 60955 | DUK_WO_NORETURN(return 0;); |
| 60956 | } |
| 60957 | curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr); |
| 60958 | } while (curr != NULL); |
| 60959 | |
| 60960 | /* |
| 60961 | * Property not found in prototype chain. |
| 60962 | */ |
| 60963 | |
| 60964 | DUK_DDD(DUK_DDDPRINT("property not found in prototype chain" )); |
| 60965 | |
| 60966 | if (orig == NULL) { |
| 60967 | DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object" )); |
| 60968 | goto fail_base_primitive; |
| 60969 | } |
| 60970 | |
| 60971 | if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) { |
| 60972 | DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible" )); |
| 60973 | goto fail_not_extensible; |
| 60974 | } |
| 60975 | |
| 60976 | goto create_new; |
| 60977 | |
| 60978 | update_old: |
| 60979 | |
| 60980 | /* |
| 60981 | * Update an existing property of the base object. |
| 60982 | */ |
| 60983 | |
| 60984 | /* [key] */ |
| 60985 | |
| 60986 | DUK_DDD(DUK_DDDPRINT("update an existing property of the original object" )); |
| 60987 | |
| 60988 | DUK_ASSERT(orig != NULL); |
| 60989 | #if defined(DUK_USE_ROM_OBJECTS) |
| 60990 | /* This should not happen because DUK_TAG_OBJECT case checks |
| 60991 | * for this already, but check just in case. |
| 60992 | */ |
| 60993 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) { |
| 60994 | goto fail_not_writable; |
| 60995 | } |
| 60996 | #endif |
| 60997 | |
| 60998 | /* Although there are writable virtual properties (e.g. plain buffer |
| 60999 | * and buffer object number indices), they are handled before we come |
| 61000 | * here. |
| 61001 | */ |
| 61002 | DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0); |
| 61003 | DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0); |
| 61004 | |
| 61005 | /* Array own property .length is handled above. */ |
| 61006 | DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr))); |
| 61007 | |
| 61008 | if (desc.e_idx >= 0) { |
| 61009 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx); |
| 61010 | DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT" , (duk_tval *) tv)); |
| 61011 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; e_idx may be invalidated */ |
| 61012 | /* don't touch property attributes or hash part */ |
| 61013 | DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT" , |
| 61014 | (long) desc.e_idx, (duk_tval *) tv)); |
| 61015 | } else { |
| 61016 | /* Note: array entries are always writable, so the writability check |
| 61017 | * above is pointless for them. The check could be avoided with some |
| 61018 | * refactoring but is probably not worth it. |
| 61019 | */ |
| 61020 | |
| 61021 | DUK_ASSERT(desc.a_idx >= 0); |
| 61022 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx); |
| 61023 | DUK_DDD(DUK_DDDPRINT("previous array value: %!iT" , (duk_tval *) tv)); |
| 61024 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; a_idx may be invalidated */ |
| 61025 | DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT" , |
| 61026 | (long) desc.a_idx, (duk_tval *) tv)); |
| 61027 | } |
| 61028 | |
| 61029 | /* Regardless of whether property is found in entry or array part, |
| 61030 | * it may have arguments exotic behavior (array indices may reside |
| 61031 | * in entry part for abandoned / non-existent array parts). |
| 61032 | */ |
| 61033 | goto success_with_arguments_exotic; |
| 61034 | |
| 61035 | create_new: |
| 61036 | |
| 61037 | /* |
| 61038 | * Create a new property in the original object. |
| 61039 | * |
| 61040 | * Exotic properties need to be reconsidered here from a write |
| 61041 | * perspective (not just property attributes perspective). |
| 61042 | * However, the property does not exist in the object already, |
| 61043 | * so this limits the kind of exotic properties that apply. |
| 61044 | */ |
| 61045 | |
| 61046 | /* [key] */ |
| 61047 | |
| 61048 | DUK_DDD(DUK_DDDPRINT("create new property to original object" )); |
| 61049 | |
| 61050 | DUK_ASSERT(orig != NULL); |
| 61051 | |
| 61052 | /* Array own property .length is handled above. */ |
| 61053 | DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr))); |
| 61054 | |
| 61055 | #if defined(DUK_USE_ROM_OBJECTS) |
| 61056 | /* This should not happen because DUK_TAG_OBJECT case checks |
| 61057 | * for this already, but check just in case. |
| 61058 | */ |
| 61059 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) { |
| 61060 | goto fail_not_writable; |
| 61061 | } |
| 61062 | #endif |
| 61063 | |
| 61064 | /* Not possible because array object 'length' is present |
| 61065 | * from its creation and cannot be deleted, and is thus |
| 61066 | * caught as an existing property above. |
| 61067 | */ |
| 61068 | DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) && |
| 61069 | key == DUK_HTHREAD_STRING_LENGTH(thr))); |
| 61070 | |
| 61071 | if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) && |
| 61072 | arr_idx != DUK__NO_ARRAY_INDEX) { |
| 61073 | /* automatic length update */ |
| 61074 | duk_uint32_t old_len; |
| 61075 | duk_harray *a; |
| 61076 | |
| 61077 | a = (duk_harray *) orig; |
| 61078 | DUK_HARRAY_ASSERT_VALID(a); |
| 61079 | |
| 61080 | old_len = a->length; |
| 61081 | |
| 61082 | if (arr_idx >= old_len) { |
| 61083 | DUK_DDD(DUK_DDDPRINT("write new array entry requires length update " |
| 61084 | "(arr_idx=%ld, old_len=%ld)" , |
| 61085 | (long) arr_idx, (long) old_len)); |
| 61086 | |
| 61087 | if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) { |
| 61088 | DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable" )); |
| 61089 | goto fail_not_writable; |
| 61090 | } |
| 61091 | |
| 61092 | /* Note: actual update happens once write has been completed |
| 61093 | * without error below. The write should always succeed |
| 61094 | * from a specification viewpoint, but we may e.g. run out |
| 61095 | * of memory. It's safer in this order. |
| 61096 | */ |
| 61097 | |
| 61098 | DUK_ASSERT(arr_idx != 0xffffffffUL); |
| 61099 | new_array_length = arr_idx + 1; /* flag for later write */ |
| 61100 | } else { |
| 61101 | DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update " |
| 61102 | "(arr_idx=%ld, old_len=%ld)" , |
| 61103 | (long) arr_idx, (long) old_len)); |
| 61104 | } |
| 61105 | } |
| 61106 | |
| 61107 | /* write_to_array_part: */ |
| 61108 | |
| 61109 | /* |
| 61110 | * Write to array part? |
| 61111 | * |
| 61112 | * Note: array abandonding requires a property resize which uses |
| 61113 | * 'rechecks' valstack for temporaries and may cause any existing |
| 61114 | * valstack pointers to be invalidated. To protect against this, |
| 61115 | * tv_obj, tv_key, and tv_val are copies of the original inputs. |
| 61116 | */ |
| 61117 | |
| 61118 | if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(orig)) { |
| 61119 | tv = duk__obtain_arridx_slot(thr, arr_idx, orig); |
| 61120 | if (tv == NULL) { |
| 61121 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig)); |
| 61122 | goto write_to_entry_part; |
| 61123 | } |
| 61124 | |
| 61125 | /* prev value must be unused, no decref */ |
| 61126 | DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv)); |
| 61127 | DUK_TVAL_SET_TVAL(tv, tv_val); |
| 61128 | DUK_TVAL_INCREF(thr, tv); |
| 61129 | DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T" , |
| 61130 | (long) arr_idx, (duk_tval *) tv)); |
| 61131 | |
| 61132 | /* Note: array part values are [[Writable]], [[Enumerable]], |
| 61133 | * and [[Configurable]] which matches the required attributes |
| 61134 | * here. |
| 61135 | */ |
| 61136 | goto entry_updated; |
| 61137 | } |
| 61138 | |
| 61139 | write_to_entry_part: |
| 61140 | |
| 61141 | /* |
| 61142 | * Write to entry part |
| 61143 | */ |
| 61144 | |
| 61145 | /* entry allocation updates hash part and increases the key |
| 61146 | * refcount; may need a props allocation resize but doesn't |
| 61147 | * 'recheck' the valstack. |
| 61148 | */ |
| 61149 | e_idx = duk__hobject_alloc_entry_checked(thr, orig, key); |
| 61150 | DUK_ASSERT(e_idx >= 0); |
| 61151 | |
| 61152 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx); |
| 61153 | /* prev value can be garbage, no decref */ |
| 61154 | DUK_TVAL_SET_TVAL(tv, tv_val); |
| 61155 | DUK_TVAL_INCREF(thr, tv); |
| 61156 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC); |
| 61157 | goto entry_updated; |
| 61158 | |
| 61159 | entry_updated: |
| 61160 | |
| 61161 | /* |
| 61162 | * Possible pending array length update, which must only be done |
| 61163 | * if the actual entry write succeeded. |
| 61164 | */ |
| 61165 | |
| 61166 | if (new_array_length > 0) { |
| 61167 | /* Note: zero works as a "no update" marker because the new length |
| 61168 | * can never be zero after a new property is written. |
| 61169 | */ |
| 61170 | |
| 61171 | DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig)); |
| 61172 | |
| 61173 | DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld" , |
| 61174 | (long) new_array_length)); |
| 61175 | |
| 61176 | ((duk_harray *) orig)->length = new_array_length; |
| 61177 | } |
| 61178 | |
| 61179 | /* |
| 61180 | * Arguments exotic behavior not possible for new properties: all |
| 61181 | * magically bound properties are initially present in the arguments |
| 61182 | * object, and if they are deleted, the binding is also removed from |
| 61183 | * parameter map. |
| 61184 | */ |
| 61185 | |
| 61186 | goto success_no_arguments_exotic; |
| 61187 | |
| 61188 | success_with_arguments_exotic: |
| 61189 | |
| 61190 | /* |
| 61191 | * Arguments objects have exotic [[DefineOwnProperty]] which updates |
| 61192 | * the internal 'map' of arguments for writes to currently mapped |
| 61193 | * arguments. More conretely, writes to mapped arguments generate |
| 61194 | * a write to a bound variable. |
| 61195 | * |
| 61196 | * The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing |
| 61197 | * data properties and new properties, but not for existing accessors. |
| 61198 | * Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we |
| 61199 | * have a Desc with 'Value' (and possibly other properties too), and |
| 61200 | * we end up in step 5.b.i. |
| 61201 | */ |
| 61202 | |
| 61203 | if (arr_idx != DUK__NO_ARRAY_INDEX && |
| 61204 | DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) { |
| 61205 | /* Note: only numbered indices are relevant, so arr_idx fast reject |
| 61206 | * is good (this is valid unless there are more than 4**32-1 arguments). |
| 61207 | */ |
| 61208 | |
| 61209 | DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed" )); |
| 61210 | |
| 61211 | /* Note: we can reuse 'desc' here */ |
| 61212 | |
| 61213 | /* XXX: top of stack must contain value, which helper doesn't touch, |
| 61214 | * rework to use tv_val directly? |
| 61215 | */ |
| 61216 | |
| 61217 | duk_push_tval(thr, tv_val); |
| 61218 | (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag); |
| 61219 | duk_pop_unsafe(thr); |
| 61220 | } |
| 61221 | /* fall thru */ |
| 61222 | |
| 61223 | success_no_arguments_exotic: |
| 61224 | /* shared exit path now */ |
| 61225 | DUK_DDD(DUK_DDDPRINT("result: success" )); |
| 61226 | duk_pop_unsafe(thr); /* remove key */ |
| 61227 | return 1; |
| 61228 | |
| 61229 | #if defined(DUK_USE_ES6_PROXY) |
| 61230 | fail_proxy_rejected: |
| 61231 | DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects" )); |
| 61232 | if (throw_flag) { |
| 61233 | DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); |
| 61234 | DUK_WO_NORETURN(return 0;); |
| 61235 | } |
| 61236 | /* Note: no key on stack */ |
| 61237 | return 0; |
| 61238 | #endif |
| 61239 | |
| 61240 | fail_base_primitive: |
| 61241 | DUK_DDD(DUK_DDDPRINT("result: error, base primitive" )); |
| 61242 | if (throw_flag) { |
| 61243 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 61244 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); |
| 61245 | #else |
| 61246 | DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s" , |
| 61247 | duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); |
| 61248 | #endif |
| 61249 | DUK_WO_NORETURN(return 0;); |
| 61250 | } |
| 61251 | duk_pop_unsafe(thr); /* remove key */ |
| 61252 | return 0; |
| 61253 | |
| 61254 | fail_not_extensible: |
| 61255 | DUK_DDD(DUK_DDDPRINT("result: error, not extensible" )); |
| 61256 | if (throw_flag) { |
| 61257 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE); |
| 61258 | DUK_WO_NORETURN(return 0;); |
| 61259 | } |
| 61260 | duk_pop_unsafe(thr); /* remove key */ |
| 61261 | return 0; |
| 61262 | |
| 61263 | fail_not_writable: |
| 61264 | DUK_DDD(DUK_DDDPRINT("result: error, not writable" )); |
| 61265 | if (throw_flag) { |
| 61266 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE); |
| 61267 | DUK_WO_NORETURN(return 0;); |
| 61268 | } |
| 61269 | duk_pop_unsafe(thr); /* remove key */ |
| 61270 | return 0; |
| 61271 | |
| 61272 | #if defined(DUK_USE_ROM_OBJECTS) |
| 61273 | fail_not_writable_no_pop: |
| 61274 | DUK_DDD(DUK_DDDPRINT("result: error, not writable" )); |
| 61275 | if (throw_flag) { |
| 61276 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE); |
| 61277 | DUK_WO_NORETURN(return 0;); |
| 61278 | } |
| 61279 | return 0; |
| 61280 | #endif |
| 61281 | |
| 61282 | fail_array_length_partial: |
| 61283 | DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful" )); |
| 61284 | if (throw_flag) { |
| 61285 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); |
| 61286 | DUK_WO_NORETURN(return 0;); |
| 61287 | } |
| 61288 | duk_pop_unsafe(thr); /* remove key */ |
| 61289 | return 0; |
| 61290 | |
| 61291 | fail_no_setter: |
| 61292 | DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter" )); |
| 61293 | if (throw_flag) { |
| 61294 | DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED); |
| 61295 | DUK_WO_NORETURN(return 0;); |
| 61296 | } |
| 61297 | duk_pop_unsafe(thr); /* remove key */ |
| 61298 | return 0; |
| 61299 | |
| 61300 | fail_internal: |
| 61301 | DUK_DDD(DUK_DDDPRINT("result: error, internal" )); |
| 61302 | if (throw_flag) { |
| 61303 | DUK_ERROR_INTERNAL(thr); |
| 61304 | DUK_WO_NORETURN(return 0;); |
| 61305 | } |
| 61306 | duk_pop_unsafe(thr); /* remove key */ |
| 61307 | return 0; |
| 61308 | } |
| 61309 | |
| 61310 | /* |
| 61311 | * ECMAScript compliant [[Delete]](P, Throw). |
| 61312 | */ |
| 61313 | |
| 61314 | DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) { |
| 61315 | duk_propdesc desc; |
| 61316 | duk_tval *tv; |
| 61317 | duk_uint32_t arr_idx; |
| 61318 | duk_bool_t throw_flag; |
| 61319 | duk_bool_t force_flag; |
| 61320 | |
| 61321 | throw_flag = (flags & DUK_DELPROP_FLAG_THROW); |
| 61322 | force_flag = (flags & DUK_DELPROP_FLAG_FORCE); |
| 61323 | |
| 61324 | DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)" , |
| 61325 | (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag, |
| 61326 | (duk_heaphdr *) obj, (duk_heaphdr *) key)); |
| 61327 | |
| 61328 | DUK_ASSERT(thr != NULL); |
| 61329 | DUK_ASSERT(thr->heap != NULL); |
| 61330 | DUK_ASSERT(obj != NULL); |
| 61331 | DUK_ASSERT(key != NULL); |
| 61332 | |
| 61333 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 61334 | |
| 61335 | arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key); |
| 61336 | |
| 61337 | /* 0 = don't push current value */ |
| 61338 | if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ |
| 61339 | DUK_DDD(DUK_DDDPRINT("property not found, succeed always" )); |
| 61340 | goto success; |
| 61341 | } |
| 61342 | |
| 61343 | #if defined(DUK_USE_ROM_OBJECTS) |
| 61344 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { |
| 61345 | DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object" )); |
| 61346 | goto fail_not_configurable; |
| 61347 | } |
| 61348 | #endif |
| 61349 | |
| 61350 | if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) { |
| 61351 | goto fail_not_configurable; |
| 61352 | } |
| 61353 | if (desc.a_idx < 0 && desc.e_idx < 0) { |
| 61354 | /* Currently there are no deletable virtual properties, but |
| 61355 | * with force_flag we might attempt to delete one. |
| 61356 | */ |
| 61357 | DUK_DD(DUK_DDPRINT("delete failed: property found, force flag, but virtual (and implicitly non-configurable)" )); |
| 61358 | goto fail_virtual; |
| 61359 | } |
| 61360 | |
| 61361 | if (desc.a_idx >= 0) { |
| 61362 | DUK_ASSERT(desc.e_idx < 0); |
| 61363 | |
| 61364 | tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx); |
| 61365 | DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */ |
| 61366 | goto success; |
| 61367 | } else { |
| 61368 | DUK_ASSERT(desc.a_idx < 0); |
| 61369 | |
| 61370 | /* remove hash entry (no decref) */ |
| 61371 | #if defined(DUK_USE_HOBJECT_HASH_PART) |
| 61372 | if (desc.h_idx >= 0) { |
| 61373 | duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj); |
| 61374 | |
| 61375 | DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld" , (long) desc.h_idx)); |
| 61376 | DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0); |
| 61377 | DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj)); |
| 61378 | h_base[desc.h_idx] = DUK__HASH_DELETED; |
| 61379 | } else { |
| 61380 | DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0); |
| 61381 | } |
| 61382 | #else |
| 61383 | DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0); |
| 61384 | #endif |
| 61385 | |
| 61386 | /* Remove value. This requires multiple writes so avoid side |
| 61387 | * effects via no-refzero macros so that e_idx is not |
| 61388 | * invalidated. |
| 61389 | */ |
| 61390 | DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p" , |
| 61391 | (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx))); |
| 61392 | DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld" , (long) desc.e_idx)); |
| 61393 | if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) { |
| 61394 | duk_hobject *tmp; |
| 61395 | |
| 61396 | tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx); |
| 61397 | DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL); |
| 61398 | DUK_UNREF(tmp); |
| 61399 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); |
| 61400 | |
| 61401 | tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx); |
| 61402 | DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL); |
| 61403 | DUK_UNREF(tmp); |
| 61404 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); |
| 61405 | } else { |
| 61406 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx); |
| 61407 | DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv); |
| 61408 | } |
| 61409 | #if 0 |
| 61410 | /* Not strictly necessary because if key == NULL, flag MUST be ignored. */ |
| 61411 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0); |
| 61412 | #endif |
| 61413 | |
| 61414 | /* Remove key. */ |
| 61415 | DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p" , |
| 61416 | (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx))); |
| 61417 | DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld" , (long) desc.e_idx)); |
| 61418 | DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)); |
| 61419 | DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL); |
| 61420 | DUK_HSTRING_DECREF_NORZ(thr, key); |
| 61421 | |
| 61422 | /* Trigger refzero side effects only when we're done as a |
| 61423 | * finalizer might operate on the object and affect the |
| 61424 | * e_idx we're supposed to use. |
| 61425 | */ |
| 61426 | DUK_REFZERO_CHECK_SLOW(thr); |
| 61427 | goto success; |
| 61428 | } |
| 61429 | |
| 61430 | DUK_UNREACHABLE(); |
| 61431 | |
| 61432 | success: |
| 61433 | /* |
| 61434 | * Argument exotic [[Delete]] behavior (E5 Section 10.6) is |
| 61435 | * a post-check, keeping arguments internal 'map' in sync with |
| 61436 | * any successful deletes (note that property does not need to |
| 61437 | * exist for delete to 'succeed'). |
| 61438 | * |
| 61439 | * Delete key from 'map'. Since 'map' only contains array index |
| 61440 | * keys, we can use arr_idx for a fast skip. |
| 61441 | */ |
| 61442 | |
| 61443 | DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior" )); |
| 61444 | |
| 61445 | if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) { |
| 61446 | /* Note: only numbered indices are relevant, so arr_idx fast reject |
| 61447 | * is good (this is valid unless there are more than 4**32-1 arguments). |
| 61448 | */ |
| 61449 | |
| 61450 | DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed" )); |
| 61451 | |
| 61452 | /* Note: we can reuse 'desc' here */ |
| 61453 | (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc); |
| 61454 | } |
| 61455 | |
| 61456 | DUK_DDD(DUK_DDDPRINT("delete successful" )); |
| 61457 | return 1; |
| 61458 | |
| 61459 | fail_virtual: /* just use the same "not configurable" error message */ |
| 61460 | fail_not_configurable: |
| 61461 | DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable" )); |
| 61462 | |
| 61463 | if (throw_flag) { |
| 61464 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); |
| 61465 | DUK_WO_NORETURN(return 0;); |
| 61466 | } |
| 61467 | return 0; |
| 61468 | } |
| 61469 | |
| 61470 | /* |
| 61471 | * DELPROP: ECMAScript property deletion. |
| 61472 | */ |
| 61473 | |
| 61474 | DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) { |
| 61475 | duk_hstring *key = NULL; |
| 61476 | #if defined(DUK_USE_ES6_PROXY) |
| 61477 | duk_propdesc desc; |
| 61478 | #endif |
| 61479 | duk_int_t entry_top; |
| 61480 | duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX; |
| 61481 | duk_bool_t rc; |
| 61482 | |
| 61483 | DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)" , |
| 61484 | (void *) thr, (void *) tv_obj, (void *) tv_key, |
| 61485 | (duk_tval *) tv_obj, (duk_tval *) tv_key)); |
| 61486 | |
| 61487 | DUK_ASSERT(thr != NULL); |
| 61488 | DUK_ASSERT(thr->heap != NULL); |
| 61489 | DUK_ASSERT(tv_obj != NULL); |
| 61490 | DUK_ASSERT(tv_key != NULL); |
| 61491 | |
| 61492 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 61493 | |
| 61494 | /* Storing the entry top is cheaper here to ensure stack is correct at exit, |
| 61495 | * as there are several paths out. |
| 61496 | */ |
| 61497 | entry_top = duk_get_top(thr); |
| 61498 | |
| 61499 | if (DUK_TVAL_IS_UNDEFINED(tv_obj) || |
| 61500 | DUK_TVAL_IS_NULL(tv_obj)) { |
| 61501 | DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject" )); |
| 61502 | goto fail_invalid_base_uncond; |
| 61503 | } |
| 61504 | |
| 61505 | duk_push_tval(thr, tv_obj); |
| 61506 | duk_push_tval(thr, tv_key); |
| 61507 | |
| 61508 | tv_obj = DUK_GET_TVAL_NEGIDX(thr, -2); |
| 61509 | if (DUK_TVAL_IS_OBJECT(tv_obj)) { |
| 61510 | duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj); |
| 61511 | DUK_ASSERT(obj != NULL); |
| 61512 | |
| 61513 | #if defined(DUK_USE_ES6_PROXY) |
| 61514 | if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) { |
| 61515 | duk_hobject *h_target; |
| 61516 | duk_bool_t tmp_bool; |
| 61517 | |
| 61518 | /* Note: proxy handling must happen before key is string coerced. */ |
| 61519 | |
| 61520 | if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) { |
| 61521 | /* -> [ ... obj key trap handler ] */ |
| 61522 | DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T" , (duk_tval *) tv_key)); |
| 61523 | duk_push_hobject(thr, h_target); /* target */ |
| 61524 | duk_dup_m4(thr); /* P */ |
| 61525 | duk_call_method(thr, 2 /*nargs*/); |
| 61526 | tmp_bool = duk_to_boolean_top_pop(thr); |
| 61527 | if (!tmp_bool) { |
| 61528 | goto fail_proxy_rejected; /* retval indicates delete failed */ |
| 61529 | } |
| 61530 | |
| 61531 | /* Target object must be checked for a conflicting |
| 61532 | * non-configurable property. |
| 61533 | */ |
| 61534 | tv_key = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 61535 | arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key); |
| 61536 | DUK_ASSERT(key != NULL); |
| 61537 | |
| 61538 | if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ |
| 61539 | duk_small_int_t desc_reject; |
| 61540 | |
| 61541 | DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for " |
| 61542 | "conflicting property; desc.flags=0x%08lx, " |
| 61543 | "desc.get=%p, desc.set=%p" , |
| 61544 | (duk_heaphdr *) key, (unsigned long) desc.flags, |
| 61545 | (void *) desc.get, (void *) desc.set)); |
| 61546 | |
| 61547 | desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE); |
| 61548 | if (desc_reject) { |
| 61549 | /* unconditional */ |
| 61550 | DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); |
| 61551 | DUK_WO_NORETURN(return 0;); |
| 61552 | } |
| 61553 | } |
| 61554 | rc = 1; /* success */ |
| 61555 | goto done_rc; |
| 61556 | } |
| 61557 | |
| 61558 | obj = h_target; /* resume delete to target */ |
| 61559 | } |
| 61560 | #endif /* DUK_USE_ES6_PROXY */ |
| 61561 | |
| 61562 | arr_idx = duk__to_property_key(thr, -1, &key); |
| 61563 | DUK_ASSERT(key != NULL); |
| 61564 | |
| 61565 | rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0); |
| 61566 | goto done_rc; |
| 61567 | } else if (DUK_TVAL_IS_STRING(tv_obj)) { |
| 61568 | /* String has .length and array index virtual properties |
| 61569 | * which can't be deleted. No need for a symbol check; |
| 61570 | * no offending virtual symbols exist. |
| 61571 | */ |
| 61572 | /* XXX: unnecessary string coercion for array indices, |
| 61573 | * intentional to keep small. |
| 61574 | */ |
| 61575 | duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj); |
| 61576 | DUK_ASSERT(h != NULL); |
| 61577 | |
| 61578 | arr_idx = duk__to_property_key(thr, -1, &key); |
| 61579 | DUK_ASSERT(key != NULL); |
| 61580 | |
| 61581 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 61582 | goto fail_not_configurable; |
| 61583 | } |
| 61584 | |
| 61585 | if (arr_idx != DUK__NO_ARRAY_INDEX && |
| 61586 | arr_idx < DUK_HSTRING_GET_CHARLEN(h)) { |
| 61587 | goto fail_not_configurable; |
| 61588 | } |
| 61589 | } else if (DUK_TVAL_IS_BUFFER(tv_obj)) { |
| 61590 | /* XXX: unnecessary string coercion for array indices, |
| 61591 | * intentional to keep small; some overlap with string |
| 61592 | * handling. |
| 61593 | */ |
| 61594 | duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj); |
| 61595 | DUK_ASSERT(h != NULL); |
| 61596 | |
| 61597 | arr_idx = duk__to_property_key(thr, -1, &key); |
| 61598 | DUK_ASSERT(key != NULL); |
| 61599 | |
| 61600 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 61601 | goto fail_not_configurable; |
| 61602 | } |
| 61603 | |
| 61604 | if (arr_idx != DUK__NO_ARRAY_INDEX && |
| 61605 | arr_idx < DUK_HBUFFER_GET_SIZE(h)) { |
| 61606 | goto fail_not_configurable; |
| 61607 | } |
| 61608 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) { |
| 61609 | /* Lightfunc has no virtual properties since Duktape 2.2 |
| 61610 | * so success. Still must coerce key for side effects. |
| 61611 | */ |
| 61612 | |
| 61613 | arr_idx = duk__to_property_key(thr, -1, &key); |
| 61614 | DUK_ASSERT(key != NULL); |
| 61615 | DUK_UNREF(key); |
| 61616 | } |
| 61617 | |
| 61618 | /* non-object base, no offending virtual property */ |
| 61619 | rc = 1; |
| 61620 | goto done_rc; |
| 61621 | |
| 61622 | done_rc: |
| 61623 | duk_set_top_unsafe(thr, entry_top); |
| 61624 | return rc; |
| 61625 | |
| 61626 | fail_invalid_base_uncond: |
| 61627 | /* Note: unconditional throw */ |
| 61628 | DUK_ASSERT(duk_get_top(thr) == entry_top); |
| 61629 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 61630 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE); |
| 61631 | #else |
| 61632 | DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s" , |
| 61633 | duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj)); |
| 61634 | #endif |
| 61635 | DUK_WO_NORETURN(return 0;); |
| 61636 | |
| 61637 | #if defined(DUK_USE_ES6_PROXY) |
| 61638 | fail_proxy_rejected: |
| 61639 | if (throw_flag) { |
| 61640 | DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED); |
| 61641 | DUK_WO_NORETURN(return 0;); |
| 61642 | } |
| 61643 | duk_set_top_unsafe(thr, entry_top); |
| 61644 | return 0; |
| 61645 | #endif |
| 61646 | |
| 61647 | fail_not_configurable: |
| 61648 | if (throw_flag) { |
| 61649 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); |
| 61650 | DUK_WO_NORETURN(return 0;); |
| 61651 | } |
| 61652 | duk_set_top_unsafe(thr, entry_top); |
| 61653 | return 0; |
| 61654 | } |
| 61655 | |
| 61656 | /* |
| 61657 | * Internal helper to define a property with specific flags, ignoring |
| 61658 | * normal semantics such as extensibility, write protection etc. |
| 61659 | * Overwrites any existing value and attributes unless caller requests |
| 61660 | * that value only be updated if it doesn't already exists. |
| 61661 | * |
| 61662 | * Does not support: |
| 61663 | * - virtual properties (error if write attempted) |
| 61664 | * - getter/setter properties (error if write attempted) |
| 61665 | * - non-default (!= WEC) attributes for array entries (error if attempted) |
| 61666 | * - array abandoning: if array part exists, it is always extended |
| 61667 | * - array 'length' updating |
| 61668 | * |
| 61669 | * Stack: [... in_val] -> [] |
| 61670 | * |
| 61671 | * Used for e.g. built-in initialization and environment record |
| 61672 | * operations. |
| 61673 | */ |
| 61674 | |
| 61675 | DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) { |
| 61676 | duk_propdesc desc; |
| 61677 | duk_uint32_t arr_idx; |
| 61678 | duk_int_t e_idx; |
| 61679 | duk_tval *tv1 = NULL; |
| 61680 | duk_tval *tv2 = NULL; |
| 61681 | duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */ |
| 61682 | |
| 61683 | DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T" , |
| 61684 | (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key, |
| 61685 | (unsigned long) flags, (duk_tval *) duk_get_tval(thr, -1))); |
| 61686 | |
| 61687 | DUK_ASSERT(thr != NULL); |
| 61688 | DUK_ASSERT(thr->heap != NULL); |
| 61689 | DUK_ASSERT(obj != NULL); |
| 61690 | DUK_ASSERT(key != NULL); |
| 61691 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); |
| 61692 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 61693 | DUK_ASSERT(duk_is_valid_index(thr, -1)); /* contains value */ |
| 61694 | |
| 61695 | arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); |
| 61696 | |
| 61697 | if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */ |
| 61698 | if (desc.e_idx >= 0) { |
| 61699 | if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) { |
| 61700 | DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested" )); |
| 61701 | goto pop_exit; |
| 61702 | } |
| 61703 | DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes" )); |
| 61704 | if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) { |
| 61705 | DUK_D(DUK_DPRINT("existing property is an accessor, not supported" )); |
| 61706 | goto error_internal; |
| 61707 | } |
| 61708 | |
| 61709 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags); |
| 61710 | tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx); |
| 61711 | } else if (desc.a_idx >= 0) { |
| 61712 | if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) { |
| 61713 | DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested" )); |
| 61714 | goto pop_exit; |
| 61715 | } |
| 61716 | DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)" )); |
| 61717 | if (propflags != DUK_PROPDESC_FLAGS_WEC) { |
| 61718 | DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)" , |
| 61719 | (unsigned long) propflags)); |
| 61720 | goto error_internal; |
| 61721 | } |
| 61722 | |
| 61723 | tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx); |
| 61724 | } else { |
| 61725 | if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) { |
| 61726 | DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested" )); |
| 61727 | goto pop_exit; |
| 61728 | } |
| 61729 | if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { |
| 61730 | duk_uint32_t new_len; |
| 61731 | #if defined(DUK_USE_DEBUG) |
| 61732 | duk_uint32_t prev_len; |
| 61733 | prev_len = ((duk_harray *) obj)->length; |
| 61734 | #endif |
| 61735 | new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1)); |
| 61736 | ((duk_harray *) obj)->length = new_len; |
| 61737 | DUK_DD(DUK_DDPRINT("internal define property for array .length: %ld -> %ld" , |
| 61738 | (long) prev_len, (long) ((duk_harray *) obj)->length)); |
| 61739 | goto pop_exit; |
| 61740 | } |
| 61741 | DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure" )); |
| 61742 | goto error_virtual; |
| 61743 | } |
| 61744 | |
| 61745 | goto write_value; |
| 61746 | } |
| 61747 | |
| 61748 | if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) { |
| 61749 | if (arr_idx != DUK__NO_ARRAY_INDEX) { |
| 61750 | DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)" )); |
| 61751 | DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC); |
| 61752 | |
| 61753 | tv1 = duk__obtain_arridx_slot(thr, arr_idx, obj); |
| 61754 | if (tv1 == NULL) { |
| 61755 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj)); |
| 61756 | goto write_to_entry_part; |
| 61757 | } |
| 61758 | |
| 61759 | tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx); |
| 61760 | goto write_value; |
| 61761 | } |
| 61762 | } |
| 61763 | |
| 61764 | write_to_entry_part: |
| 61765 | DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes" )); |
| 61766 | e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); /* increases key refcount */ |
| 61767 | DUK_ASSERT(e_idx >= 0); |
| 61768 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags); |
| 61769 | tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx); |
| 61770 | /* new entry: previous value is garbage; set to undefined to share write_value */ |
| 61771 | DUK_TVAL_SET_UNDEFINED(tv1); |
| 61772 | goto write_value; |
| 61773 | |
| 61774 | write_value: |
| 61775 | /* tv1 points to value storage */ |
| 61776 | |
| 61777 | tv2 = duk_require_tval(thr, -1); /* late lookup, avoid side effects */ |
| 61778 | DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T" , |
| 61779 | (duk_tval *) tv1, (duk_tval *) tv2)); |
| 61780 | |
| 61781 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ |
| 61782 | goto pop_exit; |
| 61783 | |
| 61784 | pop_exit: |
| 61785 | duk_pop_unsafe(thr); /* remove in_val */ |
| 61786 | return; |
| 61787 | |
| 61788 | error_virtual: /* share error message */ |
| 61789 | error_internal: |
| 61790 | DUK_ERROR_INTERNAL(thr); |
| 61791 | DUK_WO_NORETURN(return;); |
| 61792 | } |
| 61793 | |
| 61794 | /* |
| 61795 | * Fast path for defining array indexed values without interning the key. |
| 61796 | * This is used by e.g. code for Array prototype and traceback creation so |
| 61797 | * must avoid interning. |
| 61798 | */ |
| 61799 | |
| 61800 | DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) { |
| 61801 | duk_hstring *key; |
| 61802 | duk_tval *tv1, *tv2; |
| 61803 | |
| 61804 | DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, " |
| 61805 | "arr_idx=%ld, flags=0x%02lx, val=%!T" , |
| 61806 | (void *) thr, obj, (long) arr_idx, (unsigned long) flags, |
| 61807 | (duk_tval *) duk_get_tval(thr, -1))); |
| 61808 | |
| 61809 | DUK_ASSERT(thr != NULL); |
| 61810 | DUK_ASSERT(thr->heap != NULL); |
| 61811 | DUK_ASSERT(obj != NULL); |
| 61812 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); |
| 61813 | |
| 61814 | if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && |
| 61815 | arr_idx != DUK__NO_ARRAY_INDEX && |
| 61816 | flags == DUK_PROPDESC_FLAGS_WEC) { |
| 61817 | DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0); /* covered by comparison */ |
| 61818 | |
| 61819 | DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)" )); |
| 61820 | |
| 61821 | tv1 = duk__obtain_arridx_slot(thr, arr_idx, obj); |
| 61822 | if (tv1 == NULL) { |
| 61823 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(obj)); |
| 61824 | goto write_slow; |
| 61825 | } |
| 61826 | tv2 = duk_require_tval(thr, -1); |
| 61827 | |
| 61828 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ |
| 61829 | |
| 61830 | duk_pop_unsafe(thr); /* [ ...val ] -> [ ... ] */ |
| 61831 | return; |
| 61832 | } |
| 61833 | |
| 61834 | write_slow: |
| 61835 | DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path" )); |
| 61836 | |
| 61837 | key = duk_push_uint_to_hstring(thr, (duk_uint_t) arr_idx); |
| 61838 | DUK_ASSERT(key != NULL); |
| 61839 | duk_insert(thr, -2); /* [ ... val key ] -> [ ... key val ] */ |
| 61840 | |
| 61841 | duk_hobject_define_property_internal(thr, obj, key, flags); |
| 61842 | |
| 61843 | duk_pop_unsafe(thr); /* [ ... key ] -> [ ... ] */ |
| 61844 | } |
| 61845 | |
| 61846 | /* |
| 61847 | * Internal helpers for managing object 'length' |
| 61848 | */ |
| 61849 | |
| 61850 | DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) { |
| 61851 | duk_double_t val; |
| 61852 | |
| 61853 | DUK_CTX_ASSERT_VALID(thr); |
| 61854 | DUK_ASSERT(obj != NULL); |
| 61855 | |
| 61856 | /* Fast path for Arrays. */ |
| 61857 | if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { |
| 61858 | return ((duk_harray *) obj)->length; |
| 61859 | } |
| 61860 | |
| 61861 | /* Slow path, .length can be e.g. accessor, obj can be a Proxy, etc. */ |
| 61862 | duk_push_hobject(thr, obj); |
| 61863 | duk_push_hstring_stridx(thr, DUK_STRIDX_LENGTH); |
| 61864 | (void) duk_hobject_getprop(thr, |
| 61865 | DUK_GET_TVAL_NEGIDX(thr, -2), |
| 61866 | DUK_GET_TVAL_NEGIDX(thr, -1)); |
| 61867 | val = duk_to_number_m1(thr); |
| 61868 | duk_pop_3_unsafe(thr); |
| 61869 | |
| 61870 | /* This isn't part of ECMAScript semantics; return a value within |
| 61871 | * duk_size_t range, or 0 otherwise. |
| 61872 | */ |
| 61873 | if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) { |
| 61874 | return (duk_size_t) val; |
| 61875 | } |
| 61876 | return 0; |
| 61877 | } |
| 61878 | |
| 61879 | /* |
| 61880 | * Fast finalizer check for an object. Walks the prototype chain, checking |
| 61881 | * for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept |
| 61882 | * in sync with the actual property when setting/removing the finalizer. |
| 61883 | */ |
| 61884 | |
| 61885 | #if defined(DUK_USE_HEAPPTR16) |
| 61886 | DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) { |
| 61887 | #else |
| 61888 | DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) { |
| 61889 | #endif |
| 61890 | duk_uint_t sanity; |
| 61891 | |
| 61892 | DUK_ASSERT(obj != NULL); |
| 61893 | |
| 61894 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 61895 | do { |
| 61896 | if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) { |
| 61897 | return 1; |
| 61898 | } |
| 61899 | if (DUK_UNLIKELY(sanity-- == 0)) { |
| 61900 | DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false" )); |
| 61901 | return 0; |
| 61902 | } |
| 61903 | #if defined(DUK_USE_HEAPPTR16) |
| 61904 | DUK_ASSERT(heap != NULL); |
| 61905 | obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj); |
| 61906 | #else |
| 61907 | obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj); /* 'heap' arg ignored */ |
| 61908 | #endif |
| 61909 | } while (obj != NULL); |
| 61910 | |
| 61911 | return 0; |
| 61912 | } |
| 61913 | |
| 61914 | /* |
| 61915 | * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4) |
| 61916 | * |
| 61917 | * [ ... key ] -> [ ... desc/undefined ] |
| 61918 | */ |
| 61919 | |
| 61920 | DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx) { |
| 61921 | duk_hobject *obj; |
| 61922 | duk_hstring *key; |
| 61923 | duk_propdesc pd; |
| 61924 | |
| 61925 | DUK_ASSERT(thr != NULL); |
| 61926 | DUK_ASSERT(thr->heap != NULL); |
| 61927 | |
| 61928 | obj = duk_require_hobject_promote_mask(thr, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 61929 | key = duk_to_property_key_hstring(thr, -1); |
| 61930 | DUK_ASSERT(key != NULL); |
| 61931 | |
| 61932 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 61933 | |
| 61934 | if (!duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 61935 | duk_push_undefined(thr); |
| 61936 | duk_remove_m2(thr); |
| 61937 | return; |
| 61938 | } |
| 61939 | |
| 61940 | duk_push_object(thr); |
| 61941 | |
| 61942 | /* [ ... key value desc ] */ |
| 61943 | |
| 61944 | if (DUK_PROPDESC_IS_ACCESSOR(&pd)) { |
| 61945 | /* If a setter/getter is missing (undefined), the descriptor must |
| 61946 | * still have the property present with the value 'undefined'. |
| 61947 | */ |
| 61948 | if (pd.get) { |
| 61949 | duk_push_hobject(thr, pd.get); |
| 61950 | } else { |
| 61951 | duk_push_undefined(thr); |
| 61952 | } |
| 61953 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_GET); |
| 61954 | if (pd.set) { |
| 61955 | duk_push_hobject(thr, pd.set); |
| 61956 | } else { |
| 61957 | duk_push_undefined(thr); |
| 61958 | } |
| 61959 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_SET); |
| 61960 | } else { |
| 61961 | duk_dup_m2(thr); |
| 61962 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_VALUE); |
| 61963 | duk_push_boolean(thr, DUK_PROPDESC_IS_WRITABLE(&pd)); |
| 61964 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_WRITABLE); |
| 61965 | } |
| 61966 | duk_push_boolean(thr, DUK_PROPDESC_IS_ENUMERABLE(&pd)); |
| 61967 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_ENUMERABLE); |
| 61968 | duk_push_boolean(thr, DUK_PROPDESC_IS_CONFIGURABLE(&pd)); |
| 61969 | duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_CONFIGURABLE); |
| 61970 | |
| 61971 | /* [ ... key value desc ] */ |
| 61972 | |
| 61973 | duk_replace(thr, -3); |
| 61974 | duk_pop_unsafe(thr); /* -> [ ... desc ] */ |
| 61975 | } |
| 61976 | |
| 61977 | /* |
| 61978 | * NormalizePropertyDescriptor() related helper. |
| 61979 | * |
| 61980 | * Internal helper which validates and normalizes a property descriptor |
| 61981 | * represented as an ECMAScript object (e.g. argument to defineProperty()). |
| 61982 | * The output of this conversion is a set of defprop_flags and possibly |
| 61983 | * some values pushed on the value stack to (1) ensure borrowed pointers |
| 61984 | * remain valid, and (2) avoid unnecessary pops for footprint reasons. |
| 61985 | * Caller must manage stack top carefully because the number of values |
| 61986 | * pushed depends on the input property descriptor. |
| 61987 | * |
| 61988 | * The original descriptor object must not be altered in the process. |
| 61989 | */ |
| 61990 | |
| 61991 | /* XXX: very basic optimization -> duk_get_prop_stridx_top */ |
| 61992 | |
| 61993 | DUK_INTERNAL |
| 61994 | void duk_hobject_prepare_property_descriptor(duk_hthread *thr, |
| 61995 | duk_idx_t idx_in, |
| 61996 | duk_uint_t *out_defprop_flags, |
| 61997 | duk_idx_t *out_idx_value, |
| 61998 | duk_hobject **out_getter, |
| 61999 | duk_hobject **out_setter) { |
| 62000 | duk_idx_t idx_value = -1; |
| 62001 | duk_hobject *getter = NULL; |
| 62002 | duk_hobject *setter = NULL; |
| 62003 | duk_bool_t is_data_desc = 0; |
| 62004 | duk_bool_t is_acc_desc = 0; |
| 62005 | duk_uint_t defprop_flags = 0; |
| 62006 | |
| 62007 | DUK_ASSERT(out_defprop_flags != NULL); |
| 62008 | DUK_ASSERT(out_idx_value != NULL); |
| 62009 | DUK_ASSERT(out_getter != NULL); |
| 62010 | DUK_ASSERT(out_setter != NULL); |
| 62011 | DUK_ASSERT(idx_in <= 0x7fffL); /* short variants would be OK, but not used to avoid shifts */ |
| 62012 | |
| 62013 | /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */ |
| 62014 | idx_in = duk_require_normalize_index(thr, idx_in); |
| 62015 | (void) duk_require_hobject(thr, idx_in); |
| 62016 | |
| 62017 | /* The coercion order must match the ToPropertyDescriptor() algorithm |
| 62018 | * so that side effects in coercion happen in the correct order. |
| 62019 | * (This order also happens to be compatible with duk_def_prop(), |
| 62020 | * although it doesn't matter in practice.) |
| 62021 | */ |
| 62022 | |
| 62023 | if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_VALUE)) { |
| 62024 | is_data_desc = 1; |
| 62025 | defprop_flags |= DUK_DEFPROP_HAVE_VALUE; |
| 62026 | idx_value = duk_get_top_index(thr); |
| 62027 | } |
| 62028 | |
| 62029 | if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) { |
| 62030 | is_data_desc = 1; |
| 62031 | if (duk_to_boolean_top_pop(thr)) { |
| 62032 | defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE; |
| 62033 | } else { |
| 62034 | defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE; |
| 62035 | } |
| 62036 | } |
| 62037 | |
| 62038 | if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_GET)) { |
| 62039 | duk_tval *tv = duk_require_tval(thr, -1); |
| 62040 | duk_hobject *h_get; |
| 62041 | |
| 62042 | if (DUK_TVAL_IS_UNDEFINED(tv)) { |
| 62043 | /* undefined is accepted */ |
| 62044 | DUK_ASSERT(getter == NULL); |
| 62045 | } else { |
| 62046 | /* NOTE: lightfuncs are coerced to full functions because |
| 62047 | * lightfuncs don't fit into a property value slot. This |
| 62048 | * has some side effects, see test-dev-lightfunc-accessor.js. |
| 62049 | */ |
| 62050 | h_get = duk_get_hobject_promote_lfunc(thr, -1); |
| 62051 | if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) { |
| 62052 | goto type_error; |
| 62053 | } |
| 62054 | getter = h_get; |
| 62055 | } |
| 62056 | is_acc_desc = 1; |
| 62057 | defprop_flags |= DUK_DEFPROP_HAVE_GETTER; |
| 62058 | } |
| 62059 | |
| 62060 | if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_SET)) { |
| 62061 | duk_tval *tv = duk_require_tval(thr, -1); |
| 62062 | duk_hobject *h_set; |
| 62063 | |
| 62064 | if (DUK_TVAL_IS_UNDEFINED(tv)) { |
| 62065 | /* undefined is accepted */ |
| 62066 | DUK_ASSERT(setter == NULL); |
| 62067 | } else { |
| 62068 | /* NOTE: lightfuncs are coerced to full functions because |
| 62069 | * lightfuncs don't fit into a property value slot. This |
| 62070 | * has some side effects, see test-dev-lightfunc-accessor.js. |
| 62071 | */ |
| 62072 | h_set = duk_get_hobject_promote_lfunc(thr, -1); |
| 62073 | if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) { |
| 62074 | goto type_error; |
| 62075 | } |
| 62076 | setter = h_set; |
| 62077 | } |
| 62078 | is_acc_desc = 1; |
| 62079 | defprop_flags |= DUK_DEFPROP_HAVE_SETTER; |
| 62080 | } |
| 62081 | |
| 62082 | if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) { |
| 62083 | if (duk_to_boolean_top_pop(thr)) { |
| 62084 | defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE; |
| 62085 | } else { |
| 62086 | defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE; |
| 62087 | } |
| 62088 | } |
| 62089 | |
| 62090 | if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) { |
| 62091 | if (duk_to_boolean_top_pop(thr)) { |
| 62092 | defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE; |
| 62093 | } else { |
| 62094 | defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE; |
| 62095 | } |
| 62096 | } |
| 62097 | |
| 62098 | if (is_data_desc && is_acc_desc) { |
| 62099 | goto type_error; |
| 62100 | } |
| 62101 | |
| 62102 | *out_defprop_flags = defprop_flags; |
| 62103 | *out_idx_value = idx_value; |
| 62104 | *out_getter = getter; |
| 62105 | *out_setter = setter; |
| 62106 | |
| 62107 | /* [ ... [multiple values] ] */ |
| 62108 | return; |
| 62109 | |
| 62110 | type_error: |
| 62111 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR); |
| 62112 | DUK_WO_NORETURN(return;); |
| 62113 | } |
| 62114 | |
| 62115 | /* |
| 62116 | * Object.defineProperty() related helper (E5 Section 15.2.3.6). |
| 62117 | * Also handles ES2015 Reflect.defineProperty(). |
| 62118 | * |
| 62119 | * Inlines all [[DefineOwnProperty]] exotic behaviors. |
| 62120 | * |
| 62121 | * Note: ECMAScript compliant [[DefineOwnProperty]](P, Desc, Throw) is not |
| 62122 | * implemented directly, but Object.defineProperty() serves its purpose. |
| 62123 | * We don't need the [[DefineOwnProperty]] internally and we don't have a |
| 62124 | * property descriptor with 'missing values' so it's easier to avoid it |
| 62125 | * entirely. |
| 62126 | * |
| 62127 | * Note: this is only called for actual objects, not primitive values. |
| 62128 | * This must support virtual properties for full objects (e.g. Strings) |
| 62129 | * but not for plain values (e.g. strings). Lightfuncs, even though |
| 62130 | * primitive in a sense, are treated like objects and accepted as target |
| 62131 | * values. |
| 62132 | */ |
| 62133 | |
| 62134 | /* XXX: this is a major target for size optimization */ |
| 62135 | DUK_INTERNAL |
| 62136 | duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr, |
| 62137 | duk_uint_t defprop_flags, |
| 62138 | duk_hobject *obj, |
| 62139 | duk_hstring *key, |
| 62140 | duk_idx_t idx_value, |
| 62141 | duk_hobject *get, |
| 62142 | duk_hobject *set, |
| 62143 | duk_bool_t throw_flag) { |
| 62144 | duk_uint32_t arr_idx; |
| 62145 | duk_tval tv; |
| 62146 | duk_bool_t has_enumerable; |
| 62147 | duk_bool_t has_configurable; |
| 62148 | duk_bool_t has_writable; |
| 62149 | duk_bool_t has_value; |
| 62150 | duk_bool_t has_get; |
| 62151 | duk_bool_t has_set; |
| 62152 | duk_bool_t is_enumerable; |
| 62153 | duk_bool_t is_configurable; |
| 62154 | duk_bool_t is_writable; |
| 62155 | duk_bool_t force_flag; |
| 62156 | duk_small_uint_t new_flags; |
| 62157 | duk_propdesc curr; |
| 62158 | duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */ |
| 62159 | duk_uint32_t arrlen_old_len; |
| 62160 | duk_uint32_t arrlen_new_len; |
| 62161 | duk_bool_t pending_write_protect; |
| 62162 | |
| 62163 | DUK_ASSERT(thr != NULL); |
| 62164 | DUK_ASSERT(thr->heap != NULL); |
| 62165 | DUK_ASSERT(obj != NULL); |
| 62166 | DUK_ASSERT(key != NULL); |
| 62167 | /* idx_value may be < 0 (no value), set and get may be NULL */ |
| 62168 | |
| 62169 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 62170 | |
| 62171 | /* All the flags fit in 16 bits, so will fit into duk_bool_t. */ |
| 62172 | |
| 62173 | has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE); |
| 62174 | has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE); |
| 62175 | has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE); |
| 62176 | has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE); |
| 62177 | has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER); |
| 62178 | has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER); |
| 62179 | is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE); |
| 62180 | is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE); |
| 62181 | is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE); |
| 62182 | force_flag = (defprop_flags & DUK_DEFPROP_FORCE); |
| 62183 | |
| 62184 | arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key); |
| 62185 | |
| 62186 | arridx_new_array_length = 0; |
| 62187 | pending_write_protect = 0; |
| 62188 | arrlen_old_len = 0; |
| 62189 | arrlen_new_len = 0; |
| 62190 | |
| 62191 | DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld " |
| 62192 | "has_configurable=%ld is_configurable=%ld " |
| 62193 | "has_writable=%ld is_writable=%ld " |
| 62194 | "has_value=%ld value=%!T " |
| 62195 | "has_get=%ld get=%p=%!O " |
| 62196 | "has_set=%ld set=%p=%!O " |
| 62197 | "arr_idx=%ld throw_flag=!%ld" , |
| 62198 | (long) has_enumerable, (long) is_enumerable, |
| 62199 | (long) has_configurable, (long) is_configurable, |
| 62200 | (long) has_writable, (long) is_writable, |
| 62201 | (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(thr, idx_value) : NULL), |
| 62202 | (long) has_get, (void *) get, (duk_heaphdr *) get, |
| 62203 | (long) has_set, (void *) set, (duk_heaphdr *) set, |
| 62204 | (long) arr_idx, (long) throw_flag)); |
| 62205 | |
| 62206 | /* |
| 62207 | * Array exotic behaviors can be implemented at this point. The local variables |
| 62208 | * are essentially a 'value copy' of the input descriptor (Desc), which is modified |
| 62209 | * by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1). |
| 62210 | */ |
| 62211 | |
| 62212 | if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { |
| 62213 | goto skip_array_exotic; |
| 62214 | } |
| 62215 | |
| 62216 | if (key == DUK_HTHREAD_STRING_LENGTH(thr)) { |
| 62217 | duk_harray *a; |
| 62218 | |
| 62219 | /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */ |
| 62220 | if (!has_value) { |
| 62221 | DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior" )); |
| 62222 | goto skip_array_exotic; |
| 62223 | } |
| 62224 | |
| 62225 | DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior" )); |
| 62226 | |
| 62227 | /* |
| 62228 | * Get old and new length |
| 62229 | */ |
| 62230 | |
| 62231 | a = (duk_harray *) obj; |
| 62232 | DUK_HARRAY_ASSERT_VALID(a); |
| 62233 | arrlen_old_len = a->length; |
| 62234 | |
| 62235 | DUK_ASSERT(idx_value >= 0); |
| 62236 | arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(thr, idx_value)); |
| 62237 | duk_push_u32(thr, arrlen_new_len); |
| 62238 | duk_replace(thr, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */ |
| 62239 | |
| 62240 | DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld" , (long) arrlen_old_len, (long) arrlen_new_len)); |
| 62241 | |
| 62242 | if (arrlen_new_len >= arrlen_old_len) { |
| 62243 | /* standard behavior, step 3.f.i */ |
| 62244 | DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior" )); |
| 62245 | goto skip_array_exotic; |
| 62246 | } |
| 62247 | DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior" )); |
| 62248 | |
| 62249 | /* XXX: consolidated algorithm step 15.f -> redundant? */ |
| 62250 | if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) { |
| 62251 | /* Array .length is always non-configurable; if it's also |
| 62252 | * non-writable, don't allow it to be written. |
| 62253 | */ |
| 62254 | goto fail_not_configurable; |
| 62255 | } |
| 62256 | |
| 62257 | /* steps 3.h and 3.i */ |
| 62258 | if (has_writable && !is_writable) { |
| 62259 | DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect" )); |
| 62260 | is_writable = 1; |
| 62261 | pending_write_protect = 1; |
| 62262 | } |
| 62263 | |
| 62264 | /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */ |
| 62265 | } else if (arr_idx != DUK__NO_ARRAY_INDEX) { |
| 62266 | /* XXX: any chance of unifying this with the 'length' key handling? */ |
| 62267 | |
| 62268 | /* E5 Section 15.4.5.1, step 4 */ |
| 62269 | duk_uint32_t old_len; |
| 62270 | duk_harray *a; |
| 62271 | |
| 62272 | a = (duk_harray *) obj; |
| 62273 | DUK_HARRAY_ASSERT_VALID(a); |
| 62274 | |
| 62275 | old_len = a->length; |
| 62276 | |
| 62277 | if (arr_idx >= old_len) { |
| 62278 | DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update " |
| 62279 | "(arr_idx=%ld, old_len=%ld)" , |
| 62280 | (long) arr_idx, (long) old_len)); |
| 62281 | |
| 62282 | if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) { |
| 62283 | /* Array .length is always non-configurable, so |
| 62284 | * if it's also non-writable, don't allow a value |
| 62285 | * write. With force flag allow writing. |
| 62286 | */ |
| 62287 | goto fail_not_configurable; |
| 62288 | } |
| 62289 | |
| 62290 | /* actual update happens once write has been completed without |
| 62291 | * error below. |
| 62292 | */ |
| 62293 | DUK_ASSERT(arr_idx != 0xffffffffUL); |
| 62294 | arridx_new_array_length = arr_idx + 1; |
| 62295 | } else { |
| 62296 | DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update " |
| 62297 | "(arr_idx=%ld, old_len=%ld) -> standard behavior" , |
| 62298 | (long) arr_idx, (long) old_len)); |
| 62299 | } |
| 62300 | } |
| 62301 | skip_array_exotic: |
| 62302 | |
| 62303 | /* XXX: There is currently no support for writing buffer object |
| 62304 | * indexed elements here. Attempt to do so will succeed and |
| 62305 | * write a concrete property into the buffer object. This should |
| 62306 | * be fixed at some point but because buffers are a custom feature |
| 62307 | * anyway, this is relatively unimportant. |
| 62308 | */ |
| 62309 | |
| 62310 | /* |
| 62311 | * Actual Object.defineProperty() default algorithm. |
| 62312 | */ |
| 62313 | |
| 62314 | /* |
| 62315 | * First check whether property exists; if not, simple case. This covers |
| 62316 | * steps 1-4. |
| 62317 | */ |
| 62318 | |
| 62319 | if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) { |
| 62320 | DUK_DDD(DUK_DDDPRINT("property does not exist" )); |
| 62321 | |
| 62322 | if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) { |
| 62323 | goto fail_not_extensible; |
| 62324 | } |
| 62325 | |
| 62326 | #if defined(DUK_USE_ROM_OBJECTS) |
| 62327 | /* ROM objects are never extensible but force flag may |
| 62328 | * allow us to come here anyway. |
| 62329 | */ |
| 62330 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj) || !DUK_HOBJECT_HAS_EXTENSIBLE(obj)); |
| 62331 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { |
| 62332 | DUK_D(DUK_DPRINT("attempt to define property on a read-only target object" )); |
| 62333 | goto fail_not_configurable; |
| 62334 | } |
| 62335 | #endif |
| 62336 | |
| 62337 | /* XXX: share final setting code for value and flags? difficult because |
| 62338 | * refcount code is different. Share entry allocation? But can't allocate |
| 62339 | * until array index checked. |
| 62340 | */ |
| 62341 | |
| 62342 | /* steps 4.a and 4.b are tricky */ |
| 62343 | if (has_set || has_get) { |
| 62344 | duk_int_t e_idx; |
| 62345 | |
| 62346 | DUK_DDD(DUK_DDDPRINT("create new accessor property" )); |
| 62347 | |
| 62348 | DUK_ASSERT(has_set || set == NULL); |
| 62349 | DUK_ASSERT(has_get || get == NULL); |
| 62350 | DUK_ASSERT(!has_value); |
| 62351 | DUK_ASSERT(!has_writable); |
| 62352 | |
| 62353 | new_flags = DUK_PROPDESC_FLAG_ACCESSOR; /* defaults, E5 Section 8.6.1, Table 7 */ |
| 62354 | if (has_enumerable && is_enumerable) { |
| 62355 | new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE; |
| 62356 | } |
| 62357 | if (has_configurable && is_configurable) { |
| 62358 | new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 62359 | } |
| 62360 | |
| 62361 | if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) { |
| 62362 | DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array" )); |
| 62363 | duk__abandon_array_part(thr, obj); |
| 62364 | } |
| 62365 | |
| 62366 | /* write to entry part */ |
| 62367 | e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); |
| 62368 | DUK_ASSERT(e_idx >= 0); |
| 62369 | |
| 62370 | DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get); |
| 62371 | DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set); |
| 62372 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, get); |
| 62373 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, set); |
| 62374 | |
| 62375 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags); |
| 62376 | goto success_exotics; |
| 62377 | } else { |
| 62378 | duk_int_t e_idx; |
| 62379 | duk_tval *tv2; |
| 62380 | |
| 62381 | DUK_DDD(DUK_DDDPRINT("create new data property" )); |
| 62382 | |
| 62383 | DUK_ASSERT(!has_set); |
| 62384 | DUK_ASSERT(!has_get); |
| 62385 | |
| 62386 | new_flags = 0; /* defaults, E5 Section 8.6.1, Table 7 */ |
| 62387 | if (has_writable && is_writable) { |
| 62388 | new_flags |= DUK_PROPDESC_FLAG_WRITABLE; |
| 62389 | } |
| 62390 | if (has_enumerable && is_enumerable) { |
| 62391 | new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE; |
| 62392 | } |
| 62393 | if (has_configurable && is_configurable) { |
| 62394 | new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 62395 | } |
| 62396 | if (has_value) { |
| 62397 | duk_tval *tv_tmp = duk_require_tval(thr, idx_value); |
| 62398 | DUK_TVAL_SET_TVAL(&tv, tv_tmp); |
| 62399 | } else { |
| 62400 | DUK_TVAL_SET_UNDEFINED(&tv); /* default value */ |
| 62401 | } |
| 62402 | |
| 62403 | if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) { |
| 62404 | if (new_flags == DUK_PROPDESC_FLAGS_WEC) { |
| 62405 | DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part" )); |
| 62406 | tv2 = duk__obtain_arridx_slot(thr, arr_idx, obj); |
| 62407 | if (tv2 == NULL) { |
| 62408 | DUK_DDD(DUK_DDDPRINT("failed writing to array part, abandoned array" )); |
| 62409 | } else { |
| 62410 | DUK_DDD(DUK_DDDPRINT("success in writing to array part" )); |
| 62411 | DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(obj)); |
| 62412 | DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv2)); |
| 62413 | DUK_TVAL_SET_TVAL(tv2, &tv); |
| 62414 | DUK_TVAL_INCREF(thr, tv2); |
| 62415 | goto success_exotics; |
| 62416 | } |
| 62417 | } else { |
| 62418 | DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array" )); |
| 62419 | duk__abandon_array_part(thr, obj); |
| 62420 | } |
| 62421 | /* fall through */ |
| 62422 | } |
| 62423 | |
| 62424 | /* write to entry part */ |
| 62425 | e_idx = duk__hobject_alloc_entry_checked(thr, obj, key); |
| 62426 | DUK_ASSERT(e_idx >= 0); |
| 62427 | tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx); |
| 62428 | DUK_TVAL_SET_TVAL(tv2, &tv); |
| 62429 | DUK_TVAL_INCREF(thr, tv2); |
| 62430 | |
| 62431 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags); |
| 62432 | goto success_exotics; |
| 62433 | } |
| 62434 | DUK_UNREACHABLE(); |
| 62435 | } |
| 62436 | |
| 62437 | /* we currently assume virtual properties are not configurable (as none of them are) */ |
| 62438 | DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)); |
| 62439 | |
| 62440 | /* [obj key desc value get set curr_value] */ |
| 62441 | |
| 62442 | /* |
| 62443 | * Property already exists. Steps 5-6 detect whether any changes need |
| 62444 | * to be made. |
| 62445 | */ |
| 62446 | |
| 62447 | if (has_enumerable) { |
| 62448 | if (is_enumerable) { |
| 62449 | if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) { |
| 62450 | goto need_check; |
| 62451 | } |
| 62452 | } else { |
| 62453 | if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) { |
| 62454 | goto need_check; |
| 62455 | } |
| 62456 | } |
| 62457 | } |
| 62458 | if (has_configurable) { |
| 62459 | if (is_configurable) { |
| 62460 | if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) { |
| 62461 | goto need_check; |
| 62462 | } |
| 62463 | } else { |
| 62464 | if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) { |
| 62465 | goto need_check; |
| 62466 | } |
| 62467 | } |
| 62468 | } |
| 62469 | if (has_value) { |
| 62470 | duk_tval *tmp1; |
| 62471 | duk_tval *tmp2; |
| 62472 | |
| 62473 | /* attempt to change from accessor to data property */ |
| 62474 | if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 62475 | goto need_check; |
| 62476 | } |
| 62477 | |
| 62478 | tmp1 = duk_require_tval(thr, -1); /* curr value */ |
| 62479 | tmp2 = duk_require_tval(thr, idx_value); /* new value */ |
| 62480 | if (!duk_js_samevalue(tmp1, tmp2)) { |
| 62481 | goto need_check; |
| 62482 | } |
| 62483 | } |
| 62484 | if (has_writable) { |
| 62485 | /* attempt to change from accessor to data property */ |
| 62486 | if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 62487 | goto need_check; |
| 62488 | } |
| 62489 | |
| 62490 | if (is_writable) { |
| 62491 | if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) { |
| 62492 | goto need_check; |
| 62493 | } |
| 62494 | } else { |
| 62495 | if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) { |
| 62496 | goto need_check; |
| 62497 | } |
| 62498 | } |
| 62499 | } |
| 62500 | if (has_set) { |
| 62501 | if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 62502 | if (set != curr.set) { |
| 62503 | goto need_check; |
| 62504 | } |
| 62505 | } else { |
| 62506 | goto need_check; |
| 62507 | } |
| 62508 | } |
| 62509 | if (has_get) { |
| 62510 | if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 62511 | if (get != curr.get) { |
| 62512 | goto need_check; |
| 62513 | } |
| 62514 | } else { |
| 62515 | goto need_check; |
| 62516 | } |
| 62517 | } |
| 62518 | |
| 62519 | /* property exists, either 'desc' is empty, or all values |
| 62520 | * match (SameValue) |
| 62521 | */ |
| 62522 | goto success_no_exotics; |
| 62523 | |
| 62524 | need_check: |
| 62525 | |
| 62526 | /* |
| 62527 | * Some change(s) need to be made. Steps 7-11. |
| 62528 | */ |
| 62529 | |
| 62530 | /* shared checks for all descriptor types */ |
| 62531 | if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { |
| 62532 | if (has_configurable && is_configurable) { |
| 62533 | goto fail_not_configurable; |
| 62534 | } |
| 62535 | if (has_enumerable) { |
| 62536 | if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) { |
| 62537 | if (!is_enumerable) { |
| 62538 | goto fail_not_configurable; |
| 62539 | } |
| 62540 | } else { |
| 62541 | if (is_enumerable) { |
| 62542 | goto fail_not_configurable; |
| 62543 | } |
| 62544 | } |
| 62545 | } |
| 62546 | } |
| 62547 | |
| 62548 | /* Virtual properties don't have backing so they can't mostly be |
| 62549 | * edited. Some virtual properties are, however, writable: for |
| 62550 | * example, virtual index properties of buffer objects and Array |
| 62551 | * instance .length. These are not configurable so the checks |
| 62552 | * above mostly cover attempts to change them, except when the |
| 62553 | * duk_def_prop() call is used with DUK_DEFPROP_FORCE; even in |
| 62554 | * that case we can't forcibly change the property attributes |
| 62555 | * because they don't have concrete backing. |
| 62556 | */ |
| 62557 | |
| 62558 | /* XXX: for ROM objects too it'd be best if value modify was |
| 62559 | * allowed if the value matches SameValue. |
| 62560 | */ |
| 62561 | /* Reject attempt to change a read-only object. */ |
| 62562 | #if defined(DUK_USE_ROM_OBJECTS) |
| 62563 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { |
| 62564 | DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object" )); |
| 62565 | goto fail_not_configurable; |
| 62566 | } |
| 62567 | #endif |
| 62568 | |
| 62569 | /* descriptor type specific checks */ |
| 62570 | if (has_set || has_get) { |
| 62571 | /* IsAccessorDescriptor(desc) == true */ |
| 62572 | DUK_ASSERT(!has_writable); |
| 62573 | DUK_ASSERT(!has_value); |
| 62574 | |
| 62575 | if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 62576 | /* curr and desc are accessors */ |
| 62577 | if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { |
| 62578 | if (has_set && set != curr.set) { |
| 62579 | goto fail_not_configurable; |
| 62580 | } |
| 62581 | if (has_get && get != curr.get) { |
| 62582 | goto fail_not_configurable; |
| 62583 | } |
| 62584 | } |
| 62585 | } else { |
| 62586 | duk_bool_t rc; |
| 62587 | duk_tval *tv1; |
| 62588 | |
| 62589 | /* curr is data, desc is accessor */ |
| 62590 | if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { |
| 62591 | goto fail_not_configurable; |
| 62592 | } |
| 62593 | |
| 62594 | DUK_DDD(DUK_DDDPRINT("convert property to accessor property" )); |
| 62595 | if (curr.a_idx >= 0) { |
| 62596 | DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup" )); |
| 62597 | duk__abandon_array_part(thr, obj); |
| 62598 | duk_pop_unsafe(thr); /* remove old value */ |
| 62599 | rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE); |
| 62600 | DUK_UNREF(rc); |
| 62601 | DUK_ASSERT(rc != 0); |
| 62602 | DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0); |
| 62603 | } |
| 62604 | if (curr.e_idx < 0) { |
| 62605 | DUK_ASSERT(curr.a_idx < 0 && curr.e_idx < 0); |
| 62606 | goto fail_virtual; /* safeguard for virtual property */ |
| 62607 | } |
| 62608 | |
| 62609 | DUK_ASSERT(curr.e_idx >= 0); |
| 62610 | DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); |
| 62611 | |
| 62612 | tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx); |
| 62613 | DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv1); /* XXX: just decref */ |
| 62614 | |
| 62615 | DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL); |
| 62616 | DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL); |
| 62617 | DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx); |
| 62618 | DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx); |
| 62619 | |
| 62620 | DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx" , |
| 62621 | (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx))); |
| 62622 | /* Update curr.flags; faster than a re-lookup. */ |
| 62623 | curr.flags &= ~DUK_PROPDESC_FLAG_WRITABLE; |
| 62624 | curr.flags |= DUK_PROPDESC_FLAG_ACCESSOR; |
| 62625 | } |
| 62626 | } else if (has_value || has_writable) { |
| 62627 | /* IsDataDescriptor(desc) == true */ |
| 62628 | DUK_ASSERT(!has_set); |
| 62629 | DUK_ASSERT(!has_get); |
| 62630 | |
| 62631 | if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 62632 | duk_hobject *tmp; |
| 62633 | |
| 62634 | /* curr is accessor, desc is data */ |
| 62635 | if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { |
| 62636 | goto fail_not_configurable; |
| 62637 | } |
| 62638 | |
| 62639 | /* curr is accessor -> cannot be in array part. */ |
| 62640 | DUK_ASSERT(curr.a_idx < 0); |
| 62641 | if (curr.e_idx < 0) { |
| 62642 | goto fail_virtual; /* safeguard; no virtual accessors now */ |
| 62643 | } |
| 62644 | |
| 62645 | DUK_DDD(DUK_DDDPRINT("convert property to data property" )); |
| 62646 | |
| 62647 | DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); |
| 62648 | tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx); |
| 62649 | DUK_UNREF(tmp); |
| 62650 | DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL); |
| 62651 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); |
| 62652 | tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx); |
| 62653 | DUK_UNREF(tmp); |
| 62654 | DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL); |
| 62655 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); |
| 62656 | |
| 62657 | DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx)); |
| 62658 | DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx); |
| 62659 | DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx); |
| 62660 | |
| 62661 | DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx" , |
| 62662 | (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx))); |
| 62663 | |
| 62664 | /* Update curr.flags; faster than a re-lookup. */ |
| 62665 | curr.flags &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ACCESSOR); |
| 62666 | } else { |
| 62667 | /* curr and desc are data */ |
| 62668 | if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) { |
| 62669 | if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) { |
| 62670 | goto fail_not_configurable; |
| 62671 | } |
| 62672 | /* Note: changing from writable to non-writable is OK */ |
| 62673 | if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) { |
| 62674 | duk_tval *tmp1 = duk_require_tval(thr, -1); /* curr value */ |
| 62675 | duk_tval *tmp2 = duk_require_tval(thr, idx_value); /* new value */ |
| 62676 | if (!duk_js_samevalue(tmp1, tmp2)) { |
| 62677 | goto fail_not_configurable; |
| 62678 | } |
| 62679 | } |
| 62680 | } |
| 62681 | } |
| 62682 | } else { |
| 62683 | /* IsGenericDescriptor(desc) == true; this means in practice that 'desc' |
| 62684 | * only has [[Enumerable]] or [[Configurable]] flag updates, which are |
| 62685 | * allowed at this point. |
| 62686 | */ |
| 62687 | |
| 62688 | DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set); |
| 62689 | } |
| 62690 | |
| 62691 | /* |
| 62692 | * Start doing property attributes updates. Steps 12-13. |
| 62693 | * |
| 62694 | * Start by computing new attribute flags without writing yet. |
| 62695 | * Property type conversion is done above if necessary. |
| 62696 | */ |
| 62697 | |
| 62698 | new_flags = curr.flags; |
| 62699 | |
| 62700 | if (has_enumerable) { |
| 62701 | if (is_enumerable) { |
| 62702 | new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE; |
| 62703 | } else { |
| 62704 | new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE; |
| 62705 | } |
| 62706 | } |
| 62707 | if (has_configurable) { |
| 62708 | if (is_configurable) { |
| 62709 | new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 62710 | } else { |
| 62711 | new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 62712 | } |
| 62713 | } |
| 62714 | if (has_writable) { |
| 62715 | if (is_writable) { |
| 62716 | new_flags |= DUK_PROPDESC_FLAG_WRITABLE; |
| 62717 | } else { |
| 62718 | new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE; |
| 62719 | } |
| 62720 | } |
| 62721 | |
| 62722 | /* XXX: write protect after flag? -> any chance of handling it here? */ |
| 62723 | |
| 62724 | DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx" , |
| 62725 | (unsigned long) new_flags)); |
| 62726 | |
| 62727 | /* |
| 62728 | * Check whether we need to abandon an array part (if it exists) |
| 62729 | */ |
| 62730 | |
| 62731 | if (curr.a_idx >= 0) { |
| 62732 | duk_bool_t rc; |
| 62733 | |
| 62734 | DUK_ASSERT(curr.e_idx < 0); |
| 62735 | |
| 62736 | if (new_flags == DUK_PROPDESC_FLAGS_WEC) { |
| 62737 | duk_tval *tv1, *tv2; |
| 62738 | |
| 62739 | DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place" )); |
| 62740 | |
| 62741 | DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */ |
| 62742 | DUK_ASSERT(!has_set); |
| 62743 | DUK_ASSERT(!has_get); |
| 62744 | DUK_ASSERT(idx_value >= 0); /* must be: if attributes match and we get here the value must differ (otherwise no change) */ |
| 62745 | |
| 62746 | tv2 = duk_require_tval(thr, idx_value); |
| 62747 | tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx); |
| 62748 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate a_idx */ |
| 62749 | goto success_exotics; |
| 62750 | } |
| 62751 | |
| 62752 | DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup" )); |
| 62753 | duk__abandon_array_part(thr, obj); |
| 62754 | duk_pop_unsafe(thr); /* remove old value */ |
| 62755 | rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE); |
| 62756 | DUK_UNREF(rc); |
| 62757 | DUK_ASSERT(rc != 0); |
| 62758 | DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0); |
| 62759 | } |
| 62760 | |
| 62761 | DUK_DDD(DUK_DDDPRINT("updating existing property in entry part" )); |
| 62762 | |
| 62763 | /* Array case is handled comprehensively above: either in entry |
| 62764 | * part or a virtual property. |
| 62765 | */ |
| 62766 | DUK_ASSERT(curr.a_idx < 0); |
| 62767 | |
| 62768 | DUK_DDD(DUK_DDDPRINT("update existing property attributes" )); |
| 62769 | if (curr.e_idx >= 0) { |
| 62770 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags); |
| 62771 | } else { |
| 62772 | /* For Array .length the only allowed transition is for .length |
| 62773 | * to become non-writable. |
| 62774 | */ |
| 62775 | if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { |
| 62776 | duk_harray *a; |
| 62777 | a = (duk_harray *) obj; |
| 62778 | DUK_DD(DUK_DDPRINT("Object.defineProperty() attribute update for duk_harray .length -> %02lx" , (unsigned long) new_flags)); |
| 62779 | DUK_HARRAY_ASSERT_VALID(a); |
| 62780 | if ((new_flags & DUK_PROPDESC_FLAGS_EC) != (curr.flags & DUK_PROPDESC_FLAGS_EC)) { |
| 62781 | DUK_D(DUK_DPRINT("Object.defineProperty() attempt to change virtual array .length enumerable or configurable attribute, fail" )); |
| 62782 | goto fail_virtual; |
| 62783 | } |
| 62784 | if (new_flags & DUK_PROPDESC_FLAG_WRITABLE) { |
| 62785 | DUK_HARRAY_SET_LENGTH_WRITABLE(a); |
| 62786 | } else { |
| 62787 | DUK_HARRAY_SET_LENGTH_NONWRITABLE(a); |
| 62788 | } |
| 62789 | } |
| 62790 | } |
| 62791 | |
| 62792 | if (has_set) { |
| 62793 | duk_hobject *tmp; |
| 62794 | |
| 62795 | /* Virtual properties are non-configurable but with a 'force' |
| 62796 | * flag we might come here so check explicitly for virtual. |
| 62797 | */ |
| 62798 | if (curr.e_idx < 0) { |
| 62799 | goto fail_virtual; |
| 62800 | } |
| 62801 | |
| 62802 | DUK_DDD(DUK_DDDPRINT("update existing property setter" )); |
| 62803 | DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); |
| 62804 | |
| 62805 | tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx); |
| 62806 | DUK_UNREF(tmp); |
| 62807 | DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set); |
| 62808 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, set); |
| 62809 | DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */ |
| 62810 | } |
| 62811 | if (has_get) { |
| 62812 | duk_hobject *tmp; |
| 62813 | |
| 62814 | if (curr.e_idx < 0) { |
| 62815 | goto fail_virtual; |
| 62816 | } |
| 62817 | |
| 62818 | DUK_DDD(DUK_DDDPRINT("update existing property getter" )); |
| 62819 | DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); |
| 62820 | |
| 62821 | tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx); |
| 62822 | DUK_UNREF(tmp); |
| 62823 | DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get); |
| 62824 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, get); |
| 62825 | DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */ |
| 62826 | } |
| 62827 | if (has_value) { |
| 62828 | duk_tval *tv1, *tv2; |
| 62829 | |
| 62830 | DUK_DDD(DUK_DDDPRINT("update existing property value" )); |
| 62831 | |
| 62832 | if (curr.e_idx >= 0) { |
| 62833 | DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx)); |
| 62834 | tv2 = duk_require_tval(thr, idx_value); |
| 62835 | tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx); |
| 62836 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate e_idx */ |
| 62837 | } else { |
| 62838 | DUK_ASSERT(curr.a_idx < 0); /* array part case handled comprehensively previously */ |
| 62839 | |
| 62840 | DUK_DD(DUK_DDPRINT("Object.defineProperty(), value update for virtual property" )); |
| 62841 | /* XXX: Uint8Array and other typed array virtual writes not currently |
| 62842 | * handled. |
| 62843 | */ |
| 62844 | if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { |
| 62845 | duk_harray *a; |
| 62846 | a = (duk_harray *) obj; |
| 62847 | DUK_DD(DUK_DDPRINT("Object.defineProperty() value update for duk_harray .length -> %ld" , (long) arrlen_new_len)); |
| 62848 | DUK_HARRAY_ASSERT_VALID(a); |
| 62849 | a->length = arrlen_new_len; |
| 62850 | } else { |
| 62851 | goto fail_virtual; /* should not happen */ |
| 62852 | } |
| 62853 | } |
| 62854 | } |
| 62855 | |
| 62856 | /* |
| 62857 | * Standard algorithm succeeded without errors, check for exotic post-behaviors. |
| 62858 | * |
| 62859 | * Arguments exotic behavior in E5 Section 10.6 occurs after the standard |
| 62860 | * [[DefineOwnProperty]] has completed successfully. |
| 62861 | * |
| 62862 | * Array exotic behavior in E5 Section 15.4.5.1 is implemented partly |
| 62863 | * prior to the default [[DefineOwnProperty]], but: |
| 62864 | * - for an array index key (e.g. "10") the final 'length' update occurs here |
| 62865 | * - for 'length' key the element deletion and 'length' update occurs here |
| 62866 | */ |
| 62867 | |
| 62868 | success_exotics: |
| 62869 | |
| 62870 | /* curr.a_idx or curr.e_idx may have been invalidated by side effects |
| 62871 | * above. |
| 62872 | */ |
| 62873 | |
| 62874 | /* [obj key desc value get set curr_value] */ |
| 62875 | |
| 62876 | if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) { |
| 62877 | duk_harray *a; |
| 62878 | |
| 62879 | a = (duk_harray *) obj; |
| 62880 | DUK_HARRAY_ASSERT_VALID(a); |
| 62881 | |
| 62882 | if (arridx_new_array_length > 0) { |
| 62883 | /* |
| 62884 | * Note: zero works as a "no update" marker because the new length |
| 62885 | * can never be zero after a new property is written. |
| 62886 | */ |
| 62887 | |
| 62888 | /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */ |
| 62889 | |
| 62890 | DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld" , |
| 62891 | (long) arridx_new_array_length)); |
| 62892 | |
| 62893 | a->length = arridx_new_array_length; |
| 62894 | } |
| 62895 | |
| 62896 | if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) { |
| 62897 | /* |
| 62898 | * E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines |
| 62899 | * the error case 3.l.iii and the success case 3.m-3.n. |
| 62900 | */ |
| 62901 | |
| 62902 | /* XXX: investigate whether write protect can be handled above, if we |
| 62903 | * just update length here while ignoring its protected status |
| 62904 | */ |
| 62905 | |
| 62906 | duk_uint32_t result_len; |
| 62907 | duk_bool_t rc; |
| 62908 | |
| 62909 | DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, " |
| 62910 | "doing array element deletion and length update" )); |
| 62911 | |
| 62912 | rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len); |
| 62913 | |
| 62914 | /* update length (curr points to length, and we assume it's still valid) */ |
| 62915 | DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len); |
| 62916 | |
| 62917 | a->length = result_len; |
| 62918 | |
| 62919 | if (pending_write_protect) { |
| 62920 | DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)" )); |
| 62921 | DUK_HARRAY_SET_LENGTH_NONWRITABLE(a); |
| 62922 | } |
| 62923 | |
| 62924 | /* XXX: shrink array allocation or entries compaction here? */ |
| 62925 | if (!rc) { |
| 62926 | DUK_DD(DUK_DDPRINT("array length write only partially successful" )); |
| 62927 | goto fail_not_configurable; |
| 62928 | } |
| 62929 | } |
| 62930 | } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) { |
| 62931 | duk_hobject *map; |
| 62932 | duk_hobject *varenv; |
| 62933 | |
| 62934 | DUK_ASSERT(arridx_new_array_length == 0); |
| 62935 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); /* traits are separate; in particular, arguments not an array */ |
| 62936 | |
| 62937 | map = NULL; |
| 62938 | varenv = NULL; |
| 62939 | if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) { |
| 62940 | goto success_no_exotics; |
| 62941 | } |
| 62942 | DUK_ASSERT(map != NULL); |
| 62943 | DUK_ASSERT(varenv != NULL); |
| 62944 | |
| 62945 | /* [obj key desc value get set curr_value varname] */ |
| 62946 | |
| 62947 | if (has_set || has_get) { |
| 62948 | /* = IsAccessorDescriptor(Desc) */ |
| 62949 | DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' " |
| 62950 | "changed to an accessor, delete arguments binding" )); |
| 62951 | |
| 62952 | (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */ |
| 62953 | } else { |
| 62954 | /* Note: this order matters (final value before deleting map entry must be done) */ |
| 62955 | DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', " |
| 62956 | "check for value update / binding deletion" )); |
| 62957 | |
| 62958 | if (has_value) { |
| 62959 | duk_hstring *varname; |
| 62960 | |
| 62961 | DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', " |
| 62962 | "update bound value (variable/argument)" )); |
| 62963 | |
| 62964 | varname = duk_require_hstring(thr, -1); |
| 62965 | DUK_ASSERT(varname != NULL); |
| 62966 | |
| 62967 | DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; " |
| 62968 | "key=%!O, varname=%!O, value=%!T" , |
| 62969 | (duk_heaphdr *) key, |
| 62970 | (duk_heaphdr *) varname, |
| 62971 | (duk_tval *) duk_require_tval(thr, idx_value))); |
| 62972 | |
| 62973 | /* strict flag for putvar comes from our caller (currently: fixed) */ |
| 62974 | duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, idx_value), 1 /*throw_flag*/); |
| 62975 | } |
| 62976 | if (has_writable && !is_writable) { |
| 62977 | DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', " |
| 62978 | "changed to non-writable, delete arguments binding" )); |
| 62979 | |
| 62980 | (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */ |
| 62981 | } |
| 62982 | } |
| 62983 | |
| 62984 | /* 'varname' is in stack in this else branch, leaving an unbalanced stack below, |
| 62985 | * but this doesn't matter now. |
| 62986 | */ |
| 62987 | } |
| 62988 | |
| 62989 | success_no_exotics: |
| 62990 | /* Some code paths use NORZ macros for simplicity, ensure refzero |
| 62991 | * handling is completed. |
| 62992 | */ |
| 62993 | DUK_REFZERO_CHECK_SLOW(thr); |
| 62994 | return 1; |
| 62995 | |
| 62996 | fail_not_extensible: |
| 62997 | if (throw_flag) { |
| 62998 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE); |
| 62999 | DUK_WO_NORETURN(return 0;); |
| 63000 | } |
| 63001 | return 0; |
| 63002 | |
| 63003 | fail_virtual: /* just use the same "not configurable" error message" */ |
| 63004 | fail_not_configurable: |
| 63005 | if (throw_flag) { |
| 63006 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); |
| 63007 | DUK_WO_NORETURN(return 0;); |
| 63008 | } |
| 63009 | return 0; |
| 63010 | } |
| 63011 | |
| 63012 | /* |
| 63013 | * Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable(). |
| 63014 | */ |
| 63015 | |
| 63016 | DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags) { |
| 63017 | duk_hstring *h_v; |
| 63018 | duk_hobject *h_obj; |
| 63019 | duk_propdesc desc; |
| 63020 | duk_bool_t ret; |
| 63021 | |
| 63022 | /* coercion order matters */ |
| 63023 | h_v = duk_to_hstring_acceptsymbol(thr, 0); |
| 63024 | DUK_ASSERT(h_v != NULL); |
| 63025 | |
| 63026 | h_obj = duk_push_this_coercible_to_object(thr); |
| 63027 | DUK_ASSERT(h_obj != NULL); |
| 63028 | |
| 63029 | ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */ |
| 63030 | |
| 63031 | duk_push_boolean(thr, ret && ((desc.flags & required_desc_flags) == required_desc_flags)); |
| 63032 | return 1; |
| 63033 | } |
| 63034 | |
| 63035 | /* |
| 63036 | * Object.seal() and Object.freeze() (E5 Sections 15.2.3.8 and 15.2.3.9) |
| 63037 | * |
| 63038 | * Since the algorithms are similar, a helper provides both functions. |
| 63039 | * Freezing is essentially sealing + making plain properties non-writable. |
| 63040 | * |
| 63041 | * Note: virtual (non-concrete) properties which are non-configurable but |
| 63042 | * writable would pose some problems, but such properties do not currently |
| 63043 | * exist (all virtual properties are non-configurable and non-writable). |
| 63044 | * If they did exist, the non-configurability does NOT prevent them from |
| 63045 | * becoming non-writable. However, this change should be recorded somehow |
| 63046 | * so that it would turn up (e.g. when getting the property descriptor), |
| 63047 | * requiring some additional flags in the object. |
| 63048 | */ |
| 63049 | |
| 63050 | DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) { |
| 63051 | duk_uint_fast32_t i; |
| 63052 | |
| 63053 | DUK_ASSERT(thr != NULL); |
| 63054 | DUK_ASSERT(thr->heap != NULL); |
| 63055 | DUK_ASSERT(obj != NULL); |
| 63056 | |
| 63057 | DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); |
| 63058 | |
| 63059 | #if defined(DUK_USE_ROM_OBJECTS) |
| 63060 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) { |
| 63061 | DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject" )); |
| 63062 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); |
| 63063 | DUK_WO_NORETURN(return;); |
| 63064 | } |
| 63065 | #endif |
| 63066 | |
| 63067 | /* |
| 63068 | * Abandon array part because all properties must become non-configurable. |
| 63069 | * Note that this is now done regardless of whether this is always the case |
| 63070 | * (skips check, but performance problem if caller would do this many times |
| 63071 | * for the same object; not likely). |
| 63072 | */ |
| 63073 | |
| 63074 | duk__abandon_array_part(thr, obj); |
| 63075 | DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0); |
| 63076 | |
| 63077 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 63078 | duk_uint8_t *fp; |
| 63079 | |
| 63080 | /* since duk__abandon_array_part() causes a resize, there should be no gaps in keys */ |
| 63081 | DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL); |
| 63082 | |
| 63083 | /* avoid multiple computations of flags address; bypasses macros */ |
| 63084 | fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i); |
| 63085 | if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) { |
| 63086 | *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE); |
| 63087 | } else { |
| 63088 | *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 63089 | } |
| 63090 | } |
| 63091 | |
| 63092 | DUK_HOBJECT_CLEAR_EXTENSIBLE(obj); |
| 63093 | |
| 63094 | /* no need to compact since we already did that in duk__abandon_array_part() |
| 63095 | * (regardless of whether an array part existed or not. |
| 63096 | */ |
| 63097 | |
| 63098 | return; |
| 63099 | } |
| 63100 | |
| 63101 | /* |
| 63102 | * Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13) |
| 63103 | * |
| 63104 | * Since the algorithms are similar, a helper provides both functions. |
| 63105 | * Freezing is essentially sealing + making plain properties non-writable. |
| 63106 | * |
| 63107 | * Note: all virtual (non-concrete) properties are currently non-configurable |
| 63108 | * and non-writable (and there are no accessor virtual properties), so they don't |
| 63109 | * need to be considered here now. |
| 63110 | */ |
| 63111 | |
| 63112 | DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) { |
| 63113 | duk_uint_fast32_t i; |
| 63114 | |
| 63115 | DUK_ASSERT(obj != NULL); |
| 63116 | DUK_UNREF(thr); |
| 63117 | |
| 63118 | /* Note: no allocation pressure, no need to check refcounts etc */ |
| 63119 | |
| 63120 | /* must not be extensible */ |
| 63121 | if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) { |
| 63122 | return 0; |
| 63123 | } |
| 63124 | |
| 63125 | /* all virtual properties are non-configurable and non-writable */ |
| 63126 | |
| 63127 | /* entry part must not contain any configurable properties, or |
| 63128 | * writable properties (if is_frozen). |
| 63129 | */ |
| 63130 | for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) { |
| 63131 | duk_small_uint_t flags; |
| 63132 | |
| 63133 | if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) { |
| 63134 | continue; |
| 63135 | } |
| 63136 | |
| 63137 | /* avoid multiple computations of flags address; bypasses macros */ |
| 63138 | flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i); |
| 63139 | |
| 63140 | if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) { |
| 63141 | return 0; |
| 63142 | } |
| 63143 | if (is_frozen && |
| 63144 | !(flags & DUK_PROPDESC_FLAG_ACCESSOR) && |
| 63145 | (flags & DUK_PROPDESC_FLAG_WRITABLE)) { |
| 63146 | return 0; |
| 63147 | } |
| 63148 | } |
| 63149 | |
| 63150 | /* array part must not contain any non-unused properties, as they would |
| 63151 | * be configurable and writable. |
| 63152 | */ |
| 63153 | for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) { |
| 63154 | duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i); |
| 63155 | if (!DUK_TVAL_IS_UNUSED(tv)) { |
| 63156 | return 0; |
| 63157 | } |
| 63158 | } |
| 63159 | |
| 63160 | return 1; |
| 63161 | } |
| 63162 | |
| 63163 | /* |
| 63164 | * Object.preventExtensions() and Object.isExtensible() (E5 Sections 15.2.3.10, 15.2.3.13) |
| 63165 | * |
| 63166 | * Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE |
| 63167 | * and the Object built-in bindings. |
| 63168 | */ |
| 63169 | |
| 63170 | /* automatic undefs */ |
| 63171 | #undef DUK__HASH_DELETED |
| 63172 | #undef DUK__HASH_UNUSED |
| 63173 | #undef DUK__NO_ARRAY_INDEX |
| 63174 | #undef DUK__VALSTACK_PROXY_LOOKUP |
| 63175 | #undef DUK__VALSTACK_SPACE |
| 63176 | #line 1 "duk_hstring_assert.c" |
| 63177 | /* |
| 63178 | * duk_hstring assertion helpers. |
| 63179 | */ |
| 63180 | |
| 63181 | /* #include duk_internal.h -> already included */ |
| 63182 | |
| 63183 | #if defined(DUK_USE_ASSERTIONS) |
| 63184 | |
| 63185 | DUK_INTERNAL void duk_hstring_assert_valid(duk_hstring *h) { |
| 63186 | DUK_ASSERT(h != NULL); |
| 63187 | } |
| 63188 | |
| 63189 | #endif /* DUK_USE_ASSERTIONS */ |
| 63190 | #line 1 "duk_hstring_misc.c" |
| 63191 | /* |
| 63192 | * Misc support functions |
| 63193 | */ |
| 63194 | |
| 63195 | /* #include duk_internal.h -> already included */ |
| 63196 | |
| 63197 | /* |
| 63198 | * duk_hstring charCodeAt, with and without surrogate awareness |
| 63199 | */ |
| 63200 | |
| 63201 | DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos, duk_bool_t surrogate_aware) { |
| 63202 | duk_uint32_t boff; |
| 63203 | const duk_uint8_t *p, *p_start, *p_end; |
| 63204 | duk_ucodepoint_t cp1; |
| 63205 | duk_ucodepoint_t cp2; |
| 63206 | |
| 63207 | /* Caller must check character offset to be inside the string. */ |
| 63208 | DUK_ASSERT(thr != NULL); |
| 63209 | DUK_ASSERT(h != NULL); |
| 63210 | DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */ |
| 63211 | DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); |
| 63212 | |
| 63213 | boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos); |
| 63214 | DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O" , |
| 63215 | (long) pos, (long) boff, (duk_heaphdr *) h)); |
| 63216 | DUK_ASSERT_DISABLE(boff >= 0); |
| 63217 | DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h)); |
| 63218 | |
| 63219 | p_start = DUK_HSTRING_GET_DATA(h); |
| 63220 | p_end = p_start + DUK_HSTRING_GET_BYTELEN(h); |
| 63221 | p = p_start + boff; |
| 63222 | DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p" , |
| 63223 | (const void *) p_start, (const void *) p_end, |
| 63224 | (const void *) p)); |
| 63225 | |
| 63226 | /* For invalid UTF-8 (never happens for standard ECMAScript strings) |
| 63227 | * return U+FFFD replacement character. |
| 63228 | */ |
| 63229 | if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) { |
| 63230 | if (surrogate_aware && cp1 >= 0xd800UL && cp1 <= 0xdbffUL) { |
| 63231 | /* The decode helper is memory safe even if 'cp1' was |
| 63232 | * decoded at the end of the string and 'p' is no longer |
| 63233 | * within string memory range. |
| 63234 | */ |
| 63235 | cp2 = 0; /* If call fails, this is left untouched and won't match cp2 check. */ |
| 63236 | (void) duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp2); |
| 63237 | if (cp2 >= 0xdc00UL && cp2 <= 0xdfffUL) { |
| 63238 | cp1 = (duk_ucodepoint_t) (((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL); |
| 63239 | } |
| 63240 | } |
| 63241 | } else { |
| 63242 | cp1 = DUK_UNICODE_CP_REPLACEMENT_CHARACTER; |
| 63243 | } |
| 63244 | |
| 63245 | return cp1; |
| 63246 | } |
| 63247 | |
| 63248 | /* |
| 63249 | * duk_hstring charlen, when lazy charlen disabled |
| 63250 | */ |
| 63251 | |
| 63252 | #if !defined(DUK_USE_HSTRING_LAZY_CLEN) |
| 63253 | #if !defined(DUK_USE_HSTRING_CLEN) |
| 63254 | #error non-lazy duk_hstring charlen but DUK_USE_HSTRING_CLEN not set |
| 63255 | #endif |
| 63256 | DUK_INTERNAL void duk_hstring_init_charlen(duk_hstring *h) { |
| 63257 | duk_uint32_t clen; |
| 63258 | |
| 63259 | DUK_ASSERT(h != NULL); |
| 63260 | DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(h)); |
| 63261 | DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)); |
| 63262 | |
| 63263 | clen = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); |
| 63264 | #if defined(DUK_USE_STRLEN16) |
| 63265 | DUK_ASSERT(clen <= 0xffffUL); /* Bytelength checked during interning. */ |
| 63266 | h->clen16 = (duk_uint16_t) clen; |
| 63267 | #else |
| 63268 | h->clen = (duk_uint32_t) clen; |
| 63269 | #endif |
| 63270 | if (DUK_LIKELY(clen == DUK_HSTRING_GET_BYTELEN(h))) { |
| 63271 | DUK_HSTRING_SET_ASCII(h); |
| 63272 | } |
| 63273 | } |
| 63274 | |
| 63275 | DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { |
| 63276 | #if defined(DUK_USE_STRLEN16) |
| 63277 | return h->clen16; |
| 63278 | #else |
| 63279 | return h->clen; |
| 63280 | #endif |
| 63281 | } |
| 63282 | #endif /* !DUK_USE_HSTRING_LAZY_CLEN */ |
| 63283 | |
| 63284 | /* |
| 63285 | * duk_hstring charlen, when lazy charlen enabled |
| 63286 | */ |
| 63287 | |
| 63288 | #if defined(DUK_USE_HSTRING_LAZY_CLEN) |
| 63289 | #if defined(DUK_USE_HSTRING_CLEN) |
| 63290 | DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { |
| 63291 | duk_size_t res; |
| 63292 | |
| 63293 | DUK_ASSERT(h->clen == 0); /* Checked by caller. */ |
| 63294 | |
| 63295 | #if defined(DUK_USE_ROM_STRINGS) |
| 63296 | /* ROM strings have precomputed clen, but if the computed clen is zero |
| 63297 | * we can still come here and can't write anything. |
| 63298 | */ |
| 63299 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { |
| 63300 | return 0; |
| 63301 | } |
| 63302 | #endif |
| 63303 | |
| 63304 | res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); |
| 63305 | #if defined(DUK_USE_STRLEN16) |
| 63306 | DUK_ASSERT(res <= 0xffffUL); /* Bytelength checked during interning. */ |
| 63307 | h->clen16 = (duk_uint16_t) res; |
| 63308 | #else |
| 63309 | h->clen = (duk_uint32_t) res; |
| 63310 | #endif |
| 63311 | if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { |
| 63312 | DUK_HSTRING_SET_ASCII(h); |
| 63313 | } |
| 63314 | return res; |
| 63315 | } |
| 63316 | #else /* DUK_USE_HSTRING_CLEN */ |
| 63317 | DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) { |
| 63318 | if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) { |
| 63319 | /* Most practical strings will go here. */ |
| 63320 | return DUK_HSTRING_GET_BYTELEN(h); |
| 63321 | } else { |
| 63322 | /* ASCII flag is lazy, so set it here. */ |
| 63323 | duk_size_t res; |
| 63324 | |
| 63325 | /* XXX: here we could use the strcache to speed up the |
| 63326 | * computation (matters for 'i < str.length' loops). |
| 63327 | */ |
| 63328 | |
| 63329 | res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h)); |
| 63330 | |
| 63331 | #if defined(DUK_USE_ROM_STRINGS) |
| 63332 | if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { |
| 63333 | /* For ROM strings, can't write anything; ASCII flag |
| 63334 | * is preset so we don't need to update it. |
| 63335 | */ |
| 63336 | return res; |
| 63337 | } |
| 63338 | #endif |
| 63339 | if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) { |
| 63340 | DUK_HSTRING_SET_ASCII(h); |
| 63341 | } |
| 63342 | return res; |
| 63343 | } |
| 63344 | } |
| 63345 | #endif /* DUK_USE_HSTRING_CLEN */ |
| 63346 | |
| 63347 | #if defined(DUK_USE_HSTRING_CLEN) |
| 63348 | DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { |
| 63349 | #if defined(DUK_USE_STRLEN16) |
| 63350 | if (DUK_LIKELY(h->clen16 != 0)) { |
| 63351 | return h->clen16; |
| 63352 | } |
| 63353 | #else |
| 63354 | if (DUK_LIKELY(h->clen != 0)) { |
| 63355 | return h->clen; |
| 63356 | } |
| 63357 | #endif |
| 63358 | return duk__hstring_get_charlen_slowpath(h); |
| 63359 | } |
| 63360 | #else /* DUK_USE_HSTRING_CLEN */ |
| 63361 | DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) { |
| 63362 | /* Always use slow path. */ |
| 63363 | return duk__hstring_get_charlen_slowpath(h); |
| 63364 | } |
| 63365 | #endif /* DUK_USE_HSTRING_CLEN */ |
| 63366 | #endif /* DUK_USE_HSTRING_LAZY_CLEN */ |
| 63367 | |
| 63368 | /* |
| 63369 | * Compare duk_hstring to an ASCII cstring. |
| 63370 | */ |
| 63371 | |
| 63372 | DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr) { |
| 63373 | duk_size_t len; |
| 63374 | |
| 63375 | DUK_ASSERT(h != NULL); |
| 63376 | DUK_ASSERT(cstr != NULL); |
| 63377 | |
| 63378 | len = DUK_STRLEN(cstr); |
| 63379 | if (len != DUK_HSTRING_GET_BYTELEN(h)) { |
| 63380 | return 0; |
| 63381 | } |
| 63382 | if (duk_memcmp((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) { |
| 63383 | return 1; |
| 63384 | } |
| 63385 | return 0; |
| 63386 | } |
| 63387 | #line 1 "duk_hthread_alloc.c" |
| 63388 | /* |
| 63389 | * duk_hthread allocation and freeing. |
| 63390 | */ |
| 63391 | |
| 63392 | /* #include duk_internal.h -> already included */ |
| 63393 | |
| 63394 | /* |
| 63395 | * Allocate initial stacks for a thread. Note that 'thr' must be reachable |
| 63396 | * as a garbage collection may be triggered by the allocation attempts. |
| 63397 | * Returns zero (without leaking memory) if init fails. |
| 63398 | */ |
| 63399 | |
| 63400 | DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) { |
| 63401 | duk_size_t alloc_size; |
| 63402 | duk_size_t i; |
| 63403 | |
| 63404 | DUK_ASSERT(heap != NULL); |
| 63405 | DUK_ASSERT(thr != NULL); |
| 63406 | DUK_ASSERT(thr->valstack == NULL); |
| 63407 | DUK_ASSERT(thr->valstack_end == NULL); |
| 63408 | DUK_ASSERT(thr->valstack_alloc_end == NULL); |
| 63409 | DUK_ASSERT(thr->valstack_bottom == NULL); |
| 63410 | DUK_ASSERT(thr->valstack_top == NULL); |
| 63411 | DUK_ASSERT(thr->callstack_curr == NULL); |
| 63412 | |
| 63413 | /* valstack */ |
| 63414 | DUK_ASSERT(DUK_VALSTACK_API_ENTRY_MINIMUM <= DUK_VALSTACK_INITIAL_SIZE); |
| 63415 | alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE; |
| 63416 | thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size); |
| 63417 | if (!thr->valstack) { |
| 63418 | goto fail; |
| 63419 | } |
| 63420 | duk_memzero(thr->valstack, alloc_size); |
| 63421 | thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM; |
| 63422 | thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE; |
| 63423 | thr->valstack_bottom = thr->valstack; |
| 63424 | thr->valstack_top = thr->valstack; |
| 63425 | |
| 63426 | for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) { |
| 63427 | DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]); |
| 63428 | } |
| 63429 | |
| 63430 | return 1; |
| 63431 | |
| 63432 | fail: |
| 63433 | DUK_FREE(heap, thr->valstack); |
| 63434 | DUK_ASSERT(thr->callstack_curr == NULL); |
| 63435 | |
| 63436 | thr->valstack = NULL; |
| 63437 | return 0; |
| 63438 | } |
| 63439 | |
| 63440 | /* For indirect allocs. */ |
| 63441 | |
| 63442 | DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) { |
| 63443 | duk_hthread *thr = (duk_hthread *) ud; |
| 63444 | DUK_UNREF(heap); |
| 63445 | return (void *) thr->valstack; |
| 63446 | } |
| 63447 | #line 1 "duk_hthread_builtins.c" |
| 63448 | /* |
| 63449 | * Initialize built-in objects. Current thread must have a valstack |
| 63450 | * and initialization errors may longjmp, so a setjmp() catch point |
| 63451 | * must exist. |
| 63452 | */ |
| 63453 | |
| 63454 | /* #include duk_internal.h -> already included */ |
| 63455 | |
| 63456 | /* |
| 63457 | * Encoding constants, must match genbuiltins.py |
| 63458 | */ |
| 63459 | |
| 63460 | #define DUK__PROP_FLAGS_BITS 3 |
| 63461 | #define DUK__LENGTH_PROP_BITS 3 |
| 63462 | #define DUK__NARGS_BITS 3 |
| 63463 | #define DUK__PROP_TYPE_BITS 3 |
| 63464 | |
| 63465 | #define DUK__NARGS_VARARGS_MARKER 0x07 |
| 63466 | |
| 63467 | #define DUK__PROP_TYPE_DOUBLE 0 |
| 63468 | #define DUK__PROP_TYPE_STRING 1 |
| 63469 | #define DUK__PROP_TYPE_STRIDX 2 |
| 63470 | #define DUK__PROP_TYPE_BUILTIN 3 |
| 63471 | #define DUK__PROP_TYPE_UNDEFINED 4 |
| 63472 | #define DUK__PROP_TYPE_BOOLEAN_TRUE 5 |
| 63473 | #define DUK__PROP_TYPE_BOOLEAN_FALSE 6 |
| 63474 | #define DUK__PROP_TYPE_ACCESSOR 7 |
| 63475 | |
| 63476 | /* |
| 63477 | * Create built-in objects by parsing an init bitstream generated |
| 63478 | * by genbuiltins.py. |
| 63479 | */ |
| 63480 | |
| 63481 | #if defined(DUK_USE_ROM_OBJECTS) |
| 63482 | #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) |
| 63483 | DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { |
| 63484 | duk_hobject *h_global; |
| 63485 | #if defined(DUK_USE_ROM_GLOBAL_CLONE) |
| 63486 | duk_hobject *h_oldglobal; |
| 63487 | duk_uint8_t *props; |
| 63488 | duk_size_t alloc_size; |
| 63489 | #endif |
| 63490 | duk_hobject *h_objenv; |
| 63491 | |
| 63492 | /* XXX: refactor into internal helper, duk_clone_hobject() */ |
| 63493 | |
| 63494 | #if defined(DUK_USE_ROM_GLOBAL_INHERIT) |
| 63495 | /* Inherit from ROM-based global object: less RAM usage, less transparent. */ |
| 63496 | h_global = duk_push_object_helper(thr, |
| 63497 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 63498 | DUK_HOBJECT_FLAG_FASTREFS | |
| 63499 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), |
| 63500 | DUK_BIDX_GLOBAL); |
| 63501 | DUK_ASSERT(h_global != NULL); |
| 63502 | #elif defined(DUK_USE_ROM_GLOBAL_CLONE) |
| 63503 | /* Clone the properties of the ROM-based global object to create a |
| 63504 | * fully RAM-based global object. Uses more memory than the inherit |
| 63505 | * model but more compliant. |
| 63506 | */ |
| 63507 | h_global = duk_push_object_helper(thr, |
| 63508 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 63509 | DUK_HOBJECT_FLAG_FASTREFS | |
| 63510 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), |
| 63511 | DUK_BIDX_OBJECT_PROTOTYPE); |
| 63512 | DUK_ASSERT(h_global != NULL); |
| 63513 | h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL]; |
| 63514 | DUK_ASSERT(h_oldglobal != NULL); |
| 63515 | |
| 63516 | /* Copy the property table verbatim; this handles attributes etc. |
| 63517 | * For ROM objects it's not necessary (or possible) to update |
| 63518 | * refcounts so leave them as is. |
| 63519 | */ |
| 63520 | alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal); |
| 63521 | DUK_ASSERT(alloc_size > 0); |
| 63522 | props = DUK_ALLOC_CHECKED(thr, alloc_size); |
| 63523 | DUK_ASSERT(props != NULL); |
| 63524 | DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL); |
| 63525 | duk_memcpy((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size); |
| 63526 | |
| 63527 | /* XXX: keep property attributes or tweak them here? |
| 63528 | * Properties will now be non-configurable even when they're |
| 63529 | * normally configurable for the global object. |
| 63530 | */ |
| 63531 | |
| 63532 | DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL); |
| 63533 | DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props); |
| 63534 | DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal)); |
| 63535 | DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal)); |
| 63536 | DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal)); |
| 63537 | DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal)); |
| 63538 | #else |
| 63539 | #error internal error in config defines |
| 63540 | #endif |
| 63541 | |
| 63542 | duk_hobject_compact_props(thr, h_global); |
| 63543 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); |
| 63544 | DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref: ROM object */ |
| 63545 | thr->builtins[DUK_BIDX_GLOBAL] = h_global; |
| 63546 | DUK_HOBJECT_INCREF(thr, h_global); |
| 63547 | DUK_D(DUK_DPRINT("duplicated global object: %!O" , h_global)); |
| 63548 | |
| 63549 | /* Create a fresh object environment for the global scope. This is |
| 63550 | * needed so that the global scope points to the newly created RAM-based |
| 63551 | * global object. |
| 63552 | */ |
| 63553 | h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr, |
| 63554 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 63555 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); |
| 63556 | DUK_ASSERT(h_objenv != NULL); |
| 63557 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL); |
| 63558 | duk_push_hobject(thr, h_objenv); |
| 63559 | |
| 63560 | DUK_ASSERT(h_global != NULL); |
| 63561 | ((duk_hobjenv *) h_objenv)->target = h_global; |
| 63562 | DUK_HOBJECT_INCREF(thr, h_global); |
| 63563 | DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0); |
| 63564 | |
| 63565 | DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); |
| 63566 | DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref: ROM object */ |
| 63567 | thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv; |
| 63568 | DUK_HOBJECT_INCREF(thr, h_objenv); |
| 63569 | DUK_D(DUK_DPRINT("duplicated global env: %!O" , h_objenv)); |
| 63570 | |
| 63571 | DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) h_objenv); |
| 63572 | |
| 63573 | duk_pop_2(thr); /* Pop global object and global env. */ |
| 63574 | } |
| 63575 | #endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */ |
| 63576 | |
| 63577 | DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { |
| 63578 | /* Setup builtins from ROM objects. All heaps/threads will share |
| 63579 | * the same readonly objects. |
| 63580 | */ |
| 63581 | duk_small_uint_t i; |
| 63582 | |
| 63583 | for (i = 0; i < DUK_NUM_BUILTINS; i++) { |
| 63584 | duk_hobject *h; |
| 63585 | h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]); |
| 63586 | DUK_ASSERT(h != NULL); |
| 63587 | thr->builtins[i] = h; |
| 63588 | } |
| 63589 | |
| 63590 | #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT) |
| 63591 | /* By default the global object is read-only which is often much |
| 63592 | * more of an issue than having read-only built-in objects (like |
| 63593 | * RegExp, Date, etc). Use a RAM-based copy of the global object |
| 63594 | * and the global environment object for convenience. |
| 63595 | */ |
| 63596 | duk__duplicate_ram_global_object(thr); |
| 63597 | #endif |
| 63598 | } |
| 63599 | #else /* DUK_USE_ROM_OBJECTS */ |
| 63600 | DUK_LOCAL void duk__push_stridx(duk_hthread *thr, duk_bitdecoder_ctx *bd) { |
| 63601 | duk_small_uint_t n; |
| 63602 | |
| 63603 | n = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63604 | DUK_ASSERT_DISABLE(n >= 0); /* unsigned */ |
| 63605 | DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS); |
| 63606 | duk_push_hstring_stridx(thr, n); |
| 63607 | } |
| 63608 | DUK_LOCAL void duk__push_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) { |
| 63609 | /* XXX: built-ins data could provide a maximum length that is |
| 63610 | * actually needed; bitpacked max length is now 256 bytes. |
| 63611 | */ |
| 63612 | duk_uint8_t tmp[DUK_BD_BITPACKED_STRING_MAXLEN]; |
| 63613 | duk_small_uint_t len; |
| 63614 | |
| 63615 | len = duk_bd_decode_bitpacked_string(bd, tmp); |
| 63616 | duk_push_lstring(thr, (const char *) tmp, (duk_size_t) len); |
| 63617 | } |
| 63618 | DUK_LOCAL void duk__push_stridx_or_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) { |
| 63619 | duk_small_uint_t n; |
| 63620 | |
| 63621 | n = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63622 | if (n == 0) { |
| 63623 | duk__push_string(thr, bd); |
| 63624 | } else { |
| 63625 | n--; |
| 63626 | DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS); |
| 63627 | duk_push_hstring_stridx(thr, n); |
| 63628 | } |
| 63629 | } |
| 63630 | DUK_LOCAL void duk__push_double(duk_hthread *thr, duk_bitdecoder_ctx *bd) { |
| 63631 | duk_double_union du; |
| 63632 | duk_small_uint_t i; |
| 63633 | |
| 63634 | for (i = 0; i < 8; i++) { |
| 63635 | /* Encoding endianness must match target memory layout, |
| 63636 | * build scripts and genbuiltins.py must ensure this. |
| 63637 | */ |
| 63638 | du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8); |
| 63639 | } |
| 63640 | |
| 63641 | duk_push_number(thr, du.d); /* push operation normalizes NaNs */ |
| 63642 | } |
| 63643 | |
| 63644 | DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) { |
| 63645 | duk_bitdecoder_ctx bd_ctx; |
| 63646 | duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */ |
| 63647 | duk_hobject *h; |
| 63648 | duk_small_uint_t i, j; |
| 63649 | |
| 63650 | DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d" , (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS)); |
| 63651 | |
| 63652 | duk_memzero(&bd_ctx, sizeof(bd_ctx)); |
| 63653 | bd->data = (const duk_uint8_t *) duk_builtins_data; |
| 63654 | bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH; |
| 63655 | |
| 63656 | /* |
| 63657 | * First create all built-in bare objects on the empty valstack. |
| 63658 | * |
| 63659 | * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value |
| 63660 | * stack indices matching their eventual thr->builtins[] index. |
| 63661 | * |
| 63662 | * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS] |
| 63663 | * will exist on the value stack during init but won't be placed |
| 63664 | * into thr->builtins[]. These are objects referenced in some way |
| 63665 | * from thr->builtins[] roots but which don't need to be indexed by |
| 63666 | * Duktape through thr->builtins[] (e.g. user custom objects). |
| 63667 | * |
| 63668 | * Internal prototypes will be incorrect (NULL) at this stage. |
| 63669 | */ |
| 63670 | |
| 63671 | duk_require_stack(thr, DUK_NUM_ALL_BUILTINS); |
| 63672 | |
| 63673 | DUK_DD(DUK_DDPRINT("create empty built-ins" )); |
| 63674 | DUK_ASSERT_TOP(thr, 0); |
| 63675 | for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { |
| 63676 | duk_small_uint_t class_num; |
| 63677 | duk_small_int_t len = -1; /* must be signed */ |
| 63678 | |
| 63679 | class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63680 | len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/); |
| 63681 | |
| 63682 | if (class_num == DUK_HOBJECT_CLASS_FUNCTION) { |
| 63683 | duk_small_uint_t natidx; |
| 63684 | duk_small_int_t c_nargs; /* must hold DUK_VARARGS */ |
| 63685 | duk_c_function c_func; |
| 63686 | duk_int16_t magic; |
| 63687 | |
| 63688 | DUK_DDD(DUK_DDDPRINT("len=%ld" , (long) len)); |
| 63689 | DUK_ASSERT(len >= 0); |
| 63690 | |
| 63691 | natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63692 | DUK_ASSERT(natidx != 0); |
| 63693 | c_func = duk_bi_native_functions[natidx]; |
| 63694 | DUK_ASSERT(c_func != NULL); |
| 63695 | |
| 63696 | c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/); |
| 63697 | if (c_nargs == DUK__NARGS_VARARGS_MARKER) { |
| 63698 | c_nargs = DUK_VARARGS; |
| 63699 | } |
| 63700 | |
| 63701 | /* XXX: set magic directly here? (it could share the c_nargs arg) */ |
| 63702 | (void) duk_push_c_function_builtin(thr, c_func, c_nargs); |
| 63703 | h = duk_known_hobject(thr, -1); |
| 63704 | |
| 63705 | /* Currently all built-in native functions are strict. |
| 63706 | * duk_push_c_function() now sets strict flag, so |
| 63707 | * assert for it. |
| 63708 | */ |
| 63709 | DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h)); |
| 63710 | |
| 63711 | /* XXX: function properties */ |
| 63712 | |
| 63713 | duk__push_stridx_or_string(thr, bd); |
| 63714 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 63715 | duk_xdef_prop_stridx_short(thr, |
| 63716 | -2, |
| 63717 | DUK_STRIDX_NAME, |
| 63718 | DUK_PROPDESC_FLAGS_C); |
| 63719 | #else |
| 63720 | duk_pop(thr); /* Not very ideal but good enough for now. */ |
| 63721 | #endif |
| 63722 | |
| 63723 | /* Almost all global level Function objects are constructable |
| 63724 | * but not all: Function.prototype is a non-constructable, |
| 63725 | * callable Function. |
| 63726 | */ |
| 63727 | if (duk_bd_decode_flag(bd)) { |
| 63728 | DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h)); |
| 63729 | } else { |
| 63730 | DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h); |
| 63731 | } |
| 63732 | |
| 63733 | /* Cast converts magic to 16-bit signed value */ |
| 63734 | magic = (duk_int16_t) duk_bd_decode_varuint(bd); |
| 63735 | ((duk_hnatfunc *) h)->magic = magic; |
| 63736 | } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) { |
| 63737 | duk_push_array(thr); |
| 63738 | } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) { |
| 63739 | duk_hobjenv *env; |
| 63740 | duk_hobject *global; |
| 63741 | |
| 63742 | DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV); |
| 63743 | DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL); |
| 63744 | |
| 63745 | env = duk_hobjenv_alloc(thr, |
| 63746 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 63747 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); |
| 63748 | DUK_ASSERT(env->target == NULL); |
| 63749 | duk_push_hobject(thr, (duk_hobject *) env); |
| 63750 | |
| 63751 | global = duk_known_hobject(thr, DUK_BIDX_GLOBAL); |
| 63752 | DUK_ASSERT(global != NULL); |
| 63753 | env->target = global; |
| 63754 | DUK_HOBJECT_INCREF(thr, global); |
| 63755 | DUK_ASSERT(env->has_this == 0); |
| 63756 | |
| 63757 | DUK_HOBJENV_ASSERT_VALID(env); |
| 63758 | } else { |
| 63759 | DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV); |
| 63760 | |
| 63761 | (void) duk_push_object_helper(thr, |
| 63762 | DUK_HOBJECT_FLAG_FASTREFS | |
| 63763 | DUK_HOBJECT_FLAG_EXTENSIBLE, |
| 63764 | -1); /* no prototype or class yet */ |
| 63765 | |
| 63766 | } |
| 63767 | |
| 63768 | h = duk_known_hobject(thr, -1); |
| 63769 | DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num); |
| 63770 | |
| 63771 | if (i < DUK_NUM_BUILTINS) { |
| 63772 | thr->builtins[i] = h; |
| 63773 | DUK_HOBJECT_INCREF(thr, &h->hdr); |
| 63774 | } |
| 63775 | |
| 63776 | if (len >= 0) { |
| 63777 | /* In ES2015+ built-in function object .length property |
| 63778 | * has property attributes C (configurable only): |
| 63779 | * http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-standard-built-in-objects |
| 63780 | * |
| 63781 | * Array.prototype remains an Array instance in ES2015+ |
| 63782 | * and its length has attributes W (writable only). |
| 63783 | * Because .length is now virtual for duk_harray, it is |
| 63784 | * not encoded explicitly in init data. |
| 63785 | */ |
| 63786 | |
| 63787 | DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */ |
| 63788 | duk_push_int(thr, len); |
| 63789 | duk_xdef_prop_stridx_short(thr, |
| 63790 | -2, |
| 63791 | DUK_STRIDX_LENGTH, |
| 63792 | DUK_PROPDESC_FLAGS_C); |
| 63793 | } |
| 63794 | |
| 63795 | /* enable exotic behaviors last */ |
| 63796 | |
| 63797 | if (class_num == DUK_HOBJECT_CLASS_ARRAY) { |
| 63798 | DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)); /* set by duk_push_array() */ |
| 63799 | } |
| 63800 | if (class_num == DUK_HOBJECT_CLASS_STRING) { |
| 63801 | DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h); |
| 63802 | } |
| 63803 | |
| 63804 | /* some assertions */ |
| 63805 | |
| 63806 | DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h)); |
| 63807 | /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */ |
| 63808 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h)); |
| 63809 | DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h)); |
| 63810 | /* DUK_HOBJECT_FLAG_NATFUNC varies */ |
| 63811 | DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h)); |
| 63812 | DUK_ASSERT(!DUK_HOBJECT_IS_PROXY(h)); |
| 63813 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY); |
| 63814 | /* DUK_HOBJECT_FLAG_STRICT varies */ |
| 63815 | DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */ |
| 63816 | DUK_HOBJECT_HAS_NEWENV(h)); |
| 63817 | DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h)); |
| 63818 | DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h)); |
| 63819 | /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */ |
| 63820 | /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */ |
| 63821 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)); |
| 63822 | |
| 63823 | DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld" , (long) i, (long) class_num, (long) len)); |
| 63824 | } |
| 63825 | |
| 63826 | /* |
| 63827 | * Then decode the builtins init data (see genbuiltins.py) to |
| 63828 | * init objects. Internal prototypes are set at this stage, |
| 63829 | * with thr->builtins[] populated. |
| 63830 | */ |
| 63831 | |
| 63832 | DUK_DD(DUK_DDPRINT("initialize built-in object properties" )); |
| 63833 | for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { |
| 63834 | duk_small_uint_t t; |
| 63835 | duk_small_uint_t num; |
| 63836 | |
| 63837 | DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld" , (long) i)); |
| 63838 | h = duk_known_hobject(thr, (duk_idx_t) i); |
| 63839 | |
| 63840 | t = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63841 | if (t > 0) { |
| 63842 | t--; |
| 63843 | DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld" , (long) t)); |
| 63844 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(thr, (duk_idx_t) t)); |
| 63845 | } else if (DUK_HOBJECT_IS_NATFUNC(h)) { |
| 63846 | /* Standard native built-ins cannot inherit from |
| 63847 | * %NativeFunctionPrototype%, they are required to |
| 63848 | * inherit from Function.prototype directly. |
| 63849 | */ |
| 63850 | DUK_ASSERT(thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE] != NULL); |
| 63851 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 63852 | } |
| 63853 | |
| 63854 | t = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63855 | if (t > 0) { |
| 63856 | /* 'prototype' property for all built-in objects (which have it) has attributes: |
| 63857 | * [[Writable]] = false, |
| 63858 | * [[Enumerable]] = false, |
| 63859 | * [[Configurable]] = false |
| 63860 | */ |
| 63861 | t--; |
| 63862 | DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld" , (long) t)); |
| 63863 | duk_dup(thr, (duk_idx_t) t); |
| 63864 | duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_NONE); |
| 63865 | } |
| 63866 | |
| 63867 | t = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63868 | if (t > 0) { |
| 63869 | /* 'constructor' property for all built-in objects (which have it) has attributes: |
| 63870 | * [[Writable]] = true, |
| 63871 | * [[Enumerable]] = false, |
| 63872 | * [[Configurable]] = true |
| 63873 | */ |
| 63874 | t--; |
| 63875 | DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld" , (long) t)); |
| 63876 | duk_dup(thr, (duk_idx_t) t); |
| 63877 | duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); |
| 63878 | } |
| 63879 | |
| 63880 | /* normal valued properties */ |
| 63881 | num = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63882 | DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties" , (long) i, (long) num)); |
| 63883 | for (j = 0; j < num; j++) { |
| 63884 | duk_small_uint_t defprop_flags; |
| 63885 | |
| 63886 | duk__push_stridx_or_string(thr, bd); |
| 63887 | |
| 63888 | /* |
| 63889 | * Property attribute defaults are defined in E5 Section 15 (first |
| 63890 | * few pages); there is a default for all properties and a special |
| 63891 | * default for 'length' properties. Variation from the defaults is |
| 63892 | * signaled using a single flag bit in the bitstream. |
| 63893 | */ |
| 63894 | |
| 63895 | defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd, |
| 63896 | DUK__PROP_FLAGS_BITS, |
| 63897 | (duk_uint32_t) DUK_PROPDESC_FLAGS_WC); |
| 63898 | defprop_flags |= DUK_DEFPROP_FORCE | |
| 63899 | DUK_DEFPROP_HAVE_VALUE | |
| 63900 | DUK_DEFPROP_HAVE_WRITABLE | |
| 63901 | DUK_DEFPROP_HAVE_ENUMERABLE | |
| 63902 | DUK_DEFPROP_HAVE_CONFIGURABLE; /* Defaults for data properties. */ |
| 63903 | |
| 63904 | /* The writable, enumerable, configurable flags in prop_flags |
| 63905 | * match both duk_def_prop() and internal property flags. |
| 63906 | */ |
| 63907 | DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE); |
| 63908 | DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE); |
| 63909 | DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE); |
| 63910 | |
| 63911 | t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS); |
| 63912 | |
| 63913 | DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld" , |
| 63914 | (long) i, (long) j, duk_get_tval(thr, -1), (unsigned long) defprop_flags, (long) t)); |
| 63915 | |
| 63916 | switch (t) { |
| 63917 | case DUK__PROP_TYPE_DOUBLE: { |
| 63918 | duk__push_double(thr, bd); |
| 63919 | break; |
| 63920 | } |
| 63921 | case DUK__PROP_TYPE_STRING: { |
| 63922 | duk__push_string(thr, bd); |
| 63923 | break; |
| 63924 | } |
| 63925 | case DUK__PROP_TYPE_STRIDX: { |
| 63926 | duk__push_stridx(thr, bd); |
| 63927 | break; |
| 63928 | } |
| 63929 | case DUK__PROP_TYPE_BUILTIN: { |
| 63930 | duk_small_uint_t bidx; |
| 63931 | |
| 63932 | bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63933 | duk_dup(thr, (duk_idx_t) bidx); |
| 63934 | break; |
| 63935 | } |
| 63936 | case DUK__PROP_TYPE_UNDEFINED: { |
| 63937 | duk_push_undefined(thr); |
| 63938 | break; |
| 63939 | } |
| 63940 | case DUK__PROP_TYPE_BOOLEAN_TRUE: { |
| 63941 | duk_push_true(thr); |
| 63942 | break; |
| 63943 | } |
| 63944 | case DUK__PROP_TYPE_BOOLEAN_FALSE: { |
| 63945 | duk_push_false(thr); |
| 63946 | break; |
| 63947 | } |
| 63948 | case DUK__PROP_TYPE_ACCESSOR: { |
| 63949 | duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63950 | duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63951 | duk_small_uint_t accessor_magic = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63952 | duk_c_function c_func_getter; |
| 63953 | duk_c_function c_func_setter; |
| 63954 | |
| 63955 | DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx" , |
| 63956 | (long) i, duk_get_tval(thr, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags)); |
| 63957 | |
| 63958 | c_func_getter = duk_bi_native_functions[natidx_getter]; |
| 63959 | if (c_func_getter != NULL) { |
| 63960 | duk_push_c_function_builtin_noconstruct(thr, c_func_getter, 0); /* always 0 args */ |
| 63961 | duk_set_magic(thr, -1, (duk_int_t) accessor_magic); |
| 63962 | defprop_flags |= DUK_DEFPROP_HAVE_GETTER; |
| 63963 | } |
| 63964 | c_func_setter = duk_bi_native_functions[natidx_setter]; |
| 63965 | if (c_func_setter != NULL) { |
| 63966 | duk_push_c_function_builtin_noconstruct(thr, c_func_setter, 1); /* always 1 arg */ |
| 63967 | duk_set_magic(thr, -1, (duk_int_t) accessor_magic); |
| 63968 | defprop_flags |= DUK_DEFPROP_HAVE_SETTER; |
| 63969 | } |
| 63970 | |
| 63971 | /* Writable flag doesn't make sense for an accessor. */ |
| 63972 | DUK_ASSERT((defprop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */ |
| 63973 | |
| 63974 | defprop_flags &= ~(DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE); |
| 63975 | defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE; |
| 63976 | break; |
| 63977 | } |
| 63978 | default: { |
| 63979 | /* exhaustive */ |
| 63980 | DUK_UNREACHABLE(); |
| 63981 | } |
| 63982 | } |
| 63983 | |
| 63984 | duk_def_prop(thr, (duk_idx_t) i, defprop_flags); |
| 63985 | DUK_ASSERT_TOP(thr, DUK_NUM_ALL_BUILTINS); |
| 63986 | } |
| 63987 | |
| 63988 | /* native function properties */ |
| 63989 | num = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 63990 | DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties" , (long) i, (long) num)); |
| 63991 | for (j = 0; j < num; j++) { |
| 63992 | duk_hstring *h_key; |
| 63993 | duk_small_uint_t natidx; |
| 63994 | duk_int_t c_nargs; /* must hold DUK_VARARGS */ |
| 63995 | duk_small_uint_t c_length; |
| 63996 | duk_int16_t magic; |
| 63997 | duk_c_function c_func; |
| 63998 | duk_hnatfunc *h_func; |
| 63999 | #if defined(DUK_USE_LIGHTFUNC_BUILTINS) |
| 64000 | duk_small_int_t lightfunc_eligible; |
| 64001 | #endif |
| 64002 | duk_small_uint_t defprop_flags; |
| 64003 | |
| 64004 | duk__push_stridx_or_string(thr, bd); |
| 64005 | h_key = duk_known_hstring(thr, -1); |
| 64006 | DUK_UNREF(h_key); |
| 64007 | natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd); |
| 64008 | |
| 64009 | c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS); |
| 64010 | c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_uint32_t) c_length /*def_value*/); |
| 64011 | if (c_nargs == DUK__NARGS_VARARGS_MARKER) { |
| 64012 | c_nargs = DUK_VARARGS; |
| 64013 | } |
| 64014 | |
| 64015 | c_func = duk_bi_native_functions[natidx]; |
| 64016 | |
| 64017 | DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld" , |
| 64018 | (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length, |
| 64019 | (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs))); |
| 64020 | |
| 64021 | /* Cast converts magic to 16-bit signed value */ |
| 64022 | magic = (duk_int16_t) duk_bd_decode_varuint(bd); |
| 64023 | |
| 64024 | #if defined(DUK_USE_LIGHTFUNC_BUILTINS) |
| 64025 | lightfunc_eligible = |
| 64026 | ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) && |
| 64027 | (c_length <= DUK_LFUNC_LENGTH_MAX) && |
| 64028 | (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX); |
| 64029 | |
| 64030 | /* These functions have trouble working as lightfuncs. |
| 64031 | * Some of them have specific asserts and some may have |
| 64032 | * additional properties (e.g. 'require.id' may be written). |
| 64033 | */ |
| 64034 | if (c_func == duk_bi_global_object_eval) { |
| 64035 | lightfunc_eligible = 0; |
| 64036 | } |
| 64037 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 64038 | if (c_func == duk_bi_thread_yield || |
| 64039 | c_func == duk_bi_thread_resume) { |
| 64040 | lightfunc_eligible = 0; |
| 64041 | } |
| 64042 | #endif |
| 64043 | if (c_func == duk_bi_function_prototype_call || |
| 64044 | c_func == duk_bi_function_prototype_apply || |
| 64045 | c_func == duk_bi_reflect_apply || |
| 64046 | c_func == duk_bi_reflect_construct) { |
| 64047 | lightfunc_eligible = 0; |
| 64048 | } |
| 64049 | |
| 64050 | if (lightfunc_eligible) { |
| 64051 | duk_tval tv_lfunc; |
| 64052 | duk_small_uint_t lf_nargs = (duk_small_uint_t) (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs); |
| 64053 | duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs); |
| 64054 | DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags); |
| 64055 | duk_push_tval(thr, &tv_lfunc); |
| 64056 | DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT" , (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(thr, -1))); |
| 64057 | goto lightfunc_skip; |
| 64058 | } |
| 64059 | |
| 64060 | DUK_D(DUK_DPRINT("built-in function NOT ELIGIBLE as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld" , (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic)); |
| 64061 | #endif /* DUK_USE_LIGHTFUNC_BUILTINS */ |
| 64062 | |
| 64063 | /* [ (builtin objects) name ] */ |
| 64064 | |
| 64065 | duk_push_c_function_builtin_noconstruct(thr, c_func, c_nargs); |
| 64066 | h_func = duk_known_hnatfunc(thr, -1); |
| 64067 | DUK_UNREF(h_func); |
| 64068 | |
| 64069 | /* XXX: add into init data? */ |
| 64070 | |
| 64071 | /* Special call handling, not described in init data. */ |
| 64072 | if (c_func == duk_bi_global_object_eval || |
| 64073 | c_func == duk_bi_function_prototype_call || |
| 64074 | c_func == duk_bi_function_prototype_apply || |
| 64075 | c_func == duk_bi_reflect_apply || |
| 64076 | c_func == duk_bi_reflect_construct) { |
| 64077 | DUK_HOBJECT_SET_SPECIAL_CALL((duk_hobject *) h_func); |
| 64078 | } |
| 64079 | |
| 64080 | /* Currently all built-in native functions are strict. |
| 64081 | * This doesn't matter for many functions, but e.g. |
| 64082 | * String.prototype.charAt (and other string functions) |
| 64083 | * rely on being strict so that their 'this' binding is |
| 64084 | * not automatically coerced. |
| 64085 | */ |
| 64086 | DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func); |
| 64087 | |
| 64088 | /* No built-in functions are constructable except the top |
| 64089 | * level ones (Number, etc). |
| 64090 | */ |
| 64091 | DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func)); |
| 64092 | |
| 64093 | /* XXX: any way to avoid decoding magic bit; there are quite |
| 64094 | * many function properties and relatively few with magic values. |
| 64095 | */ |
| 64096 | h_func->magic = magic; |
| 64097 | |
| 64098 | /* [ (builtin objects) name func ] */ |
| 64099 | |
| 64100 | duk_push_uint(thr, c_length); |
| 64101 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); |
| 64102 | |
| 64103 | duk_dup_m2(thr); |
| 64104 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); |
| 64105 | |
| 64106 | /* XXX: other properties of function instances; 'arguments', 'caller'. */ |
| 64107 | |
| 64108 | DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T" , |
| 64109 | (long) i, (long) j, (duk_tval *) duk_get_tval(thr, -1))); |
| 64110 | |
| 64111 | /* [ (builtin objects) name func ] */ |
| 64112 | |
| 64113 | /* |
| 64114 | * The default property attributes are correct for all |
| 64115 | * function valued properties of built-in objects now. |
| 64116 | */ |
| 64117 | |
| 64118 | #if defined(DUK_USE_LIGHTFUNC_BUILTINS) |
| 64119 | lightfunc_skip: |
| 64120 | #endif |
| 64121 | |
| 64122 | defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd, |
| 64123 | DUK__PROP_FLAGS_BITS, |
| 64124 | (duk_uint32_t) DUK_PROPDESC_FLAGS_WC); |
| 64125 | defprop_flags |= DUK_DEFPROP_FORCE | |
| 64126 | DUK_DEFPROP_HAVE_VALUE | |
| 64127 | DUK_DEFPROP_HAVE_WRITABLE | |
| 64128 | DUK_DEFPROP_HAVE_ENUMERABLE | |
| 64129 | DUK_DEFPROP_HAVE_CONFIGURABLE; |
| 64130 | DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE); |
| 64131 | DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE); |
| 64132 | DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE); |
| 64133 | |
| 64134 | duk_def_prop(thr, (duk_idx_t) i, defprop_flags); |
| 64135 | |
| 64136 | /* [ (builtin objects) ] */ |
| 64137 | } |
| 64138 | } |
| 64139 | |
| 64140 | /* |
| 64141 | * Special post-tweaks, for cases not covered by the init data format. |
| 64142 | * |
| 64143 | * - Set Date.prototype.toGMTString to Date.prototype.toUTCString. |
| 64144 | * toGMTString is required to have the same Function object as |
| 64145 | * toUTCString in E5 Section B.2.6. Note that while Smjs respects |
| 64146 | * this, V8 does not (the Function objects are distinct). |
| 64147 | * |
| 64148 | * - Make DoubleError non-extensible. |
| 64149 | * |
| 64150 | * - Add info about most important effective compile options to Duktape. |
| 64151 | * |
| 64152 | * - Possibly remove some properties (values or methods) which are not |
| 64153 | * desirable with current feature options but are not currently |
| 64154 | * conditional in init data. |
| 64155 | */ |
| 64156 | |
| 64157 | #if defined(DUK_USE_DATE_BUILTIN) |
| 64158 | duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING); |
| 64159 | duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC); |
| 64160 | #endif |
| 64161 | |
| 64162 | h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR); |
| 64163 | DUK_HOBJECT_CLEAR_EXTENSIBLE(h); |
| 64164 | |
| 64165 | #if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY) |
| 64166 | DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features" )); |
| 64167 | (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW); |
| 64168 | #endif |
| 64169 | |
| 64170 | #if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF) |
| 64171 | DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features" )); |
| 64172 | (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW); |
| 64173 | #endif |
| 64174 | |
| 64175 | /* XXX: relocate */ |
| 64176 | duk_push_string(thr, |
| 64177 | /* Endianness indicator */ |
| 64178 | #if defined(DUK_USE_INTEGER_LE) |
| 64179 | "l" |
| 64180 | #elif defined(DUK_USE_INTEGER_BE) |
| 64181 | "b" |
| 64182 | #elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */ |
| 64183 | "m" |
| 64184 | #else |
| 64185 | "?" |
| 64186 | #endif |
| 64187 | #if defined(DUK_USE_DOUBLE_LE) |
| 64188 | "l" |
| 64189 | #elif defined(DUK_USE_DOUBLE_BE) |
| 64190 | "b" |
| 64191 | #elif defined(DUK_USE_DOUBLE_ME) |
| 64192 | "m" |
| 64193 | #else |
| 64194 | "?" |
| 64195 | #endif |
| 64196 | " " |
| 64197 | /* Packed or unpacked tval */ |
| 64198 | #if defined(DUK_USE_PACKED_TVAL) |
| 64199 | "p" |
| 64200 | #else |
| 64201 | "u" |
| 64202 | #endif |
| 64203 | #if defined(DUK_USE_FASTINT) |
| 64204 | "f" |
| 64205 | #endif |
| 64206 | " " |
| 64207 | /* Low memory/performance options */ |
| 64208 | #if defined(DUK_USE_STRTAB_PTRCOMP) |
| 64209 | "s" |
| 64210 | #endif |
| 64211 | #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16) |
| 64212 | "n" |
| 64213 | #endif |
| 64214 | #if defined(DUK_USE_HEAPPTR16) |
| 64215 | "h" |
| 64216 | #endif |
| 64217 | #if defined(DUK_USE_DATAPTR16) |
| 64218 | "d" |
| 64219 | #endif |
| 64220 | #if defined(DUK_USE_FUNCPTR16) |
| 64221 | "f" |
| 64222 | #endif |
| 64223 | #if defined(DUK_USE_REFCOUNT16) |
| 64224 | "R" |
| 64225 | #endif |
| 64226 | #if defined(DUK_USE_STRHASH16) |
| 64227 | "H" |
| 64228 | #endif |
| 64229 | #if defined(DUK_USE_STRLEN16) |
| 64230 | "S" |
| 64231 | #endif |
| 64232 | #if defined(DUK_USE_BUFLEN16) |
| 64233 | "B" |
| 64234 | #endif |
| 64235 | #if defined(DUK_USE_OBJSIZES16) |
| 64236 | "O" |
| 64237 | #endif |
| 64238 | #if defined(DUK_USE_LIGHTFUNC_BUILTINS) |
| 64239 | "L" |
| 64240 | #endif |
| 64241 | #if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS) |
| 64242 | /* XXX: This won't be shown in practice now |
| 64243 | * because this code is not run when builtins |
| 64244 | * are in ROM. |
| 64245 | */ |
| 64246 | "Z" |
| 64247 | #endif |
| 64248 | #if defined(DUK_USE_LITCACHE_SIZE) |
| 64249 | "l" |
| 64250 | #endif |
| 64251 | " " |
| 64252 | /* Object property allocation layout */ |
| 64253 | #if defined(DUK_USE_HOBJECT_LAYOUT_1) |
| 64254 | "p1" |
| 64255 | #elif defined(DUK_USE_HOBJECT_LAYOUT_2) |
| 64256 | "p2" |
| 64257 | #elif defined(DUK_USE_HOBJECT_LAYOUT_3) |
| 64258 | "p3" |
| 64259 | #else |
| 64260 | "p?" |
| 64261 | #endif |
| 64262 | " " |
| 64263 | /* Alignment guarantee */ |
| 64264 | #if (DUK_USE_ALIGN_BY == 4) |
| 64265 | "a4" |
| 64266 | #elif (DUK_USE_ALIGN_BY == 8) |
| 64267 | "a8" |
| 64268 | #elif (DUK_USE_ALIGN_BY == 1) |
| 64269 | "a1" |
| 64270 | #else |
| 64271 | #error invalid DUK_USE_ALIGN_BY |
| 64272 | #endif |
| 64273 | " " |
| 64274 | /* Architecture, OS, and compiler strings */ |
| 64275 | DUK_USE_ARCH_STRING |
| 64276 | " " |
| 64277 | DUK_USE_OS_STRING |
| 64278 | " " |
| 64279 | DUK_USE_COMPILER_STRING); |
| 64280 | duk_xdef_prop_stridx_short(thr, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC); |
| 64281 | |
| 64282 | /* |
| 64283 | * Since built-ins are not often extended, compact them. |
| 64284 | */ |
| 64285 | |
| 64286 | DUK_DD(DUK_DDPRINT("compact built-ins" )); |
| 64287 | for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { |
| 64288 | duk_hobject_compact_props(thr, duk_known_hobject(thr, (duk_idx_t) i)); |
| 64289 | } |
| 64290 | |
| 64291 | DUK_D(DUK_DPRINT("INITBUILTINS END" )); |
| 64292 | |
| 64293 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1) |
| 64294 | for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) { |
| 64295 | DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO" , |
| 64296 | (long) i, (duk_heaphdr *) duk_require_hobject(thr, (duk_idx_t) i))); |
| 64297 | } |
| 64298 | #endif |
| 64299 | |
| 64300 | /* |
| 64301 | * Pop built-ins from stack: they are now INCREF'd and |
| 64302 | * reachable from the builtins[] array or indirectly |
| 64303 | * through builtins[]. |
| 64304 | */ |
| 64305 | |
| 64306 | duk_set_top(thr, 0); |
| 64307 | DUK_ASSERT_TOP(thr, 0); |
| 64308 | } |
| 64309 | #endif /* DUK_USE_ROM_OBJECTS */ |
| 64310 | |
| 64311 | DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) { |
| 64312 | duk_small_uint_t i; |
| 64313 | |
| 64314 | for (i = 0; i < DUK_NUM_BUILTINS; i++) { |
| 64315 | thr_to->builtins[i] = thr_from->builtins[i]; |
| 64316 | DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */ |
| 64317 | } |
| 64318 | } |
| 64319 | |
| 64320 | /* automatic undefs */ |
| 64321 | #undef DUK__LENGTH_PROP_BITS |
| 64322 | #undef DUK__NARGS_BITS |
| 64323 | #undef DUK__NARGS_VARARGS_MARKER |
| 64324 | #undef DUK__PROP_FLAGS_BITS |
| 64325 | #undef DUK__PROP_TYPE_ACCESSOR |
| 64326 | #undef DUK__PROP_TYPE_BITS |
| 64327 | #undef DUK__PROP_TYPE_BOOLEAN_FALSE |
| 64328 | #undef DUK__PROP_TYPE_BOOLEAN_TRUE |
| 64329 | #undef DUK__PROP_TYPE_BUILTIN |
| 64330 | #undef DUK__PROP_TYPE_DOUBLE |
| 64331 | #undef DUK__PROP_TYPE_STRIDX |
| 64332 | #undef DUK__PROP_TYPE_STRING |
| 64333 | #undef DUK__PROP_TYPE_UNDEFINED |
| 64334 | #line 1 "duk_hthread_misc.c" |
| 64335 | /* |
| 64336 | * Thread support. |
| 64337 | */ |
| 64338 | |
| 64339 | /* #include duk_internal.h -> already included */ |
| 64340 | |
| 64341 | DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) { |
| 64342 | DUK_ASSERT(thr != NULL); |
| 64343 | |
| 64344 | while (thr->callstack_curr != NULL) { |
| 64345 | duk_hthread_activation_unwind_norz(thr); |
| 64346 | } |
| 64347 | |
| 64348 | thr->valstack_bottom = thr->valstack; |
| 64349 | duk_set_top(thr, 0); /* unwinds valstack, updating refcounts */ |
| 64350 | |
| 64351 | thr->state = DUK_HTHREAD_STATE_TERMINATED; |
| 64352 | |
| 64353 | /* Here we could remove references to built-ins, but it may not be |
| 64354 | * worth the effort because built-ins are quite likely to be shared |
| 64355 | * with another (unterminated) thread, and terminated threads are also |
| 64356 | * usually garbage collected quite quickly. |
| 64357 | * |
| 64358 | * We could also shrink the value stack here, but that also may not |
| 64359 | * be worth the effort for the same reason. |
| 64360 | */ |
| 64361 | |
| 64362 | DUK_REFZERO_CHECK_SLOW(thr); |
| 64363 | } |
| 64364 | |
| 64365 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 64366 | DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { |
| 64367 | duk_instr_t *bcode; |
| 64368 | |
| 64369 | DUK_ASSERT(thr != NULL); |
| 64370 | DUK_ASSERT(act != NULL); |
| 64371 | DUK_UNREF(thr); |
| 64372 | |
| 64373 | /* XXX: store 'bcode' pointer to activation for faster lookup? */ |
| 64374 | if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) { |
| 64375 | bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func)); |
| 64376 | return (duk_uint_fast32_t) (act->curr_pc - bcode); |
| 64377 | } |
| 64378 | return 0; |
| 64379 | } |
| 64380 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 64381 | |
| 64382 | DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) { |
| 64383 | duk_instr_t *bcode; |
| 64384 | duk_uint_fast32_t ret; |
| 64385 | |
| 64386 | DUK_ASSERT(thr != NULL); |
| 64387 | DUK_ASSERT(act != NULL); |
| 64388 | DUK_UNREF(thr); |
| 64389 | |
| 64390 | if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) { |
| 64391 | bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func)); |
| 64392 | ret = (duk_uint_fast32_t) (act->curr_pc - bcode); |
| 64393 | if (ret > 0) { |
| 64394 | ret--; |
| 64395 | } |
| 64396 | return ret; |
| 64397 | } |
| 64398 | return 0; |
| 64399 | } |
| 64400 | |
| 64401 | /* Write bytecode executor's curr_pc back to topmost activation (if any). */ |
| 64402 | DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) { |
| 64403 | duk_activation *act; |
| 64404 | |
| 64405 | DUK_ASSERT(thr != NULL); |
| 64406 | |
| 64407 | if (thr->ptr_curr_pc != NULL) { |
| 64408 | /* ptr_curr_pc != NULL only when bytecode executor is active. */ |
| 64409 | DUK_ASSERT(thr->callstack_top > 0); |
| 64410 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 64411 | act = thr->callstack_curr; |
| 64412 | DUK_ASSERT(act != NULL); |
| 64413 | act->curr_pc = *thr->ptr_curr_pc; |
| 64414 | } |
| 64415 | } |
| 64416 | |
| 64417 | DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) { |
| 64418 | duk_activation *act; |
| 64419 | |
| 64420 | DUK_ASSERT(thr != NULL); |
| 64421 | |
| 64422 | if (thr->ptr_curr_pc != NULL) { |
| 64423 | /* ptr_curr_pc != NULL only when bytecode executor is active. */ |
| 64424 | DUK_ASSERT(thr->callstack_top > 0); |
| 64425 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 64426 | act = thr->callstack_curr; |
| 64427 | DUK_ASSERT(act != NULL); |
| 64428 | act->curr_pc = *thr->ptr_curr_pc; |
| 64429 | thr->ptr_curr_pc = NULL; |
| 64430 | } |
| 64431 | } |
| 64432 | #line 1 "duk_hthread_stacks.c" |
| 64433 | /* |
| 64434 | * Thread stack (mainly call stack) primitives: allocation of activations, |
| 64435 | * unwinding catchers and activations, etc. |
| 64436 | * |
| 64437 | * Value stack handling is a part of the API implementation. |
| 64438 | */ |
| 64439 | |
| 64440 | /* #include duk_internal.h -> already included */ |
| 64441 | |
| 64442 | /* Unwind the topmost catcher of the current activation (caller must check that |
| 64443 | * both exist) without side effects. |
| 64444 | */ |
| 64445 | DUK_INTERNAL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act) { |
| 64446 | duk_catcher *cat; |
| 64447 | |
| 64448 | DUK_ASSERT(thr != NULL); |
| 64449 | DUK_ASSERT(act != NULL); |
| 64450 | DUK_ASSERT(act->cat != NULL); /* caller must check */ |
| 64451 | cat = act->cat; |
| 64452 | DUK_ASSERT(cat != NULL); |
| 64453 | |
| 64454 | DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is done)" , (void *) cat)); |
| 64455 | |
| 64456 | if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { |
| 64457 | duk_hobject *env; |
| 64458 | |
| 64459 | env = act->lex_env; /* current lex_env of the activation (created for catcher) */ |
| 64460 | DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */ |
| 64461 | act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */ |
| 64462 | DUK_HOBJECT_INCREF(thr, act->lex_env); |
| 64463 | DUK_HOBJECT_DECREF_NORZ(thr, env); |
| 64464 | |
| 64465 | /* There is no need to decref anything else than 'env': if 'env' |
| 64466 | * becomes unreachable, refzero will handle decref'ing its prototype. |
| 64467 | */ |
| 64468 | } |
| 64469 | |
| 64470 | act->cat = cat->parent; |
| 64471 | duk_hthread_catcher_free(thr, cat); |
| 64472 | } |
| 64473 | |
| 64474 | /* Same as above, but caller is certain no catcher-related lexenv may exist. */ |
| 64475 | DUK_INTERNAL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act) { |
| 64476 | duk_catcher *cat; |
| 64477 | |
| 64478 | DUK_ASSERT(thr != NULL); |
| 64479 | DUK_ASSERT(act != NULL); |
| 64480 | DUK_ASSERT(act->cat != NULL); /* caller must check */ |
| 64481 | cat = act->cat; |
| 64482 | DUK_ASSERT(cat != NULL); |
| 64483 | |
| 64484 | DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is not done)" , (void *) cat)); |
| 64485 | |
| 64486 | DUK_ASSERT(!DUK_CAT_HAS_LEXENV_ACTIVE(cat)); |
| 64487 | |
| 64488 | act->cat = cat->parent; |
| 64489 | duk_hthread_catcher_free(thr, cat); |
| 64490 | } |
| 64491 | |
| 64492 | DUK_LOCAL |
| 64493 | #if defined(DUK_USE_CACHE_CATCHER) |
| 64494 | DUK_NOINLINE |
| 64495 | #endif |
| 64496 | duk_catcher *duk__hthread_catcher_alloc_slow(duk_hthread *thr) { |
| 64497 | duk_catcher *cat; |
| 64498 | |
| 64499 | cat = (duk_catcher *) DUK_ALLOC_CHECKED(thr, sizeof(duk_catcher)); |
| 64500 | DUK_ASSERT(cat != NULL); |
| 64501 | return cat; |
| 64502 | } |
| 64503 | |
| 64504 | #if defined(DUK_USE_CACHE_CATCHER) |
| 64505 | DUK_INTERNAL DUK_INLINE duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) { |
| 64506 | duk_catcher *cat; |
| 64507 | |
| 64508 | DUK_ASSERT(thr != NULL); |
| 64509 | |
| 64510 | cat = thr->heap->catcher_free; |
| 64511 | if (DUK_LIKELY(cat != NULL)) { |
| 64512 | thr->heap->catcher_free = cat->parent; |
| 64513 | return cat; |
| 64514 | } |
| 64515 | |
| 64516 | return duk__hthread_catcher_alloc_slow(thr); |
| 64517 | } |
| 64518 | #else /* DUK_USE_CACHE_CATCHER */ |
| 64519 | DUK_INTERNAL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) { |
| 64520 | return duk__hthread_catcher_alloc_slow(thr); |
| 64521 | } |
| 64522 | #endif /* DUK_USE_CACHE_CATCHER */ |
| 64523 | |
| 64524 | DUK_INTERNAL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat) { |
| 64525 | DUK_ASSERT(thr != NULL); |
| 64526 | DUK_ASSERT(cat != NULL); |
| 64527 | |
| 64528 | #if defined(DUK_USE_CACHE_CATCHER) |
| 64529 | /* Unconditional caching for now; freed in mark-and-sweep. */ |
| 64530 | cat->parent = thr->heap->catcher_free; |
| 64531 | thr->heap->catcher_free = cat; |
| 64532 | #else |
| 64533 | DUK_FREE_CHECKED(thr, (void *) cat); |
| 64534 | #endif |
| 64535 | } |
| 64536 | |
| 64537 | DUK_LOCAL |
| 64538 | #if defined(DUK_USE_CACHE_ACTIVATION) |
| 64539 | DUK_NOINLINE |
| 64540 | #endif |
| 64541 | duk_activation *duk__hthread_activation_alloc_slow(duk_hthread *thr) { |
| 64542 | duk_activation *act; |
| 64543 | |
| 64544 | act = (duk_activation *) DUK_ALLOC_CHECKED(thr, sizeof(duk_activation)); |
| 64545 | DUK_ASSERT(act != NULL); |
| 64546 | return act; |
| 64547 | } |
| 64548 | |
| 64549 | #if defined(DUK_USE_CACHE_ACTIVATION) |
| 64550 | DUK_INTERNAL DUK_INLINE duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) { |
| 64551 | duk_activation *act; |
| 64552 | |
| 64553 | DUK_ASSERT(thr != NULL); |
| 64554 | |
| 64555 | act = thr->heap->activation_free; |
| 64556 | if (DUK_LIKELY(act != NULL)) { |
| 64557 | thr->heap->activation_free = act->parent; |
| 64558 | return act; |
| 64559 | } |
| 64560 | |
| 64561 | return duk__hthread_activation_alloc_slow(thr); |
| 64562 | } |
| 64563 | #else /* DUK_USE_CACHE_ACTIVATION */ |
| 64564 | DUK_INTERNAL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) { |
| 64565 | return duk__hthread_activation_alloc_slow(thr); |
| 64566 | } |
| 64567 | #endif /* DUK_USE_CACHE_ACTIVATION */ |
| 64568 | |
| 64569 | |
| 64570 | DUK_INTERNAL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act) { |
| 64571 | DUK_ASSERT(thr != NULL); |
| 64572 | DUK_ASSERT(act != NULL); |
| 64573 | |
| 64574 | #if defined(DUK_USE_CACHE_ACTIVATION) |
| 64575 | /* Unconditional caching for now; freed in mark-and-sweep. */ |
| 64576 | act->parent = thr->heap->activation_free; |
| 64577 | thr->heap->activation_free = act; |
| 64578 | #else |
| 64579 | DUK_FREE_CHECKED(thr, (void *) act); |
| 64580 | #endif |
| 64581 | } |
| 64582 | |
| 64583 | /* Internal helper: process the unwind for the topmost activation of a thread, |
| 64584 | * but leave the duk_activation in place for possible tailcall reuse. |
| 64585 | */ |
| 64586 | DUK_LOCAL void duk__activation_unwind_nofree_norz(duk_hthread *thr) { |
| 64587 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 64588 | duk_heap *heap; |
| 64589 | #endif |
| 64590 | duk_activation *act; |
| 64591 | duk_hobject *func; |
| 64592 | duk_hobject *tmp; |
| 64593 | |
| 64594 | DUK_ASSERT(thr != NULL); |
| 64595 | DUK_ASSERT(thr->callstack_curr != NULL); /* caller must check */ |
| 64596 | DUK_ASSERT(thr->callstack_top > 0); |
| 64597 | act = thr->callstack_curr; |
| 64598 | DUK_ASSERT(act != NULL); |
| 64599 | /* With lightfuncs, act 'func' may be NULL. */ |
| 64600 | |
| 64601 | /* With duk_activation records allocated separately, 'act' is a stable |
| 64602 | * pointer and not affected by side effects. |
| 64603 | */ |
| 64604 | |
| 64605 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 64606 | /* |
| 64607 | * Restore 'caller' property for non-strict callee functions. |
| 64608 | */ |
| 64609 | |
| 64610 | func = DUK_ACT_GET_FUNC(act); |
| 64611 | if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) { |
| 64612 | duk_tval *tv_caller; |
| 64613 | duk_tval tv_tmp; |
| 64614 | duk_hobject *h_tmp; |
| 64615 | |
| 64616 | tv_caller = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, func, DUK_STRIDX_CALLER); |
| 64617 | |
| 64618 | /* The act->prev_caller should only be set if the entry for 'caller' |
| 64619 | * exists (as it is only set in that case, and the property is not |
| 64620 | * configurable), but handle all the cases anyway. |
| 64621 | */ |
| 64622 | |
| 64623 | if (tv_caller) { |
| 64624 | DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller); |
| 64625 | if (act->prev_caller) { |
| 64626 | /* Just transfer the refcount from act->prev_caller to tv_caller, |
| 64627 | * so no need for a refcount update. This is the expected case. |
| 64628 | */ |
| 64629 | DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller); |
| 64630 | act->prev_caller = NULL; |
| 64631 | } else { |
| 64632 | DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */ |
| 64633 | DUK_ASSERT(act->prev_caller == NULL); |
| 64634 | } |
| 64635 | DUK_TVAL_DECREF_NORZ(thr, &tv_tmp); |
| 64636 | } else { |
| 64637 | h_tmp = act->prev_caller; |
| 64638 | if (h_tmp) { |
| 64639 | act->prev_caller = NULL; |
| 64640 | DUK_HOBJECT_DECREF_NORZ(thr, h_tmp); |
| 64641 | } |
| 64642 | } |
| 64643 | DUK_ASSERT(act->prev_caller == NULL); |
| 64644 | } |
| 64645 | #endif |
| 64646 | |
| 64647 | /* |
| 64648 | * Unwind debugger state. If we unwind while stepping |
| 64649 | * (for any step type), pause execution. This is the |
| 64650 | * only place explicitly handling a step out. |
| 64651 | */ |
| 64652 | |
| 64653 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 64654 | heap = thr->heap; |
| 64655 | if (heap->dbg_pause_act == thr->callstack_curr) { |
| 64656 | if (heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_EXIT) { |
| 64657 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function exit" )); |
| 64658 | duk_debug_set_paused(heap); |
| 64659 | } else { |
| 64660 | DUK_D(DUK_DPRINT("unwound past dbg_pause_act, set to NULL" )); |
| 64661 | heap->dbg_pause_act = NULL; /* avoid stale pointers */ |
| 64662 | } |
| 64663 | DUK_ASSERT(heap->dbg_pause_act == NULL); |
| 64664 | } |
| 64665 | #endif |
| 64666 | |
| 64667 | /* |
| 64668 | * Unwind catchers. |
| 64669 | * |
| 64670 | * Since there are no references in the catcher structure, |
| 64671 | * unwinding is quite simple. The only thing we need to |
| 64672 | * look out for is popping a possible lexical environment |
| 64673 | * established for an active catch clause. |
| 64674 | */ |
| 64675 | |
| 64676 | while (act->cat != NULL) { |
| 64677 | duk_hthread_catcher_unwind_norz(thr, act); |
| 64678 | } |
| 64679 | |
| 64680 | /* |
| 64681 | * Close environment record(s) if they exist. |
| 64682 | * |
| 64683 | * Only variable environments are closed. If lex_env != var_env, it |
| 64684 | * cannot currently contain any register bound declarations. |
| 64685 | * |
| 64686 | * Only environments created for a NEWENV function are closed. If an |
| 64687 | * environment is created for e.g. an eval call, it must not be closed. |
| 64688 | */ |
| 64689 | |
| 64690 | func = DUK_ACT_GET_FUNC(act); |
| 64691 | if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) { |
| 64692 | DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation" )); |
| 64693 | goto skip_env_close; |
| 64694 | } |
| 64695 | /* func is NULL for lightfunc */ |
| 64696 | |
| 64697 | /* Catch sites are required to clean up their environments |
| 64698 | * in FINALLY part before propagating, so this should |
| 64699 | * always hold here. |
| 64700 | */ |
| 64701 | DUK_ASSERT(act->lex_env == act->var_env); |
| 64702 | |
| 64703 | /* XXX: Closing the environment record copies values from registers |
| 64704 | * into the scope object. It's side effect free as such, but may |
| 64705 | * currently run out of memory which causes an error throw. This is |
| 64706 | * an actual sandboxing problem for error unwinds, and needs to be |
| 64707 | * fixed e.g. by preallocating the scope property slots. |
| 64708 | */ |
| 64709 | if (act->var_env != NULL) { |
| 64710 | DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O" , |
| 64711 | (void *) act->var_env, (duk_heaphdr *) act->var_env)); |
| 64712 | duk_js_close_environment_record(thr, act->var_env); |
| 64713 | } |
| 64714 | |
| 64715 | skip_env_close: |
| 64716 | |
| 64717 | /* |
| 64718 | * Update preventcount |
| 64719 | */ |
| 64720 | |
| 64721 | if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { |
| 64722 | DUK_ASSERT(thr->callstack_preventcount >= 1); |
| 64723 | thr->callstack_preventcount--; |
| 64724 | } |
| 64725 | |
| 64726 | /* |
| 64727 | * Reference count updates, using NORZ macros so we don't |
| 64728 | * need to handle side effects. |
| 64729 | * |
| 64730 | * duk_activation pointers like act->var_env are intentionally |
| 64731 | * left as garbage and not NULLed. Without side effects they |
| 64732 | * can't be used when the values are dangling/garbage. |
| 64733 | */ |
| 64734 | |
| 64735 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env); |
| 64736 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env); |
| 64737 | tmp = DUK_ACT_GET_FUNC(act); |
| 64738 | DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp); |
| 64739 | DUK_UNREF(tmp); |
| 64740 | } |
| 64741 | |
| 64742 | /* Unwind topmost duk_activation of a thread, caller must ensure that an |
| 64743 | * activation exists. The call is side effect free, except that scope |
| 64744 | * closure may currently throw an out-of-memory error. |
| 64745 | */ |
| 64746 | DUK_INTERNAL void duk_hthread_activation_unwind_norz(duk_hthread *thr) { |
| 64747 | duk_activation *act; |
| 64748 | |
| 64749 | duk__activation_unwind_nofree_norz(thr); |
| 64750 | |
| 64751 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 64752 | DUK_ASSERT(thr->callstack_top > 0); |
| 64753 | act = thr->callstack_curr; |
| 64754 | thr->callstack_curr = act->parent; |
| 64755 | thr->callstack_top--; |
| 64756 | |
| 64757 | /* Ideally we'd restore value stack reserve here to caller's value. |
| 64758 | * This doesn't work for current unwind call sites however, because |
| 64759 | * the current (unwound) value stack top may be above the reserve. |
| 64760 | * Thus value stack reserve is restored by the call sites. |
| 64761 | */ |
| 64762 | |
| 64763 | /* XXX: inline for performance builds? */ |
| 64764 | duk_hthread_activation_free(thr, act); |
| 64765 | |
| 64766 | /* We could clear the book-keeping variables like retval_byteoff for |
| 64767 | * the topmost activation, but don't do so now as it's not necessary. |
| 64768 | */ |
| 64769 | } |
| 64770 | |
| 64771 | DUK_INTERNAL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr) { |
| 64772 | duk__activation_unwind_nofree_norz(thr); |
| 64773 | } |
| 64774 | |
| 64775 | /* Get duk_activation for given callstack level or NULL if level is invalid |
| 64776 | * or deeper than the call stack. Level -1 refers to current activation, -2 |
| 64777 | * to its caller, etc. Starting from Duktape 2.2 finding the activation is |
| 64778 | * a linked list scan which gets more expensive the deeper the lookup is. |
| 64779 | */ |
| 64780 | DUK_INTERNAL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level) { |
| 64781 | duk_activation *act; |
| 64782 | |
| 64783 | if (level >= 0) { |
| 64784 | return NULL; |
| 64785 | } |
| 64786 | act = thr->callstack_curr; |
| 64787 | for (;;) { |
| 64788 | if (act == NULL) { |
| 64789 | return act; |
| 64790 | } |
| 64791 | if (level == -1) { |
| 64792 | return act; |
| 64793 | } |
| 64794 | level++; |
| 64795 | act = act->parent; |
| 64796 | } |
| 64797 | /* never here */ |
| 64798 | } |
| 64799 | |
| 64800 | #if defined(DUK_USE_FINALIZER_TORTURE) |
| 64801 | DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) { |
| 64802 | duk_size_t alloc_size; |
| 64803 | duk_tval *new_ptr; |
| 64804 | duk_ptrdiff_t alloc_end_off; |
| 64805 | duk_ptrdiff_t end_off; |
| 64806 | duk_ptrdiff_t bottom_off; |
| 64807 | duk_ptrdiff_t top_off; |
| 64808 | |
| 64809 | if (thr->valstack == NULL) { |
| 64810 | DUK_D(DUK_DPRINT("skip valstack torture realloc, valstack is NULL" )); |
| 64811 | return; |
| 64812 | } |
| 64813 | |
| 64814 | alloc_end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack); |
| 64815 | end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); |
| 64816 | bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); |
| 64817 | top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack); |
| 64818 | alloc_size = (duk_size_t) alloc_end_off; |
| 64819 | if (alloc_size == 0) { |
| 64820 | DUK_D(DUK_DPRINT("skip valstack torture realloc, alloc_size is zero" )); |
| 64821 | return; |
| 64822 | } |
| 64823 | |
| 64824 | /* Use DUK_ALLOC_RAW() to avoid side effects. */ |
| 64825 | new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size); |
| 64826 | if (new_ptr != NULL) { |
| 64827 | duk_memcpy((void *) new_ptr, (const void *) thr->valstack, alloc_size); |
| 64828 | duk_memset((void *) thr->valstack, 0x55, alloc_size); |
| 64829 | DUK_FREE_CHECKED(thr, (void *) thr->valstack); |
| 64830 | thr->valstack = new_ptr; |
| 64831 | thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off); |
| 64832 | thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off); |
| 64833 | thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off); |
| 64834 | thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off); |
| 64835 | } else { |
| 64836 | DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore" )); |
| 64837 | } |
| 64838 | } |
| 64839 | #endif /* DUK_USE_FINALIZER_TORTURE */ |
| 64840 | #line 1 "duk_js_arith.c" |
| 64841 | /* |
| 64842 | * Shared helpers for arithmetic operations |
| 64843 | */ |
| 64844 | |
| 64845 | /* #include duk_internal.h -> already included */ |
| 64846 | |
| 64847 | /* ECMAScript modulus ('%') does not match IEEE 754 "remainder" operation |
| 64848 | * (implemented by remainder() in C99) but does seem to match ANSI C fmod(). |
| 64849 | * Compare E5 Section 11.5.3 and "man fmod". |
| 64850 | */ |
| 64851 | DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) { |
| 64852 | #if defined(DUK_USE_POW_WORKAROUNDS) |
| 64853 | /* Specific fixes to common fmod() implementation issues: |
| 64854 | * - test-bug-mingw-math-issues.js |
| 64855 | */ |
| 64856 | if (DUK_ISINF(d2)) { |
| 64857 | if (DUK_ISINF(d1)) { |
| 64858 | return DUK_DOUBLE_NAN; |
| 64859 | } else { |
| 64860 | return d1; |
| 64861 | } |
| 64862 | } else if (duk_double_equals(d1, 0.0)) { |
| 64863 | /* d1 +/-0 is returned as is (preserving sign) except when |
| 64864 | * d2 is zero or NaN. |
| 64865 | */ |
| 64866 | if (duk_double_equals(d2, 0.0) || DUK_ISNAN(d2)) { |
| 64867 | return DUK_DOUBLE_NAN; |
| 64868 | } else { |
| 64869 | return d1; |
| 64870 | } |
| 64871 | } |
| 64872 | #else |
| 64873 | /* Some ISO C assumptions. */ |
| 64874 | DUK_ASSERT(duk_double_equals(DUK_FMOD(1.0, DUK_DOUBLE_INFINITY), 1.0)); |
| 64875 | DUK_ASSERT(duk_double_equals(DUK_FMOD(-1.0, DUK_DOUBLE_INFINITY), -1.0)); |
| 64876 | DUK_ASSERT(duk_double_equals(DUK_FMOD(1.0, -DUK_DOUBLE_INFINITY), 1.0)); |
| 64877 | DUK_ASSERT(duk_double_equals(DUK_FMOD(-1.0, -DUK_DOUBLE_INFINITY), -1.0)); |
| 64878 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY))); |
| 64879 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY))); |
| 64880 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY))); |
| 64881 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY))); |
| 64882 | DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, 1.0), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, 1.0)) == 0); |
| 64883 | DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, 1.0), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, 1.0)) != 0); |
| 64884 | DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0); |
| 64885 | DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY)) != 0); |
| 64886 | DUK_ASSERT(duk_double_equals(DUK_FMOD(0.0, -DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0); |
| 64887 | DUK_ASSERT(duk_double_equals(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY), 0.0) && DUK_SIGNBIT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY)) != 0); |
| 64888 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, 0.0))); |
| 64889 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, 0.0))); |
| 64890 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, -0.0))); |
| 64891 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, -0.0))); |
| 64892 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, DUK_DOUBLE_NAN))); |
| 64893 | DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, DUK_DOUBLE_NAN))); |
| 64894 | #endif |
| 64895 | |
| 64896 | return (duk_double_t) DUK_FMOD((double) d1, (double) d2); |
| 64897 | } |
| 64898 | |
| 64899 | /* Shared helper for Math.pow() and exponentiation operator. */ |
| 64900 | DUK_INTERNAL double duk_js_arith_pow(double x, double y) { |
| 64901 | /* The ANSI C pow() semantics differ from ECMAScript. |
| 64902 | * |
| 64903 | * E.g. when x==1 and y is +/- infinite, the ECMAScript required |
| 64904 | * result is NaN, while at least Linux pow() returns 1. |
| 64905 | */ |
| 64906 | |
| 64907 | duk_small_int_t cx, cy, sx; |
| 64908 | |
| 64909 | DUK_UNREF(cx); |
| 64910 | DUK_UNREF(sx); |
| 64911 | cy = (duk_small_int_t) DUK_FPCLASSIFY(y); |
| 64912 | |
| 64913 | if (cy == DUK_FP_NAN) { |
| 64914 | goto ret_nan; |
| 64915 | } |
| 64916 | if (duk_double_equals(DUK_FABS(x), 1.0) && cy == DUK_FP_INFINITE) { |
| 64917 | goto ret_nan; |
| 64918 | } |
| 64919 | |
| 64920 | #if defined(DUK_USE_POW_WORKAROUNDS) |
| 64921 | /* Specific fixes to common pow() implementation issues: |
| 64922 | * - test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) |
| 64923 | * - test-bug-mingw-math-issues.js |
| 64924 | */ |
| 64925 | cx = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 64926 | if (cx == DUK_FP_ZERO && y < 0.0) { |
| 64927 | sx = (duk_small_int_t) DUK_SIGNBIT(x); |
| 64928 | if (sx == 0) { |
| 64929 | /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow() |
| 64930 | * returns -Infinity instead when y is <0 and finite. The |
| 64931 | * if-clause also catches y == -Infinity (which works even |
| 64932 | * without the fix). |
| 64933 | */ |
| 64934 | return DUK_DOUBLE_INFINITY; |
| 64935 | } else { |
| 64936 | /* Math.pow(-0,y) where y<0 should be: |
| 64937 | * - -Infinity if y<0 and an odd integer |
| 64938 | * - Infinity if y<0 but not an odd integer |
| 64939 | * NetBSD pow() returns -Infinity for all finite y<0. The |
| 64940 | * if-clause also catches y == -Infinity (which works even |
| 64941 | * without the fix). |
| 64942 | */ |
| 64943 | |
| 64944 | /* fmod() return value has same sign as input (negative) so |
| 64945 | * the result here will be in the range ]-2,0], -1 indicates |
| 64946 | * odd. If x is -Infinity, NaN is returned and the odd check |
| 64947 | * always concludes "not odd" which results in desired outcome. |
| 64948 | */ |
| 64949 | double tmp = DUK_FMOD(y, 2); |
| 64950 | if (tmp == -1.0) { |
| 64951 | return -DUK_DOUBLE_INFINITY; |
| 64952 | } else { |
| 64953 | /* Not odd, or y == -Infinity */ |
| 64954 | return DUK_DOUBLE_INFINITY; |
| 64955 | } |
| 64956 | } |
| 64957 | } else if (cx == DUK_FP_NAN) { |
| 64958 | if (duk_double_equals(y, 0.0)) { |
| 64959 | /* NaN ** +/- 0 should always be 1, but is NaN on |
| 64960 | * at least some Cygwin/MinGW versions. |
| 64961 | */ |
| 64962 | return 1.0; |
| 64963 | } |
| 64964 | } |
| 64965 | #else |
| 64966 | /* Some ISO C assumptions. */ |
| 64967 | DUK_ASSERT(duk_double_equals(DUK_POW(DUK_DOUBLE_NAN, 0.0), 1.0)); |
| 64968 | DUK_ASSERT(DUK_ISINF(DUK_POW(0.0, -1.0)) && DUK_SIGNBIT(DUK_POW(0.0, -1.0)) == 0); |
| 64969 | DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -2.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -2.0)) == 0); |
| 64970 | DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -3.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -3.0)) != 0); |
| 64971 | #endif |
| 64972 | |
| 64973 | return DUK_POW(x, y); |
| 64974 | |
| 64975 | ret_nan: |
| 64976 | return DUK_DOUBLE_NAN; |
| 64977 | } |
| 64978 | #line 1 "duk_js_call.c" |
| 64979 | /* |
| 64980 | * Call handling. |
| 64981 | * |
| 64982 | * duk_handle_call_unprotected(): |
| 64983 | * |
| 64984 | * - Unprotected call to ECMAScript or Duktape/C function, from native |
| 64985 | * code or bytecode executor. |
| 64986 | * |
| 64987 | * - Also handles Ecma-to-Ecma calls which reuses a currently running |
| 64988 | * executor instance to avoid native recursion. Call setup is done |
| 64989 | * normally, but just before calling the bytecode executor a special |
| 64990 | * return code is used to indicate that a calling executor is reused. |
| 64991 | * |
| 64992 | * - Also handles tailcalls, i.e. reuse of current duk_activation. |
| 64993 | * |
| 64994 | * - Also handles setup for initial Duktape.Thread.resume(). |
| 64995 | * |
| 64996 | * duk_handle_safe_call(): |
| 64997 | * |
| 64998 | * - Protected C call within current activation. |
| 64999 | * |
| 65000 | * setjmp() and local variables have a nasty interaction, see execution.rst; |
| 65001 | * non-volatile locals modified after setjmp() call are not guaranteed to |
| 65002 | * keep their value and can cause compiler or compiler version specific |
| 65003 | * difficult to replicate issues. |
| 65004 | * |
| 65005 | * See 'execution.rst'. |
| 65006 | */ |
| 65007 | |
| 65008 | /* #include duk_internal.h -> already included */ |
| 65009 | |
| 65010 | /* XXX: heap->error_not_allowed for success path too? */ |
| 65011 | |
| 65012 | /* |
| 65013 | * Limit check helpers. |
| 65014 | */ |
| 65015 | |
| 65016 | /* Check native stack space if DUK_USE_NATIVE_STACK_CHECK() defined. */ |
| 65017 | DUK_INTERNAL void duk_native_stack_check(duk_hthread *thr) { |
| 65018 | #if defined(DUK_USE_NATIVE_STACK_CHECK) |
| 65019 | if (DUK_USE_NATIVE_STACK_CHECK() != 0) { |
| 65020 | DUK_ERROR_RANGE(thr, DUK_STR_NATIVE_STACK_LIMIT); |
| 65021 | } |
| 65022 | #else |
| 65023 | DUK_UNREF(thr); |
| 65024 | #endif |
| 65025 | } |
| 65026 | |
| 65027 | /* Allow headroom for calls during error augmentation (see GH-191). |
| 65028 | * We allow space for 10 additional recursions, with one extra |
| 65029 | * for, e.g. a print() call at the deepest level, and an extra |
| 65030 | * +1 for protected call wrapping. |
| 65031 | */ |
| 65032 | #define DUK__AUGMENT_CALL_RELAX_COUNT (10 + 2) |
| 65033 | |
| 65034 | /* Stack space required by call handling entry. */ |
| 65035 | #define DUK__CALL_HANDLING_REQUIRE_STACK 8 |
| 65036 | |
| 65037 | DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthread *thr) { |
| 65038 | /* When augmenting an error, the effective limit is a bit higher. |
| 65039 | * Check for it only if the fast path check fails. |
| 65040 | */ |
| 65041 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 65042 | if (thr->heap->augmenting_error) { |
| 65043 | if (thr->heap->call_recursion_depth < thr->heap->call_recursion_limit + DUK__AUGMENT_CALL_RELAX_COUNT) { |
| 65044 | DUK_D(DUK_DPRINT("C recursion limit reached but augmenting error and within relaxed limit" )); |
| 65045 | return; |
| 65046 | } |
| 65047 | } |
| 65048 | #endif |
| 65049 | |
| 65050 | DUK_D(DUK_DPRINT("call prevented because C recursion limit reached" )); |
| 65051 | DUK_ERROR_RANGE(thr, DUK_STR_NATIVE_STACK_LIMIT); |
| 65052 | DUK_WO_NORETURN(return;); |
| 65053 | } |
| 65054 | |
| 65055 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) { |
| 65056 | DUK_ASSERT(thr->heap->call_recursion_depth >= 0); |
| 65057 | DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit); |
| 65058 | |
| 65059 | duk_native_stack_check(thr); |
| 65060 | |
| 65061 | /* This check is forcibly inlined because it's very cheap and almost |
| 65062 | * always passes. The slow path is forcibly noinline. |
| 65063 | */ |
| 65064 | if (DUK_LIKELY(thr->heap->call_recursion_depth < thr->heap->call_recursion_limit)) { |
| 65065 | return; |
| 65066 | } |
| 65067 | |
| 65068 | duk__call_c_recursion_limit_check_slowpath(thr); |
| 65069 | } |
| 65070 | |
| 65071 | DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread *thr) { |
| 65072 | /* When augmenting an error, the effective limit is a bit higher. |
| 65073 | * Check for it only if the fast path check fails. |
| 65074 | */ |
| 65075 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 65076 | if (thr->heap->augmenting_error) { |
| 65077 | if (thr->callstack_top < DUK_USE_CALLSTACK_LIMIT + DUK__AUGMENT_CALL_RELAX_COUNT) { |
| 65078 | DUK_D(DUK_DPRINT("call stack limit reached but augmenting error and within relaxed limit" )); |
| 65079 | return; |
| 65080 | } |
| 65081 | } |
| 65082 | #endif |
| 65083 | |
| 65084 | /* XXX: error message is a bit misleading: we reached a recursion |
| 65085 | * limit which is also essentially the same as a C callstack limit |
| 65086 | * (except perhaps with some relaxed threading assumptions). |
| 65087 | */ |
| 65088 | DUK_D(DUK_DPRINT("call prevented because call stack limit reached" )); |
| 65089 | DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT); |
| 65090 | DUK_WO_NORETURN(return;); |
| 65091 | } |
| 65092 | |
| 65093 | DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) { |
| 65094 | /* This check is forcibly inlined because it's very cheap and almost |
| 65095 | * always passes. The slow path is forcibly noinline. |
| 65096 | */ |
| 65097 | if (DUK_LIKELY(thr->callstack_top < DUK_USE_CALLSTACK_LIMIT)) { |
| 65098 | return; |
| 65099 | } |
| 65100 | |
| 65101 | duk__call_callstack_limit_check_slowpath(thr); |
| 65102 | } |
| 65103 | |
| 65104 | /* |
| 65105 | * Interrupt counter fixup (for development only). |
| 65106 | */ |
| 65107 | |
| 65108 | #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) |
| 65109 | DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) { |
| 65110 | /* Currently the bytecode executor and executor interrupt |
| 65111 | * instruction counts are off because we don't execute the |
| 65112 | * interrupt handler when we're about to exit from the initial |
| 65113 | * user call into Duktape. |
| 65114 | * |
| 65115 | * If we were to execute the interrupt handler here, the counts |
| 65116 | * would match. You can enable this block manually to check |
| 65117 | * that this is the case. |
| 65118 | */ |
| 65119 | |
| 65120 | DUK_ASSERT(thr != NULL); |
| 65121 | DUK_ASSERT(thr->heap != NULL); |
| 65122 | |
| 65123 | #if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP) |
| 65124 | if (entry_curr_thread == NULL) { |
| 65125 | thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter; |
| 65126 | thr->heap->inst_count_interrupt += thr->interrupt_init; |
| 65127 | DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to " |
| 65128 | "user code, instruction counts: executor=%ld, interrupt=%ld" , |
| 65129 | (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt)); |
| 65130 | DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt); |
| 65131 | } |
| 65132 | #else |
| 65133 | DUK_UNREF(thr); |
| 65134 | DUK_UNREF(entry_curr_thread); |
| 65135 | #endif |
| 65136 | } |
| 65137 | #endif |
| 65138 | |
| 65139 | /* |
| 65140 | * Arguments object creation. |
| 65141 | * |
| 65142 | * Creating arguments objects involves many small details, see E5 Section |
| 65143 | * 10.6 for the specific requirements. Much of the arguments object exotic |
| 65144 | * behavior is implemented in duk_hobject_props.c, and is enabled by the |
| 65145 | * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS. |
| 65146 | */ |
| 65147 | |
| 65148 | DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr, |
| 65149 | duk_hobject *func, |
| 65150 | duk_hobject *varenv, |
| 65151 | duk_idx_t idx_args) { |
| 65152 | duk_hobject *arg; /* 'arguments' */ |
| 65153 | duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */ |
| 65154 | duk_idx_t i_arg; |
| 65155 | duk_idx_t i_map; |
| 65156 | duk_idx_t i_mappednames; |
| 65157 | duk_idx_t i_formals; |
| 65158 | duk_idx_t i_argbase; |
| 65159 | duk_idx_t n_formals; |
| 65160 | duk_idx_t idx; |
| 65161 | duk_idx_t num_stack_args; |
| 65162 | duk_bool_t need_map; |
| 65163 | |
| 65164 | DUK_ASSERT(thr != NULL); |
| 65165 | DUK_ASSERT(func != NULL); |
| 65166 | DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func)); |
| 65167 | DUK_ASSERT(varenv != NULL); |
| 65168 | |
| 65169 | /* [ ... func this arg1(@idx_args) ... argN envobj ] |
| 65170 | * [ arg1(@idx_args) ... argN envobj ] (for tailcalls) |
| 65171 | */ |
| 65172 | |
| 65173 | need_map = 0; |
| 65174 | |
| 65175 | i_argbase = idx_args; |
| 65176 | num_stack_args = duk_get_top(thr) - i_argbase - 1; |
| 65177 | DUK_ASSERT(i_argbase >= 0); |
| 65178 | DUK_ASSERT(num_stack_args >= 0); |
| 65179 | |
| 65180 | formals = (duk_hobject *) duk_hobject_get_formals(thr, (duk_hobject *) func); |
| 65181 | if (formals) { |
| 65182 | n_formals = (duk_idx_t) ((duk_harray *) formals)->length; |
| 65183 | duk_push_hobject(thr, formals); |
| 65184 | } else { |
| 65185 | /* This shouldn't happen without tampering of internal |
| 65186 | * properties: if a function accesses 'arguments', _Formals |
| 65187 | * is kept. Check for the case anyway in case internal |
| 65188 | * properties have been modified manually. |
| 65189 | */ |
| 65190 | DUK_D(DUK_DPRINT("_Formals is undefined when creating arguments, use n_formals == 0" )); |
| 65191 | n_formals = 0; |
| 65192 | duk_push_undefined(thr); |
| 65193 | } |
| 65194 | i_formals = duk_require_top_index(thr); |
| 65195 | |
| 65196 | DUK_ASSERT(n_formals >= 0); |
| 65197 | DUK_ASSERT(formals != NULL || n_formals == 0); |
| 65198 | |
| 65199 | DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld" , |
| 65200 | (duk_heaphdr *) func, (duk_heaphdr *) formals, |
| 65201 | (long) n_formals)); |
| 65202 | |
| 65203 | /* [ ... formals ] */ |
| 65204 | |
| 65205 | /* |
| 65206 | * Create required objects: |
| 65207 | * - 'arguments' object: array-like, but not an array |
| 65208 | * - 'map' object: internal object, tied to 'arguments' (bare) |
| 65209 | * - 'mappedNames' object: temporary value used during construction (bare) |
| 65210 | */ |
| 65211 | |
| 65212 | arg = duk_push_object_helper(thr, |
| 65213 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 65214 | DUK_HOBJECT_FLAG_FASTREFS | |
| 65215 | DUK_HOBJECT_FLAG_ARRAY_PART | |
| 65216 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS), |
| 65217 | DUK_BIDX_OBJECT_PROTOTYPE); |
| 65218 | DUK_ASSERT(arg != NULL); |
| 65219 | (void) duk_push_object_helper(thr, |
| 65220 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 65221 | DUK_HOBJECT_FLAG_FASTREFS | |
| 65222 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), |
| 65223 | -1); /* no prototype */ |
| 65224 | (void) duk_push_object_helper(thr, |
| 65225 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 65226 | DUK_HOBJECT_FLAG_FASTREFS | |
| 65227 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT), |
| 65228 | -1); /* no prototype */ |
| 65229 | i_arg = duk_get_top(thr) - 3; |
| 65230 | i_map = i_arg + 1; |
| 65231 | i_mappednames = i_arg + 2; |
| 65232 | DUK_ASSERT(!duk_is_bare_object(thr, -3)); /* arguments */ |
| 65233 | DUK_ASSERT(duk_is_bare_object(thr, -2)); /* map */ |
| 65234 | DUK_ASSERT(duk_is_bare_object(thr, -1)); /* mappedNames */ |
| 65235 | |
| 65236 | /* [ ... formals arguments map mappedNames ] */ |
| 65237 | |
| 65238 | DUK_DDD(DUK_DDDPRINT("created arguments related objects: " |
| 65239 | "arguments at index %ld -> %!O " |
| 65240 | "map at index %ld -> %!O " |
| 65241 | "mappednames at index %ld -> %!O" , |
| 65242 | (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg), |
| 65243 | (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map), |
| 65244 | (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames))); |
| 65245 | |
| 65246 | /* |
| 65247 | * Init arguments properties, map, etc. |
| 65248 | */ |
| 65249 | |
| 65250 | duk_push_int(thr, num_stack_args); |
| 65251 | duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC); |
| 65252 | |
| 65253 | /* |
| 65254 | * Init argument related properties. |
| 65255 | */ |
| 65256 | |
| 65257 | /* step 11 */ |
| 65258 | idx = num_stack_args - 1; |
| 65259 | while (idx >= 0) { |
| 65260 | DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld" , |
| 65261 | (long) idx, (long) i_argbase, (long) (i_argbase + idx))); |
| 65262 | |
| 65263 | DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg" , (long) idx)); |
| 65264 | duk_dup(thr, i_argbase + idx); |
| 65265 | duk_xdef_prop_index_wec(thr, i_arg, (duk_uarridx_t) idx); |
| 65266 | DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg" , (long) idx)); |
| 65267 | |
| 65268 | /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */ |
| 65269 | if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) { |
| 65270 | DUK_ASSERT(formals != NULL); |
| 65271 | |
| 65272 | DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)" , |
| 65273 | (long) idx, (long) n_formals)); |
| 65274 | |
| 65275 | duk_get_prop_index(thr, i_formals, (duk_uarridx_t) idx); |
| 65276 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 65277 | |
| 65278 | duk_dup_top(thr); /* [ ... name name ] */ |
| 65279 | |
| 65280 | if (!duk_has_prop(thr, i_mappednames)) { |
| 65281 | /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping |
| 65282 | * differs from the reference model |
| 65283 | */ |
| 65284 | |
| 65285 | /* [ ... name ] */ |
| 65286 | |
| 65287 | need_map = 1; |
| 65288 | |
| 65289 | DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld" , |
| 65290 | (const char *) duk_get_string(thr, -1), |
| 65291 | (long) idx)); |
| 65292 | duk_dup_top(thr); /* name */ |
| 65293 | (void) duk_push_uint_to_hstring(thr, (duk_uint_t) idx); /* index */ |
| 65294 | duk_xdef_prop_wec(thr, i_mappednames); /* out of spec, must be configurable */ |
| 65295 | |
| 65296 | DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s" , |
| 65297 | (long) idx, |
| 65298 | duk_get_string(thr, -1))); |
| 65299 | duk_dup_top(thr); /* name */ |
| 65300 | duk_xdef_prop_index_wec(thr, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */ |
| 65301 | } else { |
| 65302 | /* duk_has_prop() popped the second 'name' */ |
| 65303 | } |
| 65304 | |
| 65305 | /* [ ... name ] */ |
| 65306 | duk_pop(thr); /* pop 'name' */ |
| 65307 | } |
| 65308 | |
| 65309 | idx--; |
| 65310 | } |
| 65311 | |
| 65312 | DUK_DDD(DUK_DDDPRINT("actual arguments processed" )); |
| 65313 | |
| 65314 | /* step 12 */ |
| 65315 | if (need_map) { |
| 65316 | DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object" )); |
| 65317 | |
| 65318 | /* should never happen for a strict callee */ |
| 65319 | DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func)); |
| 65320 | |
| 65321 | duk_dup(thr, i_map); |
| 65322 | duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */ |
| 65323 | |
| 65324 | /* The variable environment for magic variable bindings needs to be |
| 65325 | * given by the caller and recorded in the arguments object. |
| 65326 | * |
| 65327 | * See E5 Section 10.6, the creation of setters/getters. |
| 65328 | * |
| 65329 | * The variable environment also provides access to the callee, so |
| 65330 | * an explicit (internal) callee property is not needed. |
| 65331 | */ |
| 65332 | |
| 65333 | duk_push_hobject(thr, varenv); |
| 65334 | duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */ |
| 65335 | } |
| 65336 | |
| 65337 | /* steps 13-14 */ |
| 65338 | if (DUK_HOBJECT_HAS_STRICT(func)) { |
| 65339 | /* Callee/caller are throwers and are not deletable etc. They |
| 65340 | * could be implemented as virtual properties, but currently |
| 65341 | * there is no support for virtual properties which are accessors |
| 65342 | * (only plain virtual properties). This would not be difficult |
| 65343 | * to change in duk_hobject_props, but we can make the throwers |
| 65344 | * normal, concrete properties just as easily. |
| 65345 | * |
| 65346 | * Note that the specification requires that the *same* thrower |
| 65347 | * built-in object is used here! See E5 Section 10.6 main |
| 65348 | * algoritm, step 14, and Section 13.2.3 which describes the |
| 65349 | * thrower. See test case test-arguments-throwers.js. |
| 65350 | */ |
| 65351 | |
| 65352 | DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers" )); |
| 65353 | |
| 65354 | /* In ES2017 .caller is no longer set at all. */ |
| 65355 | duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLEE); |
| 65356 | } else { |
| 65357 | DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value" )); |
| 65358 | duk_push_hobject(thr, func); |
| 65359 | duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC); |
| 65360 | } |
| 65361 | |
| 65362 | /* set exotic behavior only after we're done */ |
| 65363 | if (need_map) { |
| 65364 | /* Exotic behaviors are only enabled for arguments objects |
| 65365 | * which have a parameter map (see E5 Section 10.6 main |
| 65366 | * algorithm, step 12). |
| 65367 | * |
| 65368 | * In particular, a non-strict arguments object with no |
| 65369 | * mapped formals does *NOT* get exotic behavior, even |
| 65370 | * for e.g. "caller" property. This seems counterintuitive |
| 65371 | * but seems to be the case. |
| 65372 | */ |
| 65373 | |
| 65374 | /* cannot be strict (never mapped variables) */ |
| 65375 | DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func)); |
| 65376 | |
| 65377 | DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object" )); |
| 65378 | DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg); |
| 65379 | } else { |
| 65380 | DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object" )); |
| 65381 | } |
| 65382 | |
| 65383 | DUK_DDD(DUK_DDDPRINT("final arguments related objects: " |
| 65384 | "arguments at index %ld -> %!O " |
| 65385 | "map at index %ld -> %!O " |
| 65386 | "mappednames at index %ld -> %!O" , |
| 65387 | (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg), |
| 65388 | (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map), |
| 65389 | (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames))); |
| 65390 | |
| 65391 | /* [ args(n) envobj formals arguments map mappednames ] */ |
| 65392 | |
| 65393 | duk_pop_2(thr); |
| 65394 | duk_remove_m2(thr); |
| 65395 | |
| 65396 | /* [ args(n) envobj arguments ] */ |
| 65397 | } |
| 65398 | |
| 65399 | /* Helper for creating the arguments object and adding it to the env record |
| 65400 | * on top of the value stack. |
| 65401 | */ |
| 65402 | DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr, |
| 65403 | duk_hobject *func, |
| 65404 | duk_hobject *env, |
| 65405 | duk_idx_t idx_args) { |
| 65406 | DUK_DDD(DUK_DDDPRINT("creating arguments object for function call" )); |
| 65407 | |
| 65408 | DUK_ASSERT(thr != NULL); |
| 65409 | DUK_ASSERT(func != NULL); |
| 65410 | DUK_ASSERT(env != NULL); |
| 65411 | DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func)); |
| 65412 | |
| 65413 | /* [ ... arg1 ... argN envobj ] */ |
| 65414 | |
| 65415 | duk__create_arguments_object(thr, |
| 65416 | func, |
| 65417 | env, |
| 65418 | idx_args); |
| 65419 | |
| 65420 | /* [ ... arg1 ... argN envobj argobj ] */ |
| 65421 | |
| 65422 | duk_xdef_prop_stridx_short(thr, |
| 65423 | -2, |
| 65424 | DUK_STRIDX_LC_ARGUMENTS, |
| 65425 | DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */ |
| 65426 | DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */ |
| 65427 | /* [ ... arg1 ... argN envobj ] */ |
| 65428 | } |
| 65429 | |
| 65430 | /* |
| 65431 | * Helpers for constructor call handling. |
| 65432 | * |
| 65433 | * There are two [[Construct]] operations in the specification: |
| 65434 | * |
| 65435 | * - E5 Section 13.2.2: for Function objects |
| 65436 | * - E5 Section 15.3.4.5.2: for "bound" Function objects |
| 65437 | * |
| 65438 | * The chain of bound functions is resolved in Section 15.3.4.5.2, |
| 65439 | * with arguments "piling up" until the [[Construct]] internal |
| 65440 | * method is called on the final, actual Function object. Note |
| 65441 | * that the "prototype" property is looked up *only* from the |
| 65442 | * final object, *before* calling the constructor. |
| 65443 | * |
| 65444 | * Since Duktape 2.2 bound functions are represented with the |
| 65445 | * duk_hboundfunc internal type, and bound function chains are |
| 65446 | * collapsed when a bound function is created. As a result, the |
| 65447 | * direct target of a duk_hboundfunc is always non-bound and the |
| 65448 | * this/argument lists have been resolved. |
| 65449 | * |
| 65450 | * When constructing new Array instances, an unnecessary object is |
| 65451 | * created and discarded now: the standard [[Construct]] creates an |
| 65452 | * object, and calls the Array constructor. The Array constructor |
| 65453 | * returns an Array instance, which is used as the result value for |
| 65454 | * the "new" operation; the object created before the Array constructor |
| 65455 | * call is discarded. |
| 65456 | * |
| 65457 | * This would be easy to fix, e.g. by knowing that the Array constructor |
| 65458 | * will always create a replacement object and skip creating the fallback |
| 65459 | * object in that case. |
| 65460 | */ |
| 65461 | |
| 65462 | /* Update default instance prototype for constructor call. */ |
| 65463 | DUK_LOCAL void duk__update_default_instance_proto(duk_hthread *thr, duk_idx_t idx_func) { |
| 65464 | duk_hobject *proto; |
| 65465 | duk_hobject *fallback; |
| 65466 | |
| 65467 | DUK_ASSERT(duk_is_constructable(thr, idx_func)); |
| 65468 | |
| 65469 | duk_get_prop_stridx_short(thr, idx_func, DUK_STRIDX_PROTOTYPE); |
| 65470 | proto = duk_get_hobject(thr, -1); |
| 65471 | if (proto == NULL) { |
| 65472 | DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object " |
| 65473 | "-> leave standard Object prototype as fallback prototype" )); |
| 65474 | } else { |
| 65475 | DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value " |
| 65476 | "-> set fallback prototype to that value: %!iO" , (duk_heaphdr *) proto)); |
| 65477 | /* Original fallback (default instance) is untouched when |
| 65478 | * resolving bound functions etc. |
| 65479 | */ |
| 65480 | fallback = duk_known_hobject(thr, idx_func + 1); |
| 65481 | DUK_ASSERT(fallback != NULL); |
| 65482 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto); |
| 65483 | } |
| 65484 | duk_pop(thr); |
| 65485 | } |
| 65486 | |
| 65487 | /* Postprocess: return value special handling, error augmentation. */ |
| 65488 | DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant) { |
| 65489 | /* Use either fallback (default instance) or retval depending |
| 65490 | * on retval type. Needs to be called before unwind because |
| 65491 | * the default instance is read from the current (immutable) |
| 65492 | * 'this' binding. |
| 65493 | * |
| 65494 | * For Proxy 'construct' calls the return value must be an |
| 65495 | * Object (we accept object-like values like buffers and |
| 65496 | * lightfuncs too). If not, TypeError. |
| 65497 | */ |
| 65498 | if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | |
| 65499 | DUK_TYPE_MASK_BUFFER | |
| 65500 | DUK_TYPE_MASK_LIGHTFUNC)) { |
| 65501 | DUK_DDD(DUK_DDDPRINT("replacement value" )); |
| 65502 | } else { |
| 65503 | if (DUK_UNLIKELY(proxy_invariant != 0U)) { |
| 65504 | /* Proxy 'construct' return value invariant violated. */ |
| 65505 | DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr); |
| 65506 | DUK_WO_NORETURN(return;); |
| 65507 | } |
| 65508 | /* XXX: direct value stack access */ |
| 65509 | duk_pop(thr); |
| 65510 | duk_push_this(thr); |
| 65511 | } |
| 65512 | |
| 65513 | #if defined(DUK_USE_AUGMENT_ERROR_CREATE) |
| 65514 | /* Augment created errors upon creation, not when they are thrown or |
| 65515 | * rethrown. __FILE__ and __LINE__ are not desirable here; the call |
| 65516 | * stack reflects the caller which is correct. Skip topmost, unwound |
| 65517 | * activation when creating a traceback. If thr->ptr_curr_pc was != |
| 65518 | * NULL we'd need to sync the current PC so that the traceback comes |
| 65519 | * out right; however it is always synced here so just assert for it. |
| 65520 | */ |
| 65521 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 65522 | duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE | |
| 65523 | DUK_AUGMENT_FLAG_SKIP_ONE); |
| 65524 | #endif |
| 65525 | } |
| 65526 | |
| 65527 | /* |
| 65528 | * Helper for handling a bound function when a call is being made. |
| 65529 | * |
| 65530 | * Assumes that bound function chains have been "collapsed" so that either |
| 65531 | * the target is non-bound or there is one bound function that points to a |
| 65532 | * nonbound target. |
| 65533 | * |
| 65534 | * Prepends the bound arguments to the value stack (at idx_func + 2). |
| 65535 | * The 'this' binding is also updated if necessary (at idx_func + 1). |
| 65536 | * Note that for constructor calls the 'this' binding is never updated by |
| 65537 | * [[BoundThis]]. |
| 65538 | */ |
| 65539 | |
| 65540 | DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr, |
| 65541 | duk_idx_t idx_func, |
| 65542 | duk_bool_t is_constructor_call) { |
| 65543 | duk_tval *tv_func; |
| 65544 | duk_hobject *func; |
| 65545 | duk_idx_t len; |
| 65546 | |
| 65547 | DUK_ASSERT(thr != NULL); |
| 65548 | |
| 65549 | /* On entry, item at idx_func is a bound, non-lightweight function, |
| 65550 | * but we don't rely on that below. |
| 65551 | */ |
| 65552 | |
| 65553 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 65554 | |
| 65555 | tv_func = duk_require_tval(thr, idx_func); |
| 65556 | DUK_ASSERT(tv_func != NULL); |
| 65557 | |
| 65558 | if (DUK_TVAL_IS_OBJECT(tv_func)) { |
| 65559 | func = DUK_TVAL_GET_OBJECT(tv_func); |
| 65560 | |
| 65561 | /* XXX: separate helper function, out of fast path? */ |
| 65562 | if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) { |
| 65563 | duk_hboundfunc *h_bound; |
| 65564 | duk_tval *tv_args; |
| 65565 | duk_tval *tv_gap; |
| 65566 | |
| 65567 | h_bound = (duk_hboundfunc *) (void *) func; |
| 65568 | tv_args = h_bound->args; |
| 65569 | len = h_bound->nargs; |
| 65570 | DUK_ASSERT(len == 0 || tv_args != NULL); |
| 65571 | |
| 65572 | DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p: %!T" , |
| 65573 | (void *) DUK_TVAL_GET_OBJECT(tv_func), tv_func)); |
| 65574 | |
| 65575 | /* [ ... func this arg1 ... argN ] */ |
| 65576 | |
| 65577 | if (is_constructor_call) { |
| 65578 | /* See: tests/ecmascript/test-spec-bound-constructor.js */ |
| 65579 | DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding" )); |
| 65580 | } else { |
| 65581 | /* XXX: duk_replace_tval */ |
| 65582 | duk_push_tval(thr, &h_bound->this_binding); |
| 65583 | duk_replace(thr, idx_func + 1); /* idx_this = idx_func + 1 */ |
| 65584 | } |
| 65585 | |
| 65586 | /* [ ... func this arg1 ... argN ] */ |
| 65587 | |
| 65588 | duk_require_stack(thr, len); |
| 65589 | |
| 65590 | tv_gap = duk_reserve_gap(thr, idx_func + 2, len); |
| 65591 | duk_copy_tvals_incref(thr, tv_gap, tv_args, (duk_size_t) len); |
| 65592 | |
| 65593 | /* [ ... func this <bound args> arg1 ... argN ] */ |
| 65594 | |
| 65595 | duk_push_tval(thr, &h_bound->target); |
| 65596 | duk_replace(thr, idx_func); /* replace in stack */ |
| 65597 | |
| 65598 | DUK_DDD(DUK_DDDPRINT("bound function handled, idx_func=%ld, curr func=%!T" , |
| 65599 | (long) idx_func, duk_get_tval(thr, idx_func))); |
| 65600 | } |
| 65601 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) { |
| 65602 | /* Lightweight function: never bound, so terminate. */ |
| 65603 | ; |
| 65604 | } else { |
| 65605 | /* Shouldn't happen, so ugly error is enough. */ |
| 65606 | DUK_ERROR_INTERNAL(thr); |
| 65607 | DUK_WO_NORETURN(return;); |
| 65608 | } |
| 65609 | |
| 65610 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 65611 | |
| 65612 | DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T" , duk_get_tval(thr, idx_func))); |
| 65613 | |
| 65614 | #if defined(DUK_USE_ASSERTIONS) |
| 65615 | tv_func = duk_require_tval(thr, idx_func); |
| 65616 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func)); |
| 65617 | if (DUK_TVAL_IS_OBJECT(tv_func)) { |
| 65618 | func = DUK_TVAL_GET_OBJECT(tv_func); |
| 65619 | DUK_ASSERT(func != NULL); |
| 65620 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); |
| 65621 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func) || |
| 65622 | DUK_HOBJECT_HAS_NATFUNC(func) || |
| 65623 | DUK_HOBJECT_IS_PROXY(func)); |
| 65624 | } |
| 65625 | #endif |
| 65626 | } |
| 65627 | |
| 65628 | /* |
| 65629 | * Helper for inline handling of .call(), .apply(), and .construct(). |
| 65630 | */ |
| 65631 | |
| 65632 | DUK_LOCAL duk_bool_t duk__handle_specialfuncs_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hobject *func, duk_small_uint_t *call_flags, duk_bool_t first) { |
| 65633 | #if defined(DUK_USE_ASSERTIONS) |
| 65634 | duk_c_function natfunc; |
| 65635 | #endif |
| 65636 | duk_tval *tv_args; |
| 65637 | |
| 65638 | DUK_ASSERT(func != NULL); |
| 65639 | DUK_ASSERT((*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0); /* Caller. */ |
| 65640 | |
| 65641 | #if defined(DUK_USE_ASSERTIONS) |
| 65642 | natfunc = ((duk_hnatfunc *) func)->func; |
| 65643 | DUK_ASSERT(natfunc != NULL); |
| 65644 | #endif |
| 65645 | |
| 65646 | /* On every round of function resolution at least target function and |
| 65647 | * 'this' binding are set. We can assume that here, and must guarantee |
| 65648 | * it on exit. Value stack reserve is extended for bound function and |
| 65649 | * .apply() unpacking so we don't need to extend it here when we need a |
| 65650 | * few slots. |
| 65651 | */ |
| 65652 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 65653 | |
| 65654 | /* Handle native 'eval' specially. A direct eval check is only made |
| 65655 | * for the first resolution attempt; e.g. a bound eval call is -not- |
| 65656 | * a direct eval call. |
| 65657 | */ |
| 65658 | if (DUK_UNLIKELY(((duk_hnatfunc *) func)->magic == 15)) { |
| 65659 | /* For now no special handling except for direct eval |
| 65660 | * detection. |
| 65661 | */ |
| 65662 | DUK_ASSERT(((duk_hnatfunc *) func)->func == duk_bi_global_object_eval); |
| 65663 | if (first && (*call_flags & DUK_CALL_FLAG_CALLED_AS_EVAL)) { |
| 65664 | *call_flags = (*call_flags & ~DUK_CALL_FLAG_CALLED_AS_EVAL) | DUK_CALL_FLAG_DIRECT_EVAL; |
| 65665 | } |
| 65666 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 65667 | return 1; /* stop resolving */ |
| 65668 | } |
| 65669 | |
| 65670 | /* Handle special functions based on the DUK_HOBJECT_FLAG_SPECIAL_CALL |
| 65671 | * flag; their magic value is used for switch-case. |
| 65672 | * |
| 65673 | * NOTE: duk_unpack_array_like() reserves value stack space |
| 65674 | * for the result values (unlike most other value stack calls). |
| 65675 | */ |
| 65676 | switch (((duk_hnatfunc *) func)->magic) { |
| 65677 | case 0: { /* 0=Function.prototype.call() */ |
| 65678 | /* Value stack: |
| 65679 | * idx_func + 0: Function.prototype.call() [removed] |
| 65680 | * idx_func + 1: this binding for .call (target function) |
| 65681 | * idx_func + 2: 1st argument to .call, desired 'this' binding |
| 65682 | * idx_func + 3: 2nd argument to .call, desired 1st argument for ultimate target |
| 65683 | * ... |
| 65684 | * |
| 65685 | * Remove idx_func + 0 to get: |
| 65686 | * idx_func + 0: target function |
| 65687 | * idx_func + 1: this binding |
| 65688 | * idx_func + 2: call arguments |
| 65689 | * ... |
| 65690 | */ |
| 65691 | DUK_ASSERT(natfunc == duk_bi_function_prototype_call); |
| 65692 | duk_remove_unsafe(thr, idx_func); |
| 65693 | tv_args = thr->valstack_bottom + idx_func + 2; |
| 65694 | if (thr->valstack_top < tv_args) { |
| 65695 | DUK_ASSERT(tv_args <= thr->valstack_end); |
| 65696 | thr->valstack_top = tv_args; /* at least target function and 'this' binding present */ |
| 65697 | } |
| 65698 | break; |
| 65699 | } |
| 65700 | case 1: { /* 1=Function.prototype.apply() */ |
| 65701 | /* Value stack: |
| 65702 | * idx_func + 0: Function.prototype.apply() [removed] |
| 65703 | * idx_func + 1: this binding for .apply (target function) |
| 65704 | * idx_func + 2: 1st argument to .apply, desired 'this' binding |
| 65705 | * idx_func + 3: 2nd argument to .apply, argArray |
| 65706 | * [anything after this MUST be ignored] |
| 65707 | * |
| 65708 | * Remove idx_func + 0 and unpack the argArray to get: |
| 65709 | * idx_func + 0: target function |
| 65710 | * idx_func + 1: this binding |
| 65711 | * idx_func + 2: call arguments |
| 65712 | * ... |
| 65713 | */ |
| 65714 | DUK_ASSERT(natfunc == duk_bi_function_prototype_apply); |
| 65715 | duk_remove_unsafe(thr, idx_func); |
| 65716 | goto apply_shared; |
| 65717 | } |
| 65718 | #if defined(DUK_USE_REFLECT_BUILTIN) |
| 65719 | case 2: { /* 2=Reflect.apply() */ |
| 65720 | /* Value stack: |
| 65721 | * idx_func + 0: Reflect.apply() [removed] |
| 65722 | * idx_func + 1: this binding for .apply (ignored, usually Reflect) [removed] |
| 65723 | * idx_func + 2: 1st argument to .apply, target function |
| 65724 | * idx_func + 3: 2nd argument to .apply, desired 'this' binding |
| 65725 | * idx_func + 4: 3rd argument to .apply, argArray |
| 65726 | * [anything after this MUST be ignored] |
| 65727 | * |
| 65728 | * Remove idx_func + 0 and idx_func + 1, and unpack the argArray to get: |
| 65729 | * idx_func + 0: target function |
| 65730 | * idx_func + 1: this binding |
| 65731 | * idx_func + 2: call arguments |
| 65732 | * ... |
| 65733 | */ |
| 65734 | DUK_ASSERT(natfunc == duk_bi_reflect_apply); |
| 65735 | duk_remove_n_unsafe(thr, idx_func, 2); |
| 65736 | goto apply_shared; |
| 65737 | } |
| 65738 | case 3: { /* 3=Reflect.construct() */ |
| 65739 | /* Value stack: |
| 65740 | * idx_func + 0: Reflect.construct() [removed] |
| 65741 | * idx_func + 1: this binding for .construct (ignored, usually Reflect) [removed] |
| 65742 | * idx_func + 2: 1st argument to .construct, target function |
| 65743 | * idx_func + 3: 2nd argument to .construct, argArray |
| 65744 | * idx_func + 4: 3rd argument to .construct, newTarget |
| 65745 | * [anything after this MUST be ignored] |
| 65746 | * |
| 65747 | * Remove idx_func + 0 and idx_func + 1, unpack the argArray, |
| 65748 | * and insert default instance (prototype not yet updated), to get: |
| 65749 | * idx_func + 0: target function |
| 65750 | * idx_func + 1: this binding (default instance) |
| 65751 | * idx_func + 2: constructor call arguments |
| 65752 | * ... |
| 65753 | * |
| 65754 | * Call flags must be updated to reflect the fact that we're |
| 65755 | * now dealing with a constructor call, and e.g. the 'this' |
| 65756 | * binding cannot be overwritten if the target is bound. |
| 65757 | * |
| 65758 | * newTarget is checked but not yet passed onwards. |
| 65759 | */ |
| 65760 | |
| 65761 | duk_idx_t top; |
| 65762 | |
| 65763 | DUK_ASSERT(natfunc == duk_bi_reflect_construct); |
| 65764 | *call_flags |= DUK_CALL_FLAG_CONSTRUCT; |
| 65765 | duk_remove_n_unsafe(thr, idx_func, 2); |
| 65766 | top = duk_get_top(thr); |
| 65767 | if (!duk_is_constructable(thr, idx_func)) { |
| 65768 | /* Target constructability must be checked before |
| 65769 | * unpacking argArray (which may cause side effects). |
| 65770 | * Just return; caller will throw the error. |
| 65771 | */ |
| 65772 | duk_set_top_unsafe(thr, idx_func + 2); /* satisfy asserts */ |
| 65773 | break; |
| 65774 | } |
| 65775 | duk_push_object(thr); |
| 65776 | duk_insert(thr, idx_func + 1); /* default instance */ |
| 65777 | |
| 65778 | /* [ ... func default_instance argArray newTarget? ] */ |
| 65779 | |
| 65780 | top = duk_get_top(thr); |
| 65781 | if (top < idx_func + 3) { |
| 65782 | /* argArray is a mandatory argument for Reflect.construct(). */ |
| 65783 | DUK_ERROR_TYPE_INVALID_ARGS(thr); |
| 65784 | DUK_WO_NORETURN(return 0;); |
| 65785 | } |
| 65786 | if (top > idx_func + 3) { |
| 65787 | if (!duk_strict_equals(thr, idx_func, idx_func + 3)) { |
| 65788 | /* XXX: [[Construct]] newTarget currently unsupported */ |
| 65789 | DUK_ERROR_UNSUPPORTED(thr); |
| 65790 | DUK_WO_NORETURN(return 0;); |
| 65791 | } |
| 65792 | duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */ |
| 65793 | } |
| 65794 | DUK_ASSERT(duk_get_top(thr) == idx_func + 3); |
| 65795 | DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2)); |
| 65796 | (void) duk_unpack_array_like(thr, idx_func + 2); /* XXX: should also remove target to be symmetric with duk_pack()? */ |
| 65797 | duk_remove(thr, idx_func + 2); |
| 65798 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 65799 | break; |
| 65800 | } |
| 65801 | #endif /* DUK_USE_REFLECT_BUILTIN */ |
| 65802 | default: { |
| 65803 | DUK_ASSERT(0); |
| 65804 | DUK_UNREACHABLE(); |
| 65805 | } |
| 65806 | } |
| 65807 | |
| 65808 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 65809 | return 0; /* keep resolving */ |
| 65810 | |
| 65811 | apply_shared: |
| 65812 | tv_args = thr->valstack_bottom + idx_func + 2; |
| 65813 | if (thr->valstack_top <= tv_args) { |
| 65814 | DUK_ASSERT(tv_args <= thr->valstack_end); |
| 65815 | thr->valstack_top = tv_args; /* at least target func and 'this' binding present */ |
| 65816 | /* No need to check for argArray. */ |
| 65817 | } else { |
| 65818 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 3); /* idx_func + 2 covered above */ |
| 65819 | if (thr->valstack_top > tv_args + 1) { |
| 65820 | duk_set_top_unsafe(thr, idx_func + 3); /* remove any args beyond argArray */ |
| 65821 | } |
| 65822 | DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2)); |
| 65823 | if (!duk_is_callable(thr, idx_func)) { |
| 65824 | /* Avoid unpack side effects if the target isn't callable. |
| 65825 | * Calling code will throw the actual error. |
| 65826 | */ |
| 65827 | } else { |
| 65828 | (void) duk_unpack_array_like(thr, idx_func + 2); |
| 65829 | duk_remove(thr, idx_func + 2); |
| 65830 | } |
| 65831 | } |
| 65832 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 65833 | return 0; /* keep resolving */ |
| 65834 | } |
| 65835 | |
| 65836 | /* |
| 65837 | * Helper for Proxy handling. |
| 65838 | */ |
| 65839 | |
| 65840 | #if defined(DUK_USE_ES6_PROXY) |
| 65841 | DUK_LOCAL void duk__handle_proxy_for_call(duk_hthread *thr, duk_idx_t idx_func, duk_hproxy *h_proxy, duk_small_uint_t *call_flags) { |
| 65842 | duk_bool_t rc; |
| 65843 | |
| 65844 | /* Value stack: |
| 65845 | * idx_func + 0: Proxy object |
| 65846 | * idx_func + 1: this binding for call |
| 65847 | * idx_func + 2: 1st argument for call |
| 65848 | * idx_func + 3: 2nd argument for call |
| 65849 | * ... |
| 65850 | * |
| 65851 | * If Proxy doesn't have a trap for the call ('apply' or 'construct'), |
| 65852 | * replace Proxy object with target object. |
| 65853 | * |
| 65854 | * If we're dealing with a normal call and the Proxy has an 'apply' |
| 65855 | * trap, manipulate value stack to: |
| 65856 | * |
| 65857 | * idx_func + 0: trap |
| 65858 | * idx_func + 1: Proxy's handler |
| 65859 | * idx_func + 2: Proxy's target |
| 65860 | * idx_func + 3: this binding for call (from idx_func + 1) |
| 65861 | * idx_func + 4: call arguments packed to an array |
| 65862 | * |
| 65863 | * If we're dealing with a constructor call and the Proxy has a |
| 65864 | * 'construct' trap, manipulate value stack to: |
| 65865 | * |
| 65866 | * idx_func + 0: trap |
| 65867 | * idx_func + 1: Proxy's handler |
| 65868 | * idx_func + 2: Proxy's target |
| 65869 | * idx_func + 3: call arguments packed to an array |
| 65870 | * idx_func + 4: newTarget == Proxy object here |
| 65871 | * |
| 65872 | * As we don't yet have proper newTarget support, the newTarget at |
| 65873 | * idx_func + 3 is just the original constructor being called, i.e. |
| 65874 | * the Proxy object (not the target). Note that the default instance |
| 65875 | * (original 'this' binding) is dropped and ignored. |
| 65876 | */ |
| 65877 | |
| 65878 | duk_push_hobject(thr, h_proxy->handler); |
| 65879 | rc = duk_get_prop_stridx_short(thr, -1, (*call_flags & DUK_CALL_FLAG_CONSTRUCT) ? DUK_STRIDX_CONSTRUCT : DUK_STRIDX_APPLY); |
| 65880 | if (rc == 0) { |
| 65881 | /* Not found, continue to target. If this is a construct |
| 65882 | * call, update default instance prototype using the Proxy, |
| 65883 | * not the target. |
| 65884 | */ |
| 65885 | if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { |
| 65886 | if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) { |
| 65887 | *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED; |
| 65888 | duk__update_default_instance_proto(thr, idx_func); |
| 65889 | } |
| 65890 | } |
| 65891 | duk_pop_2(thr); |
| 65892 | duk_push_hobject(thr, h_proxy->target); |
| 65893 | duk_replace(thr, idx_func); |
| 65894 | return; |
| 65895 | } |
| 65896 | |
| 65897 | /* Here we must be careful not to replace idx_func while |
| 65898 | * h_proxy is still needed, otherwise h_proxy may become |
| 65899 | * dangling. This could be improved e.g. using a |
| 65900 | * duk_pack_slice() with a freeform slice. |
| 65901 | */ |
| 65902 | |
| 65903 | /* Here: |
| 65904 | * idx_func + 0: Proxy object |
| 65905 | * idx_func + 1: this binding for call |
| 65906 | * idx_func + 2: 1st argument for call |
| 65907 | * idx_func + 3: 2nd argument for call |
| 65908 | * ... |
| 65909 | * idx_func + N: handler |
| 65910 | * idx_func + N + 1: trap |
| 65911 | */ |
| 65912 | |
| 65913 | duk_insert(thr, idx_func + 1); |
| 65914 | duk_insert(thr, idx_func + 2); |
| 65915 | duk_push_hobject(thr, h_proxy->target); |
| 65916 | duk_insert(thr, idx_func + 3); |
| 65917 | duk_pack(thr, duk_get_top(thr) - (idx_func + 5)); |
| 65918 | DUK_ASSERT(!duk_is_bare_object(thr, -1)); |
| 65919 | |
| 65920 | /* Here: |
| 65921 | * idx_func + 0: Proxy object |
| 65922 | * idx_func + 1: trap |
| 65923 | * idx_func + 2: Proxy's handler |
| 65924 | * idx_func + 3: Proxy's target |
| 65925 | * idx_func + 4: this binding for call |
| 65926 | * idx_func + 5: arguments array |
| 65927 | */ |
| 65928 | DUK_ASSERT(duk_get_top(thr) == idx_func + 6); |
| 65929 | |
| 65930 | if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { |
| 65931 | *call_flags |= DUK_CALL_FLAG_CONSTRUCT_PROXY; /* Enable 'construct' trap return invariant check. */ |
| 65932 | *call_flags &= ~(DUK_CALL_FLAG_CONSTRUCT); /* Resume as non-constructor call to the trap. */ |
| 65933 | |
| 65934 | /* 'apply' args: target, thisArg, argArray |
| 65935 | * 'construct' args: target, argArray, newTarget |
| 65936 | */ |
| 65937 | duk_remove(thr, idx_func + 4); |
| 65938 | duk_push_hobject(thr, (duk_hobject *) h_proxy); |
| 65939 | } |
| 65940 | |
| 65941 | /* Finalize value stack layout by removing Proxy reference. */ |
| 65942 | duk_remove(thr, idx_func); |
| 65943 | h_proxy = NULL; /* invalidated */ |
| 65944 | DUK_ASSERT(duk_get_top(thr) == idx_func + 5); |
| 65945 | } |
| 65946 | #endif /* DUK_USE_ES6_PROXY */ |
| 65947 | |
| 65948 | /* |
| 65949 | * Helper for setting up var_env and lex_env of an activation, |
| 65950 | * assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag. |
| 65951 | */ |
| 65952 | |
| 65953 | DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr, |
| 65954 | duk_hobject *func, |
| 65955 | duk_activation *act) { |
| 65956 | duk_hcompfunc *f; |
| 65957 | duk_hobject *h_lex; |
| 65958 | duk_hobject *h_var; |
| 65959 | |
| 65960 | DUK_ASSERT(thr != NULL); |
| 65961 | DUK_ASSERT(func != NULL); |
| 65962 | DUK_ASSERT(act != NULL); |
| 65963 | DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func)); |
| 65964 | DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); |
| 65965 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func)); |
| 65966 | DUK_UNREF(thr); |
| 65967 | |
| 65968 | f = (duk_hcompfunc *) func; |
| 65969 | h_lex = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f); |
| 65970 | h_var = DUK_HCOMPFUNC_GET_VARENV(thr->heap, f); |
| 65971 | DUK_ASSERT(h_lex != NULL); /* Always true for closures (not for templates) */ |
| 65972 | DUK_ASSERT(h_var != NULL); |
| 65973 | act->lex_env = h_lex; |
| 65974 | act->var_env = h_var; |
| 65975 | DUK_HOBJECT_INCREF(thr, h_lex); |
| 65976 | DUK_HOBJECT_INCREF(thr, h_var); |
| 65977 | } |
| 65978 | |
| 65979 | /* |
| 65980 | * Helper for updating callee 'caller' property. |
| 65981 | */ |
| 65982 | |
| 65983 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 65984 | DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) { |
| 65985 | duk_tval *tv_caller; |
| 65986 | duk_hobject *h_tmp; |
| 65987 | duk_activation *act_callee; |
| 65988 | duk_activation *act_caller; |
| 65989 | |
| 65990 | DUK_ASSERT(thr != NULL); |
| 65991 | DUK_ASSERT(func != NULL); |
| 65992 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound chain resolved */ |
| 65993 | DUK_ASSERT(thr->callstack_top >= 1); |
| 65994 | |
| 65995 | if (DUK_HOBJECT_HAS_STRICT(func)) { |
| 65996 | /* Strict functions don't get their 'caller' updated. */ |
| 65997 | return; |
| 65998 | } |
| 65999 | |
| 66000 | DUK_ASSERT(thr->callstack_top > 0); |
| 66001 | act_callee = thr->callstack_curr; |
| 66002 | DUK_ASSERT(act_callee != NULL); |
| 66003 | act_caller = (thr->callstack_top >= 2 ? act_callee->parent : NULL); |
| 66004 | |
| 66005 | /* XXX: check .caller writability? */ |
| 66006 | |
| 66007 | /* Backup 'caller' property and update its value. */ |
| 66008 | tv_caller = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, func, DUK_STRIDX_CALLER); |
| 66009 | if (tv_caller) { |
| 66010 | /* If caller is global/eval code, 'caller' should be set to |
| 66011 | * 'null'. |
| 66012 | * |
| 66013 | * XXX: there is no exotic flag to infer this correctly now. |
| 66014 | * The NEWENV flag is used now which works as intended for |
| 66015 | * everything (global code, non-strict eval code, and functions) |
| 66016 | * except strict eval code. Bound functions are never an issue |
| 66017 | * because 'func' has been resolved to a non-bound function. |
| 66018 | */ |
| 66019 | |
| 66020 | if (act_caller != NULL) { |
| 66021 | /* act_caller->func may be NULL in some finalization cases, |
| 66022 | * just treat like we don't know the caller. |
| 66023 | */ |
| 66024 | if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) { |
| 66025 | /* Setting to NULL causes 'caller' to be set to |
| 66026 | * 'null' as desired. |
| 66027 | */ |
| 66028 | act_caller = NULL; |
| 66029 | } |
| 66030 | } |
| 66031 | |
| 66032 | if (DUK_TVAL_IS_OBJECT(tv_caller)) { |
| 66033 | h_tmp = DUK_TVAL_GET_OBJECT(tv_caller); |
| 66034 | DUK_ASSERT(h_tmp != NULL); |
| 66035 | act_callee->prev_caller = h_tmp; |
| 66036 | |
| 66037 | /* Previous value doesn't need refcount changes because its ownership |
| 66038 | * is transferred to prev_caller. |
| 66039 | */ |
| 66040 | |
| 66041 | if (act_caller != NULL) { |
| 66042 | DUK_ASSERT(act_caller->func != NULL); |
| 66043 | DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func); |
| 66044 | DUK_TVAL_INCREF(thr, tv_caller); |
| 66045 | } else { |
| 66046 | DUK_TVAL_SET_NULL(tv_caller); /* no incref */ |
| 66047 | } |
| 66048 | } else { |
| 66049 | /* 'caller' must only take on 'null' or function value */ |
| 66050 | DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller)); |
| 66051 | DUK_ASSERT(act_callee->prev_caller == NULL); |
| 66052 | if (act_caller != NULL && act_caller->func) { |
| 66053 | /* Tolerate act_caller->func == NULL which happens in |
| 66054 | * some finalization cases; treat like unknown caller. |
| 66055 | */ |
| 66056 | DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func); |
| 66057 | DUK_TVAL_INCREF(thr, tv_caller); |
| 66058 | } else { |
| 66059 | DUK_TVAL_SET_NULL(tv_caller); /* no incref */ |
| 66060 | } |
| 66061 | } |
| 66062 | } |
| 66063 | } |
| 66064 | #endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */ |
| 66065 | |
| 66066 | /* |
| 66067 | * Shared helpers for resolving the final, non-bound target function of the |
| 66068 | * call and the effective 'this' binding. Resolves bound functions and |
| 66069 | * applies .call(), .apply(), and .construct() inline. |
| 66070 | * |
| 66071 | * Proxy traps are also handled inline so that if the target is a Proxy with |
| 66072 | * a 'call' or 'construct' trap, the trap handler is called with a modified |
| 66073 | * argument list. |
| 66074 | * |
| 66075 | * Once the bound function / .call() / .apply() / .construct() sequence has |
| 66076 | * been resolved, the value at idx_func + 1 may need coercion described in |
| 66077 | * E5 Section 10.4.3. |
| 66078 | * |
| 66079 | * A call that begins as a non-constructor call may be converted into a |
| 66080 | * constructor call during the resolution process if Reflect.construct() |
| 66081 | * is invoked. This is handled by updating the caller's call_flags. |
| 66082 | * |
| 66083 | * For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume |
| 66084 | * that the caller has provided the correct 'this' binding explicitly |
| 66085 | * when calling, i.e.: |
| 66086 | * |
| 66087 | * - global code: this=global object |
| 66088 | * - direct eval: this=copy from eval() caller's this binding |
| 66089 | * - other eval: this=global object |
| 66090 | * |
| 66091 | * The 'this' coercion may cause a recursive function call with arbitrary |
| 66092 | * side effects, because ToObject() may be called. |
| 66093 | */ |
| 66094 | |
| 66095 | DUK_LOCAL DUK_INLINE void duk__coerce_nonstrict_this_binding(duk_hthread *thr, duk_idx_t idx_this) { |
| 66096 | duk_tval *tv_this; |
| 66097 | duk_hobject *obj_global; |
| 66098 | |
| 66099 | tv_this = thr->valstack_bottom + idx_this; |
| 66100 | switch (DUK_TVAL_GET_TAG(tv_this)) { |
| 66101 | case DUK_TAG_OBJECT: |
| 66102 | DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly" )); |
| 66103 | break; |
| 66104 | case DUK_TAG_UNDEFINED: |
| 66105 | case DUK_TAG_NULL: |
| 66106 | DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object" )); |
| 66107 | obj_global = thr->builtins[DUK_BIDX_GLOBAL]; |
| 66108 | /* XXX: avoid this check somehow */ |
| 66109 | if (DUK_LIKELY(obj_global != NULL)) { |
| 66110 | DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */ |
| 66111 | DUK_TVAL_SET_OBJECT(tv_this, obj_global); |
| 66112 | DUK_HOBJECT_INCREF(thr, obj_global); |
| 66113 | } else { |
| 66114 | /* This may only happen if built-ins are being "torn down". |
| 66115 | * This behavior is out of specification scope. |
| 66116 | */ |
| 66117 | DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead" )); |
| 66118 | DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */ |
| 66119 | DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */ |
| 66120 | } |
| 66121 | break; |
| 66122 | default: |
| 66123 | /* Plain buffers and lightfuncs are object coerced. Lightfuncs |
| 66124 | * very rarely come here however, because the call target would |
| 66125 | * need to be a non-strict non-lightfunc (lightfuncs are considered |
| 66126 | * strict) with an explicit lightfunc 'this' binding. |
| 66127 | */ |
| 66128 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this)); |
| 66129 | DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)" )); |
| 66130 | duk_to_object(thr, idx_this); /* may have side effects */ |
| 66131 | break; |
| 66132 | } |
| 66133 | } |
| 66134 | |
| 66135 | DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__resolve_target_fastpath_check(duk_hthread *thr, duk_idx_t idx_func, duk_hobject **out_func, duk_small_uint_t call_flags) { |
| 66136 | #if defined(DUK_USE_PREFER_SIZE) |
| 66137 | DUK_UNREF(thr); |
| 66138 | DUK_UNREF(idx_func); |
| 66139 | DUK_UNREF(out_func); |
| 66140 | DUK_UNREF(call_flags); |
| 66141 | #else /* DUK_USE_PREFER_SIZE */ |
| 66142 | duk_tval *tv_func; |
| 66143 | duk_hobject *func; |
| 66144 | |
| 66145 | if (DUK_UNLIKELY(call_flags & DUK_CALL_FLAG_CONSTRUCT)) { |
| 66146 | return 0; |
| 66147 | } |
| 66148 | |
| 66149 | tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func); |
| 66150 | DUK_ASSERT(tv_func != NULL); |
| 66151 | |
| 66152 | if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv_func))) { |
| 66153 | func = DUK_TVAL_GET_OBJECT(tv_func); |
| 66154 | if (DUK_HOBJECT_IS_CALLABLE(func) && |
| 66155 | !DUK_HOBJECT_HAS_BOUNDFUNC(func) && |
| 66156 | !DUK_HOBJECT_HAS_SPECIAL_CALL(func)) { |
| 66157 | *out_func = func; |
| 66158 | |
| 66159 | if (DUK_HOBJECT_HAS_STRICT(func)) { |
| 66160 | /* Strict function: no 'this' coercion. */ |
| 66161 | return 1; |
| 66162 | } |
| 66163 | |
| 66164 | duk__coerce_nonstrict_this_binding(thr, idx_func + 1); |
| 66165 | return 1; |
| 66166 | } |
| 66167 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) { |
| 66168 | *out_func = NULL; |
| 66169 | |
| 66170 | /* Lightfuncs are considered strict, so 'this' binding is |
| 66171 | * used as is. They're never bound, always constructable, |
| 66172 | * and never special functions. |
| 66173 | */ |
| 66174 | return 1; |
| 66175 | } |
| 66176 | #endif /* DUK_USE_PREFER_SIZE */ |
| 66177 | return 0; /* let slow path deal with it */ |
| 66178 | } |
| 66179 | |
| 66180 | DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *thr, |
| 66181 | duk_idx_t idx_func, |
| 66182 | duk_small_uint_t *call_flags) { |
| 66183 | duk_tval *tv_func; |
| 66184 | duk_hobject *func; |
| 66185 | duk_bool_t first; |
| 66186 | |
| 66187 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 66188 | |
| 66189 | for (first = 1;; first = 0) { |
| 66190 | DUK_ASSERT(duk_get_top(thr) >= idx_func + 2); |
| 66191 | |
| 66192 | tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func); |
| 66193 | DUK_ASSERT(tv_func != NULL); |
| 66194 | |
| 66195 | DUK_DD(DUK_DDPRINT("target func: %!iT" , tv_func)); |
| 66196 | |
| 66197 | if (DUK_TVAL_IS_OBJECT(tv_func)) { |
| 66198 | func = DUK_TVAL_GET_OBJECT(tv_func); |
| 66199 | |
| 66200 | if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { |
| 66201 | if (DUK_UNLIKELY(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func))) { |
| 66202 | goto not_constructable; |
| 66203 | } |
| 66204 | } else { |
| 66205 | if (DUK_UNLIKELY(!DUK_HOBJECT_IS_CALLABLE(func))) { |
| 66206 | goto not_callable; |
| 66207 | } |
| 66208 | } |
| 66209 | |
| 66210 | if (DUK_LIKELY(!DUK_HOBJECT_HAS_BOUNDFUNC(func) && |
| 66211 | !DUK_HOBJECT_HAS_SPECIAL_CALL(func) && |
| 66212 | !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func))) { |
| 66213 | /* Common case, so test for using a single bitfield test. |
| 66214 | * Break out to handle this coercion etc. |
| 66215 | */ |
| 66216 | break; |
| 66217 | } |
| 66218 | |
| 66219 | /* XXX: could set specialcall for boundfuncs too, simplify check above */ |
| 66220 | |
| 66221 | if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) { |
| 66222 | DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_CALL(func)); |
| 66223 | DUK_ASSERT(!DUK_HOBJECT_IS_NATFUNC(func)); |
| 66224 | |
| 66225 | /* Callable/constructable flags are the same |
| 66226 | * for the bound function and its target, so |
| 66227 | * we don't need to check them here, we can |
| 66228 | * check them from the target only. |
| 66229 | */ |
| 66230 | duk__handle_bound_chain_for_call(thr, idx_func, *call_flags & DUK_CALL_FLAG_CONSTRUCT); |
| 66231 | |
| 66232 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(thr, idx_func)) || |
| 66233 | DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(thr, idx_func))); |
| 66234 | } else { |
| 66235 | DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_CALL(func)); |
| 66236 | |
| 66237 | #if defined(DUK_USE_ES6_PROXY) |
| 66238 | if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func)) { |
| 66239 | /* If no trap, resume processing from Proxy trap. |
| 66240 | * If trap exists, helper converts call into a trap |
| 66241 | * call; this may change a constructor call into a |
| 66242 | * normal (non-constructor) trap call. We must |
| 66243 | * continue processing even when a trap is found as |
| 66244 | * the trap may be bound. |
| 66245 | */ |
| 66246 | duk__handle_proxy_for_call(thr, idx_func, (duk_hproxy *) func, call_flags); |
| 66247 | } |
| 66248 | else |
| 66249 | #endif |
| 66250 | { |
| 66251 | DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func)); |
| 66252 | DUK_ASSERT(DUK_HOBJECT_HAS_CALLABLE(func)); |
| 66253 | DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func)); |
| 66254 | /* Constructable check already done above. */ |
| 66255 | |
| 66256 | if (duk__handle_specialfuncs_for_call(thr, idx_func, func, call_flags, first) != 0) { |
| 66257 | /* Encountered native eval call, normal call |
| 66258 | * context. Break out, handle this coercion etc. |
| 66259 | */ |
| 66260 | break; |
| 66261 | } |
| 66262 | } |
| 66263 | } |
| 66264 | /* Retry loop. */ |
| 66265 | } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) { |
| 66266 | /* Lightfuncs are: |
| 66267 | * - Always strict, so no 'this' coercion. |
| 66268 | * - Always callable. |
| 66269 | * - Always constructable. |
| 66270 | * - Never specialfuncs. |
| 66271 | */ |
| 66272 | func = NULL; |
| 66273 | goto finished; |
| 66274 | } else { |
| 66275 | goto not_callable; |
| 66276 | } |
| 66277 | } |
| 66278 | |
| 66279 | DUK_ASSERT(func != NULL); |
| 66280 | |
| 66281 | if (!DUK_HOBJECT_HAS_STRICT(func)) { |
| 66282 | /* Non-strict target needs 'this' coercion. |
| 66283 | * This has potential side effects invalidating |
| 66284 | * 'tv_func'. |
| 66285 | */ |
| 66286 | duk__coerce_nonstrict_this_binding(thr, idx_func + 1); |
| 66287 | } |
| 66288 | if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) { |
| 66289 | if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) { |
| 66290 | *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED; |
| 66291 | duk__update_default_instance_proto(thr, idx_func); |
| 66292 | } |
| 66293 | } |
| 66294 | |
| 66295 | finished: |
| 66296 | |
| 66297 | #if defined(DUK_USE_ASSERTIONS) |
| 66298 | { |
| 66299 | duk_tval *tv_tmp; |
| 66300 | |
| 66301 | tv_tmp = duk_get_tval(thr, idx_func); |
| 66302 | DUK_ASSERT(tv_tmp != NULL); |
| 66303 | |
| 66304 | DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_tmp) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_tmp))) || |
| 66305 | DUK_TVAL_IS_LIGHTFUNC(tv_tmp)); |
| 66306 | DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); |
| 66307 | DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) || |
| 66308 | DUK_HOBJECT_IS_NATFUNC(func))); |
| 66309 | DUK_ASSERT(func == NULL || (DUK_HOBJECT_HAS_CONSTRUCTABLE(func) || |
| 66310 | (*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0)); |
| 66311 | } |
| 66312 | #endif |
| 66313 | |
| 66314 | return func; |
| 66315 | |
| 66316 | not_callable: |
| 66317 | DUK_ASSERT(tv_func != NULL); |
| 66318 | |
| 66319 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 66320 | /* GETPROPC delayed error handling: when target is not callable, |
| 66321 | * GETPROPC replaces idx_func+0 with a non-callable wrapper object |
| 66322 | * with a hidden Symbol to signify it's to be handled here. If |
| 66323 | * found, unwrap the original Error and throw it as is here. The |
| 66324 | * hidden Symbol is only checked as an own property, not inherited |
| 66325 | * (which would be dangerous). |
| 66326 | */ |
| 66327 | if (DUK_TVAL_IS_OBJECT(tv_func)) { |
| 66328 | duk_tval *tv_wrap = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_STRIDX_INT_TARGET); |
| 66329 | if (tv_wrap != NULL) { |
| 66330 | DUK_DD(DUK_DDPRINT("delayed error from GETPROPC: %!T" , tv_wrap)); |
| 66331 | duk_push_tval(thr, tv_wrap); |
| 66332 | (void) duk_throw(thr); |
| 66333 | DUK_WO_NORETURN(return NULL;); |
| 66334 | } |
| 66335 | } |
| 66336 | #endif |
| 66337 | |
| 66338 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 66339 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 66340 | DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable" , duk_get_type_name(thr, idx_func)); |
| 66341 | #else |
| 66342 | DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable" , duk_push_string_tval_readable(thr, tv_func)); |
| 66343 | #endif |
| 66344 | #else |
| 66345 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE); |
| 66346 | #endif |
| 66347 | DUK_WO_NORETURN(return NULL;); |
| 66348 | |
| 66349 | not_constructable: |
| 66350 | /* For now GETPROPC delayed error not needed for constructor calls. */ |
| 66351 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 66352 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 66353 | DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable" , duk_get_type_name(thr, idx_func)); |
| 66354 | #else |
| 66355 | DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable" , duk_push_string_tval_readable(thr, tv_func)); |
| 66356 | #endif |
| 66357 | #else |
| 66358 | DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE); |
| 66359 | #endif |
| 66360 | DUK_WO_NORETURN(return NULL;); |
| 66361 | } |
| 66362 | |
| 66363 | /* |
| 66364 | * Manipulate value stack so that exactly 'num_stack_rets' return |
| 66365 | * values are at 'idx_retbase' in every case, assuming there are |
| 66366 | * 'rc' return values on top of stack. |
| 66367 | * |
| 66368 | * This is a bit tricky, because the called C function operates in |
| 66369 | * the same activation record and may have e.g. popped the stack |
| 66370 | * empty (below idx_retbase). |
| 66371 | */ |
| 66372 | |
| 66373 | DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) { |
| 66374 | duk_idx_t idx_rcbase; |
| 66375 | |
| 66376 | DUK_ASSERT(thr != NULL); |
| 66377 | DUK_ASSERT(idx_retbase >= 0); |
| 66378 | DUK_ASSERT(num_stack_rets >= 0); |
| 66379 | DUK_ASSERT(num_actual_rets >= 0); |
| 66380 | |
| 66381 | idx_rcbase = duk_get_top(thr) - num_actual_rets; /* base of known return values */ |
| 66382 | if (DUK_UNLIKELY(idx_rcbase < 0)) { |
| 66383 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC); |
| 66384 | DUK_WO_NORETURN(return;); |
| 66385 | } |
| 66386 | |
| 66387 | DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: " |
| 66388 | "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld" , |
| 66389 | (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(thr), |
| 66390 | (long) idx_retbase, (long) idx_rcbase)); |
| 66391 | |
| 66392 | DUK_ASSERT(idx_rcbase >= 0); /* caller must check */ |
| 66393 | |
| 66394 | /* Space for num_stack_rets was reserved before the safe call. |
| 66395 | * Because value stack reserve cannot shrink except in call returns, |
| 66396 | * the reserve is still in place. Adjust valstack, carefully |
| 66397 | * ensuring we don't overstep the reserve. |
| 66398 | */ |
| 66399 | |
| 66400 | /* Match idx_rcbase with idx_retbase so that the return values |
| 66401 | * start at the correct index. |
| 66402 | */ |
| 66403 | if (idx_rcbase > idx_retbase) { |
| 66404 | duk_idx_t count = idx_rcbase - idx_retbase; |
| 66405 | |
| 66406 | DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals " |
| 66407 | "(idx_retbase=%ld, idx_rcbase=%ld)" , (long) idx_retbase, (long) idx_rcbase)); |
| 66408 | |
| 66409 | /* Remove values between irc_rcbase (start of intended return |
| 66410 | * values) and idx_retbase to lower return values to idx_retbase. |
| 66411 | */ |
| 66412 | DUK_ASSERT(count > 0); |
| 66413 | duk_remove_n(thr, idx_retbase, count); /* may be NORZ */ |
| 66414 | } else { |
| 66415 | duk_idx_t count = idx_retbase - idx_rcbase; |
| 66416 | |
| 66417 | DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals " |
| 66418 | "(idx_retbase=%ld, idx_rcbase=%ld)" , (long) idx_retbase, (long) idx_rcbase)); |
| 66419 | |
| 66420 | /* Insert 'undefined' at idx_rcbase (start of intended return |
| 66421 | * values) to lift return values to idx_retbase. |
| 66422 | */ |
| 66423 | DUK_ASSERT(count >= 0); |
| 66424 | DUK_ASSERT(thr->valstack_end - thr->valstack_top >= count); /* reserve cannot shrink */ |
| 66425 | duk_insert_undefined_n(thr, idx_rcbase, count); |
| 66426 | } |
| 66427 | |
| 66428 | /* Chop extra retvals away / extend with undefined. */ |
| 66429 | duk_set_top_unsafe(thr, idx_retbase + num_stack_rets); |
| 66430 | } |
| 66431 | |
| 66432 | /* |
| 66433 | * Activation setup for tailcalls and non-tailcalls. |
| 66434 | */ |
| 66435 | |
| 66436 | #if defined(DUK_USE_TAILCALL) |
| 66437 | DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr, |
| 66438 | duk_small_uint_t call_flags, |
| 66439 | duk_idx_t idx_func, |
| 66440 | duk_hobject *func, |
| 66441 | duk_size_t entry_valstack_bottom_byteoff, |
| 66442 | duk_size_t entry_valstack_end_byteoff, |
| 66443 | duk_idx_t *out_nargs, |
| 66444 | duk_idx_t *out_nregs, |
| 66445 | duk_size_t *out_vs_min_bytes, |
| 66446 | duk_activation **out_act) { |
| 66447 | duk_activation *act; |
| 66448 | duk_tval *tv1, *tv2; |
| 66449 | duk_idx_t idx_args; |
| 66450 | duk_small_uint_t flags1, flags2; |
| 66451 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 66452 | duk_activation *prev_pause_act; |
| 66453 | #endif |
| 66454 | |
| 66455 | DUK_UNREF(entry_valstack_end_byteoff); |
| 66456 | |
| 66457 | /* Tailcall cannot be flagged to resume calls, and a |
| 66458 | * previous frame must exist. |
| 66459 | */ |
| 66460 | DUK_ASSERT(thr->callstack_top >= 1); |
| 66461 | |
| 66462 | act = thr->callstack_curr; |
| 66463 | DUK_ASSERT(act != NULL); |
| 66464 | *out_act = act; |
| 66465 | |
| 66466 | if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) { |
| 66467 | DUK_DDD(DUK_DDDPRINT("tail call prevented by target not being ecma function" )); |
| 66468 | return 0; |
| 66469 | } |
| 66470 | if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) { |
| 66471 | DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENT_YIELD" )); |
| 66472 | return 0; |
| 66473 | } |
| 66474 | /* Tailcall is only allowed if current and candidate |
| 66475 | * function have identical return value handling. There |
| 66476 | * are three possible return value handling cases: |
| 66477 | * 1. Normal function call, no special return value handling. |
| 66478 | * 2. Constructor call, return value replacement object check. |
| 66479 | * 3. Proxy 'construct' trap call, return value invariant check. |
| 66480 | */ |
| 66481 | flags1 = (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT) ? 1 : 0) |
| 66482 | #if defined(DUK_USE_ES6_PROXY) |
| 66483 | | (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) ? 2 : 0) |
| 66484 | #endif |
| 66485 | ; |
| 66486 | flags2 = (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) ? 1 : 0) |
| 66487 | #if defined(DUK_USE_ES6_PROXY) |
| 66488 | | (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) ? 2 : 0); |
| 66489 | #endif |
| 66490 | ; |
| 66491 | if (flags1 != flags2) { |
| 66492 | DUK_DDD(DUK_DDDPRINT("tail call prevented by incompatible return value handling" )); |
| 66493 | return 0; |
| 66494 | } |
| 66495 | DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT) && (call_flags & DUK_CALL_FLAG_CONSTRUCT)) || |
| 66496 | (!(act->flags & DUK_ACT_FLAG_CONSTRUCT) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT))); |
| 66497 | DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)) || |
| 66498 | (!(act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY))); |
| 66499 | if (DUK_HOBJECT_HAS_NOTAIL(func)) { |
| 66500 | /* See: test-bug-tailcall-preventyield-assert.c. */ |
| 66501 | DUK_DDD(DUK_DDDPRINT("tail call prevented by function having a notail flag" )); |
| 66502 | return 0; |
| 66503 | } |
| 66504 | |
| 66505 | /* |
| 66506 | * Tailcall handling |
| 66507 | * |
| 66508 | * Although the callstack entry is reused, we need to explicitly unwind |
| 66509 | * the current activation (or simulate an unwind). In particular, the |
| 66510 | * current activation must be closed, otherwise something like |
| 66511 | * test-bug-reduce-judofyr.js results. Also catchers need to be unwound |
| 66512 | * because there may be non-error-catching label entries in valid tail calls. |
| 66513 | * |
| 66514 | * Special attention is needed for debugger and pause behavior when |
| 66515 | * reusing an activation. |
| 66516 | * - Disable StepOut processing for the activation unwind because |
| 66517 | * we reuse the activation, see: |
| 66518 | * https://github.com/svaarala/duktape/issues/1684. |
| 66519 | * - Disable line change pause flag permanently if act == dbg_pause_act |
| 66520 | * (if set) because it would no longer be relevant, see: |
| 66521 | * https://github.com/svaarala/duktape/issues/1726, |
| 66522 | * https://github.com/svaarala/duktape/issues/1786. |
| 66523 | * - Check for function entry (e.g. StepInto) pause flag here, because |
| 66524 | * the executor pause check won't trigger due to shared activation, see: |
| 66525 | * https://github.com/svaarala/duktape/issues/1726. |
| 66526 | */ |
| 66527 | |
| 66528 | DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld" , |
| 66529 | (long) (thr->callstack_top - 1))); |
| 66530 | |
| 66531 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); |
| 66532 | DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func)); |
| 66533 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func)); |
| 66534 | DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); |
| 66535 | DUK_ASSERT(call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA); |
| 66536 | |
| 66537 | /* Unwind the topmost callstack entry before reusing it. This |
| 66538 | * also unwinds the catchers related to the topmost entry. |
| 66539 | */ |
| 66540 | DUK_ASSERT(thr->callstack_top > 0); |
| 66541 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 66542 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 66543 | if (act == thr->heap->dbg_pause_act) { |
| 66544 | thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE; |
| 66545 | } |
| 66546 | |
| 66547 | prev_pause_act = thr->heap->dbg_pause_act; |
| 66548 | thr->heap->dbg_pause_act = NULL; |
| 66549 | if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) { |
| 66550 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)" )); |
| 66551 | duk_debug_set_paused(thr->heap); |
| 66552 | } |
| 66553 | #endif |
| 66554 | duk_hthread_activation_unwind_reuse_norz(thr); |
| 66555 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 66556 | thr->heap->dbg_pause_act = prev_pause_act; |
| 66557 | #endif |
| 66558 | DUK_ASSERT(act == thr->callstack_curr); |
| 66559 | |
| 66560 | /* XXX: We could restore the caller's value stack reserve |
| 66561 | * here, as if we did an actual unwind-and-call. Without |
| 66562 | * the restoration, value stack reserve may remain higher |
| 66563 | * than would otherwise be possible until we return to a |
| 66564 | * non-tailcall. |
| 66565 | */ |
| 66566 | |
| 66567 | /* Then reuse the unwound activation. */ |
| 66568 | act->cat = NULL; |
| 66569 | act->var_env = NULL; |
| 66570 | act->lex_env = NULL; |
| 66571 | DUK_ASSERT(func != NULL); |
| 66572 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func)); |
| 66573 | act->func = func; /* don't want an intermediate exposed state with func == NULL */ |
| 66574 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 66575 | act->prev_caller = NULL; |
| 66576 | #endif |
| 66577 | /* don't want an intermediate exposed state with invalid pc */ |
| 66578 | act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func); |
| 66579 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 66580 | act->prev_line = 0; |
| 66581 | #endif |
| 66582 | DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ |
| 66583 | DUK_HOBJECT_INCREF(thr, func); |
| 66584 | |
| 66585 | act->flags = DUK_ACT_FLAG_TAILCALLED; |
| 66586 | if (DUK_HOBJECT_HAS_STRICT(func)) { |
| 66587 | act->flags |= DUK_ACT_FLAG_STRICT; |
| 66588 | } |
| 66589 | if (call_flags & DUK_CALL_FLAG_CONSTRUCT) { |
| 66590 | act->flags |= DUK_ACT_FLAG_CONSTRUCT; |
| 66591 | } |
| 66592 | #if defined(DUK_USE_ES6_PROXY) |
| 66593 | if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) { |
| 66594 | act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY; |
| 66595 | } |
| 66596 | #endif |
| 66597 | |
| 66598 | DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */ |
| 66599 | DUK_ASSERT(act->var_env == NULL); |
| 66600 | DUK_ASSERT(act->lex_env == NULL); |
| 66601 | act->bottom_byteoff = entry_valstack_bottom_byteoff; /* tail call -> reuse current "frame" */ |
| 66602 | #if 0 |
| 66603 | /* Topmost activation retval_byteoff is considered garbage, no need to init. */ |
| 66604 | act->retval_byteoff = 0; |
| 66605 | #endif |
| 66606 | /* Filled in when final reserve is known, dummy value doesn't matter |
| 66607 | * even in error unwind because reserve_byteoff is only used when |
| 66608 | * returning to -this- activation. |
| 66609 | */ |
| 66610 | act->reserve_byteoff = 0; |
| 66611 | |
| 66612 | /* |
| 66613 | * Manipulate valstack so that args are on the current bottom and the |
| 66614 | * previous caller's 'this' binding (which is the value preceding the |
| 66615 | * current bottom) is replaced with the new 'this' binding: |
| 66616 | * |
| 66617 | * [ ... this_old | (crud) func this_new arg1 ... argN ] |
| 66618 | * --> [ ... this_new | arg1 ... argN ] |
| 66619 | * |
| 66620 | * For tail calling to work properly, the valstack bottom must not grow |
| 66621 | * here; otherwise crud would accumulate on the valstack. |
| 66622 | */ |
| 66623 | |
| 66624 | tv1 = thr->valstack_bottom - 1; |
| 66625 | tv2 = thr->valstack_bottom + idx_func + 1; |
| 66626 | DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */ |
| 66627 | DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top); |
| 66628 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ |
| 66629 | |
| 66630 | idx_args = idx_func + 2; |
| 66631 | duk_remove_n(thr, 0, idx_args); /* may be NORZ */ |
| 66632 | |
| 66633 | idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */ |
| 66634 | idx_args = 0; |
| 66635 | |
| 66636 | *out_nargs = ((duk_hcompfunc *) func)->nargs; |
| 66637 | *out_nregs = ((duk_hcompfunc *) func)->nregs; |
| 66638 | DUK_ASSERT(*out_nregs >= 0); |
| 66639 | DUK_ASSERT(*out_nregs >= *out_nargs); |
| 66640 | *out_vs_min_bytes = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA); |
| 66641 | |
| 66642 | |
| 66643 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 66644 | #if defined(DUK_USE_TAILCALL) |
| 66645 | #error incorrect options: tail calls enabled with function caller property |
| 66646 | #endif |
| 66647 | /* XXX: This doesn't actually work properly for tail calls, so |
| 66648 | * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY |
| 66649 | * is in use. |
| 66650 | */ |
| 66651 | duk__update_func_caller_prop(thr, func); |
| 66652 | #endif |
| 66653 | |
| 66654 | /* [ ... this_new | arg1 ... argN ] */ |
| 66655 | |
| 66656 | return 1; |
| 66657 | } |
| 66658 | #endif /* DUK_USE_TAILCALL */ |
| 66659 | |
| 66660 | DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr, |
| 66661 | duk_small_uint_t call_flags, |
| 66662 | duk_idx_t idx_func, |
| 66663 | duk_hobject *func, |
| 66664 | duk_size_t entry_valstack_bottom_byteoff, |
| 66665 | duk_size_t entry_valstack_end_byteoff, |
| 66666 | duk_idx_t *out_nargs, |
| 66667 | duk_idx_t *out_nregs, |
| 66668 | duk_size_t *out_vs_min_bytes, |
| 66669 | duk_activation **out_act) { |
| 66670 | duk_activation *act; |
| 66671 | duk_activation *new_act; |
| 66672 | |
| 66673 | DUK_UNREF(entry_valstack_end_byteoff); |
| 66674 | |
| 66675 | DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld" , |
| 66676 | (long) (thr->callstack_top))); |
| 66677 | |
| 66678 | duk__call_callstack_limit_check(thr); |
| 66679 | new_act = duk_hthread_activation_alloc(thr); |
| 66680 | DUK_ASSERT(new_act != NULL); |
| 66681 | |
| 66682 | act = thr->callstack_curr; |
| 66683 | if (act != NULL) { |
| 66684 | /* |
| 66685 | * Update return value stack index of current activation (if any). |
| 66686 | * |
| 66687 | * Although it might seem this is not necessary (bytecode executor |
| 66688 | * does this for ECMAScript-to-ECMAScript calls; other calls are |
| 66689 | * handled here), this turns out to be necessary for handling yield |
| 66690 | * and resume. For them, an ECMAScript-to-native call happens, and |
| 66691 | * the ECMAScript call's retval_byteoff must be set for things to work. |
| 66692 | */ |
| 66693 | |
| 66694 | act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval); |
| 66695 | } |
| 66696 | |
| 66697 | new_act->parent = act; |
| 66698 | thr->callstack_curr = new_act; |
| 66699 | thr->callstack_top++; |
| 66700 | act = new_act; |
| 66701 | *out_act = act; |
| 66702 | |
| 66703 | DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */ |
| 66704 | DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); |
| 66705 | |
| 66706 | act->cat = NULL; |
| 66707 | |
| 66708 | act->flags = 0; |
| 66709 | if (call_flags & DUK_CALL_FLAG_CONSTRUCT) { |
| 66710 | act->flags |= DUK_ACT_FLAG_CONSTRUCT; |
| 66711 | } |
| 66712 | #if defined(DUK_USE_ES6_PROXY) |
| 66713 | if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) { |
| 66714 | act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY; |
| 66715 | } |
| 66716 | #endif |
| 66717 | if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) { |
| 66718 | act->flags |= DUK_ACT_FLAG_DIRECT_EVAL; |
| 66719 | } |
| 66720 | |
| 66721 | /* start of arguments: idx_func + 2. */ |
| 66722 | act->func = func; /* NULL for lightfunc */ |
| 66723 | if (DUK_LIKELY(func != NULL)) { |
| 66724 | DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */ |
| 66725 | if (DUK_HOBJECT_HAS_STRICT(func)) { |
| 66726 | act->flags |= DUK_ACT_FLAG_STRICT; |
| 66727 | } |
| 66728 | if (DUK_HOBJECT_IS_COMPFUNC(func)) { |
| 66729 | *out_nargs = ((duk_hcompfunc *) func)->nargs; |
| 66730 | *out_nregs = ((duk_hcompfunc *) func)->nregs; |
| 66731 | DUK_ASSERT(*out_nregs >= 0); |
| 66732 | DUK_ASSERT(*out_nregs >= *out_nargs); |
| 66733 | *out_vs_min_bytes = entry_valstack_bottom_byteoff + |
| 66734 | sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA); |
| 66735 | } else { |
| 66736 | /* True because of call target lookup checks. */ |
| 66737 | DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func)); |
| 66738 | |
| 66739 | *out_nargs = ((duk_hnatfunc *) func)->nargs; |
| 66740 | *out_nregs = *out_nargs; |
| 66741 | if (*out_nargs >= 0) { |
| 66742 | *out_vs_min_bytes = entry_valstack_bottom_byteoff + |
| 66743 | sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); |
| 66744 | } else { |
| 66745 | /* Vararg function. */ |
| 66746 | duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack)); |
| 66747 | *out_vs_min_bytes = valstack_top_byteoff + |
| 66748 | sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); |
| 66749 | } |
| 66750 | } |
| 66751 | } else { |
| 66752 | duk_small_uint_t lf_flags; |
| 66753 | duk_tval *tv_func; |
| 66754 | |
| 66755 | act->flags |= DUK_ACT_FLAG_STRICT; |
| 66756 | |
| 66757 | tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func); |
| 66758 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func)); |
| 66759 | DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */ |
| 66760 | |
| 66761 | lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func); |
| 66762 | *out_nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags); |
| 66763 | if (*out_nargs != DUK_LFUNC_NARGS_VARARGS) { |
| 66764 | *out_vs_min_bytes = entry_valstack_bottom_byteoff + |
| 66765 | sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nargs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); |
| 66766 | } else { |
| 66767 | duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack)); |
| 66768 | *out_vs_min_bytes = valstack_top_byteoff + |
| 66769 | sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA); |
| 66770 | *out_nargs = -1; /* vararg */ |
| 66771 | } |
| 66772 | *out_nregs = *out_nargs; |
| 66773 | } |
| 66774 | |
| 66775 | act->var_env = NULL; |
| 66776 | act->lex_env = NULL; |
| 66777 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 66778 | act->prev_caller = NULL; |
| 66779 | #endif |
| 66780 | act->curr_pc = NULL; |
| 66781 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 66782 | act->prev_line = 0; |
| 66783 | #endif |
| 66784 | act->bottom_byteoff = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) idx_func + 2U); |
| 66785 | #if 0 |
| 66786 | act->retval_byteoff = 0; /* topmost activation retval_byteoff is considered garbage, no need to init */ |
| 66787 | #endif |
| 66788 | /* Filled in when final reserve is known, dummy value doesn't matter |
| 66789 | * even in error unwind because reserve_byteoff is only used when |
| 66790 | * returning to -this- activation. |
| 66791 | */ |
| 66792 | act->reserve_byteoff = 0; /* filled in by caller */ |
| 66793 | |
| 66794 | /* XXX: Is this INCREF necessary? 'func' is always a borrowed |
| 66795 | * reference reachable through the value stack? If changed, stack |
| 66796 | * unwind code also needs to be fixed to match. |
| 66797 | */ |
| 66798 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */ |
| 66799 | |
| 66800 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 66801 | if (func) { |
| 66802 | duk__update_func_caller_prop(thr, func); |
| 66803 | } |
| 66804 | #endif |
| 66805 | } |
| 66806 | |
| 66807 | /* |
| 66808 | * Environment setup. |
| 66809 | */ |
| 66810 | |
| 66811 | DUK_LOCAL void duk__call_env_setup(duk_hthread *thr, duk_hobject *func, duk_activation *act, duk_idx_t idx_args) { |
| 66812 | duk_hobject *env; |
| 66813 | |
| 66814 | DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function has already been resolved */ |
| 66815 | |
| 66816 | if (DUK_LIKELY(func != NULL)) { |
| 66817 | if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) { |
| 66818 | DUK_STATS_INC(thr->heap, stats_envrec_newenv); |
| 66819 | if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) { |
| 66820 | /* Use a new environment but there's no 'arguments' object; |
| 66821 | * delayed environment initialization. This is the most |
| 66822 | * common case. |
| 66823 | */ |
| 66824 | DUK_ASSERT(act->lex_env == NULL); |
| 66825 | DUK_ASSERT(act->var_env == NULL); |
| 66826 | } else { |
| 66827 | /* Use a new environment and there's an 'arguments' object. |
| 66828 | * We need to initialize it right now. |
| 66829 | */ |
| 66830 | |
| 66831 | /* third arg: absolute index (to entire valstack) of bottom_byteoff of new activation */ |
| 66832 | env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff); |
| 66833 | DUK_ASSERT(env != NULL); |
| 66834 | |
| 66835 | /* [ ... func this arg1 ... argN envobj ] */ |
| 66836 | |
| 66837 | DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func)); |
| 66838 | duk__handle_createargs_for_call(thr, func, env, idx_args); |
| 66839 | |
| 66840 | /* [ ... func this arg1 ... argN envobj ] */ |
| 66841 | |
| 66842 | act->lex_env = env; |
| 66843 | act->var_env = env; |
| 66844 | DUK_HOBJECT_INCREF(thr, env); |
| 66845 | DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */ |
| 66846 | duk_pop(thr); |
| 66847 | } |
| 66848 | } else { |
| 66849 | /* Use existing env (e.g. for non-strict eval); cannot have |
| 66850 | * an own 'arguments' object (but can refer to an existing one). |
| 66851 | */ |
| 66852 | |
| 66853 | DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func)); |
| 66854 | |
| 66855 | DUK_STATS_INC(thr->heap, stats_envrec_oldenv); |
| 66856 | duk__handle_oldenv_for_call(thr, func, act); |
| 66857 | |
| 66858 | DUK_ASSERT(act->lex_env != NULL); |
| 66859 | DUK_ASSERT(act->var_env != NULL); |
| 66860 | } |
| 66861 | } else { |
| 66862 | /* Lightfuncs are always native functions and have "newenv". */ |
| 66863 | DUK_ASSERT(act->lex_env == NULL); |
| 66864 | DUK_ASSERT(act->var_env == NULL); |
| 66865 | DUK_STATS_INC(thr->heap, stats_envrec_newenv); |
| 66866 | } |
| 66867 | } |
| 66868 | |
| 66869 | /* |
| 66870 | * Misc shared helpers. |
| 66871 | */ |
| 66872 | |
| 66873 | /* Check thread state, update current thread. */ |
| 66874 | DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) { |
| 66875 | DUK_ASSERT(thr != NULL); |
| 66876 | |
| 66877 | if (DUK_LIKELY(thr == thr->heap->curr_thread)) { |
| 66878 | if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_RUNNING)) { |
| 66879 | /* Should actually never happen, but check anyway. */ |
| 66880 | goto thread_state_error; |
| 66881 | } |
| 66882 | } else { |
| 66883 | DUK_ASSERT(thr->heap->curr_thread == NULL || |
| 66884 | thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING); |
| 66885 | if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_INACTIVE)) { |
| 66886 | goto thread_state_error; |
| 66887 | } |
| 66888 | DUK_HEAP_SWITCH_THREAD(thr->heap, thr); |
| 66889 | thr->state = DUK_HTHREAD_STATE_RUNNING; |
| 66890 | |
| 66891 | /* Multiple threads may be simultaneously in the RUNNING |
| 66892 | * state, but not in the same "resume chain". |
| 66893 | */ |
| 66894 | } |
| 66895 | DUK_ASSERT(thr->heap->curr_thread == thr); |
| 66896 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); |
| 66897 | return; |
| 66898 | |
| 66899 | thread_state_error: |
| 66900 | DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)" , (long) thr->state); |
| 66901 | DUK_WO_NORETURN(return;); |
| 66902 | } |
| 66903 | |
| 66904 | /* |
| 66905 | * Main unprotected call handler, handles: |
| 66906 | * |
| 66907 | * - All combinations of native/ECMAScript caller and native/ECMAScript |
| 66908 | * target. |
| 66909 | * |
| 66910 | * - Optimized ECMAScript-to-ECMAScript call where call handling only |
| 66911 | * sets up a new duk_activation but reuses an existing bytecode executor |
| 66912 | * (the caller) without native recursion. |
| 66913 | * |
| 66914 | * - Tailcalls, where an activation is reused without increasing call |
| 66915 | * stack (duk_activation) depth. |
| 66916 | * |
| 66917 | * - Setup for an initial Duktape.Thread.resume(). |
| 66918 | * |
| 66919 | * The call handler doesn't provide any protection guarantees, protected calls |
| 66920 | * must be implemented e.g. by wrapping the call in a duk_safe_call(). |
| 66921 | * Call setup may fail at any stage, even when the new activation is in |
| 66922 | * place; the only guarantee is that the state is consistent for unwinding. |
| 66923 | */ |
| 66924 | |
| 66925 | DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr, |
| 66926 | duk_idx_t idx_func, |
| 66927 | duk_small_uint_t call_flags) { |
| 66928 | #if defined(DUK_USE_ASSERTIONS) |
| 66929 | duk_activation *entry_act; |
| 66930 | duk_size_t entry_callstack_top; |
| 66931 | #endif |
| 66932 | duk_size_t entry_valstack_bottom_byteoff; |
| 66933 | duk_size_t entry_valstack_end_byteoff; |
| 66934 | duk_int_t entry_call_recursion_depth; |
| 66935 | duk_hthread *entry_curr_thread; |
| 66936 | duk_uint_fast8_t entry_thread_state; |
| 66937 | duk_instr_t **entry_ptr_curr_pc; |
| 66938 | duk_idx_t idx_args; |
| 66939 | duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */ |
| 66940 | duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */ |
| 66941 | duk_size_t vs_min_bytes; /* minimum value stack size (bytes) for handling call */ |
| 66942 | duk_hobject *func; /* 'func' on stack (borrowed reference) */ |
| 66943 | duk_activation *act; |
| 66944 | duk_ret_t rc; |
| 66945 | duk_small_uint_t use_tailcall; |
| 66946 | |
| 66947 | DUK_ASSERT(thr != NULL); |
| 66948 | DUK_ASSERT(thr->heap != NULL); |
| 66949 | /* Asserts for heap->curr_thread omitted: it may be NULL, 'thr', or |
| 66950 | * any other thread (e.g. when heap thread is used to run finalizers). |
| 66951 | */ |
| 66952 | DUK_CTX_ASSERT_VALID(thr); |
| 66953 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 66954 | DUK_ASSERT(idx_func >= 0); |
| 66955 | |
| 66956 | DUK_STATS_INC(thr->heap, stats_call_all); |
| 66957 | |
| 66958 | /* If a tail call: |
| 66959 | * - an ECMAScript activation must be on top of the callstack |
| 66960 | * - there cannot be any catch stack entries that would catch |
| 66961 | * a return |
| 66962 | */ |
| 66963 | #if defined(DUK_USE_ASSERTIONS) |
| 66964 | if (call_flags & DUK_CALL_FLAG_TAILCALL) { |
| 66965 | duk_activation *tmp_act; |
| 66966 | duk_catcher *tmp_cat; |
| 66967 | |
| 66968 | DUK_ASSERT(thr->callstack_top >= 1); |
| 66969 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); |
| 66970 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); |
| 66971 | |
| 66972 | /* No entry in the catch stack which would actually catch a |
| 66973 | * throw can refer to the callstack entry being reused. |
| 66974 | * There *can* be catch stack entries referring to the current |
| 66975 | * callstack entry as long as they don't catch (e.g. label sites). |
| 66976 | */ |
| 66977 | |
| 66978 | tmp_act = thr->callstack_curr; |
| 66979 | for (tmp_cat = tmp_act->cat; tmp_cat != NULL; tmp_cat = tmp_cat->parent) { |
| 66980 | DUK_ASSERT(DUK_CAT_GET_TYPE(tmp_cat) == DUK_CAT_TYPE_LABEL); /* a non-catching entry */ |
| 66981 | } |
| 66982 | } |
| 66983 | #endif /* DUK_USE_ASSERTIONS */ |
| 66984 | |
| 66985 | /* |
| 66986 | * Store entry state. |
| 66987 | */ |
| 66988 | |
| 66989 | #if defined(DUK_USE_ASSERTIONS) |
| 66990 | entry_act = thr->callstack_curr; |
| 66991 | entry_callstack_top = thr->callstack_top; |
| 66992 | #endif |
| 66993 | entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); |
| 66994 | entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); |
| 66995 | entry_call_recursion_depth = thr->heap->call_recursion_depth; |
| 66996 | entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */ |
| 66997 | entry_thread_state = thr->state; |
| 66998 | entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */ |
| 66999 | |
| 67000 | /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL |
| 67001 | * thr->ptr_curr_pc so that it's not accidentally used with an incorrect |
| 67002 | * activation when side effects occur. |
| 67003 | */ |
| 67004 | duk_hthread_sync_and_null_currpc(thr); |
| 67005 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 67006 | |
| 67007 | DUK_DD(DUK_DDPRINT("duk__handle_call_raw: thr=%p, idx_func=%ld, " |
| 67008 | "call_flags=0x%08lx (constructor=%ld), " |
| 67009 | "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, " |
| 67010 | "entry_valstack_bottom_byteoff=%ld, entry_valstack_end_byteoff=%ld, " |
| 67011 | "entry_call_recursion_depth=%ld, " |
| 67012 | "entry_curr_thread=%p, entry_thread_state=%ld" , |
| 67013 | (void *) thr, |
| 67014 | (long) idx_func, |
| 67015 | (unsigned long) call_flags, |
| 67016 | (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) != 0 ? 1 : 0), |
| 67017 | (long) duk_get_top(thr), |
| 67018 | (long) idx_func, |
| 67019 | (long) (idx_func + 2), |
| 67020 | (long) thr->heap->call_recursion_depth, |
| 67021 | (long) thr->heap->call_recursion_limit, |
| 67022 | (long) entry_valstack_bottom_byteoff, |
| 67023 | (long) entry_valstack_end_byteoff, |
| 67024 | (long) entry_call_recursion_depth, |
| 67025 | (void *) entry_curr_thread, |
| 67026 | (long) entry_thread_state)); |
| 67027 | |
| 67028 | /* |
| 67029 | * Thread state check and book-keeping. |
| 67030 | */ |
| 67031 | |
| 67032 | duk__call_thread_state_update(thr); |
| 67033 | |
| 67034 | /* |
| 67035 | * Increase call recursion depth as early as possible so that if we |
| 67036 | * enter a recursive call for any reason there's a backstop to native |
| 67037 | * recursion. This can happen e.g. for almost any property read |
| 67038 | * because it may cause a getter call or a Proxy trap (GC and finalizers |
| 67039 | * are not an issue because they are not recursive). If we end up |
| 67040 | * doing an Ecma-to-Ecma call, revert the increase. (See GH-2032.) |
| 67041 | * |
| 67042 | * For similar reasons, ensure there is a known value stack spare |
| 67043 | * even before we actually prepare the value stack for the target |
| 67044 | * function. If this isn't done, early recursion may consume the |
| 67045 | * value stack space. |
| 67046 | * |
| 67047 | * XXX: Should bump yield preventcount early, for the same reason. |
| 67048 | */ |
| 67049 | |
| 67050 | duk__call_c_recursion_limit_check(thr); |
| 67051 | thr->heap->call_recursion_depth++; |
| 67052 | duk_require_stack(thr, DUK__CALL_HANDLING_REQUIRE_STACK); |
| 67053 | |
| 67054 | /* |
| 67055 | * Resolve final target function; handle bound functions and special |
| 67056 | * functions like .call() and .apply(). Also figure out the effective |
| 67057 | * 'this' binding, which replaces the current value at idx_func + 1. |
| 67058 | */ |
| 67059 | |
| 67060 | if (DUK_LIKELY(duk__resolve_target_fastpath_check(thr, idx_func, &func, call_flags) != 0U)) { |
| 67061 | DUK_DDD(DUK_DDDPRINT("fast path target resolve" )); |
| 67062 | } else { |
| 67063 | DUK_DDD(DUK_DDDPRINT("slow path target resolve" )); |
| 67064 | func = duk__resolve_target_func_and_this_binding(thr, idx_func, &call_flags); |
| 67065 | } |
| 67066 | DUK_ASSERT(duk_get_top(thr) - idx_func >= 2); /* at least func and this present */ |
| 67067 | |
| 67068 | DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); |
| 67069 | DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) || |
| 67070 | DUK_HOBJECT_IS_NATFUNC(func))); |
| 67071 | |
| 67072 | /* [ ... func this arg1 ... argN ] */ |
| 67073 | |
| 67074 | /* |
| 67075 | * Setup a preliminary activation and figure out nargs/nregs and |
| 67076 | * value stack minimum size. |
| 67077 | * |
| 67078 | * Don't touch valstack_bottom or valstack_top yet so that Duktape API |
| 67079 | * calls work normally. |
| 67080 | * |
| 67081 | * Because 'act' is not zeroed, all fields must be filled in. |
| 67082 | */ |
| 67083 | |
| 67084 | /* Should not be necessary, but initialize to silence warnings. */ |
| 67085 | act = NULL; |
| 67086 | nargs = 0; |
| 67087 | nregs = 0; |
| 67088 | vs_min_bytes = 0; |
| 67089 | |
| 67090 | #if defined(DUK_USE_TAILCALL) |
| 67091 | use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL); |
| 67092 | if (use_tailcall) { |
| 67093 | use_tailcall = duk__call_setup_act_attempt_tailcall(thr, |
| 67094 | call_flags, |
| 67095 | idx_func, |
| 67096 | func, |
| 67097 | entry_valstack_bottom_byteoff, |
| 67098 | entry_valstack_end_byteoff, |
| 67099 | &nargs, |
| 67100 | &nregs, |
| 67101 | &vs_min_bytes, |
| 67102 | &act); |
| 67103 | } |
| 67104 | #else |
| 67105 | DUK_ASSERT((call_flags & DUK_CALL_FLAG_TAILCALL) == 0); /* compiler ensures this */ |
| 67106 | use_tailcall = 0; |
| 67107 | #endif |
| 67108 | |
| 67109 | if (use_tailcall) { |
| 67110 | idx_args = 0; |
| 67111 | DUK_STATS_INC(thr->heap, stats_call_tailcall); |
| 67112 | } else { |
| 67113 | duk__call_setup_act_not_tailcall(thr, |
| 67114 | call_flags, |
| 67115 | idx_func, |
| 67116 | func, |
| 67117 | entry_valstack_bottom_byteoff, |
| 67118 | entry_valstack_end_byteoff, |
| 67119 | &nargs, |
| 67120 | &nregs, |
| 67121 | &vs_min_bytes, |
| 67122 | &act); |
| 67123 | idx_args = idx_func + 2; |
| 67124 | } |
| 67125 | /* After this point idx_func is no longer valid for tailcalls. */ |
| 67126 | |
| 67127 | DUK_ASSERT(act != NULL); |
| 67128 | |
| 67129 | /* [ ... func this arg1 ... argN ] */ |
| 67130 | |
| 67131 | /* |
| 67132 | * Environment record creation and 'arguments' object creation. |
| 67133 | * Named function expression name binding is handled by the |
| 67134 | * compiler; the compiled function's parent env will contain |
| 67135 | * the (immutable) binding already. |
| 67136 | * |
| 67137 | * This handling is now identical for C and ECMAScript functions. |
| 67138 | * C functions always have the 'NEWENV' flag set, so their |
| 67139 | * environment record initialization is delayed (which is good). |
| 67140 | * |
| 67141 | * Delayed creation (on demand) is handled in duk_js_var.c. |
| 67142 | */ |
| 67143 | |
| 67144 | duk__call_env_setup(thr, func, act, idx_args); |
| 67145 | |
| 67146 | /* [ ... func this arg1 ... argN ] */ |
| 67147 | |
| 67148 | /* |
| 67149 | * Setup value stack: clamp to 'nargs', fill up to 'nregs', |
| 67150 | * ensure value stack size matches target requirements, and |
| 67151 | * switch value stack bottom. Valstack top is kept. |
| 67152 | * |
| 67153 | * Value stack can only grow here. |
| 67154 | */ |
| 67155 | |
| 67156 | duk_valstack_grow_check_throw(thr, vs_min_bytes); |
| 67157 | act->reserve_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); |
| 67158 | |
| 67159 | if (use_tailcall) { |
| 67160 | DUK_ASSERT(nregs >= 0); |
| 67161 | DUK_ASSERT(nregs >= nargs); |
| 67162 | duk_set_top_and_wipe(thr, nregs, nargs); |
| 67163 | } else { |
| 67164 | if (nregs >= 0) { |
| 67165 | DUK_ASSERT(nregs >= nargs); |
| 67166 | duk_set_top_and_wipe(thr, idx_func + 2 + nregs, idx_func + 2 + nargs); |
| 67167 | } else { |
| 67168 | ; |
| 67169 | } |
| 67170 | thr->valstack_bottom = thr->valstack_bottom + idx_func + 2; |
| 67171 | } |
| 67172 | DUK_ASSERT(thr->valstack_bottom >= thr->valstack); |
| 67173 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 67174 | DUK_ASSERT(thr->valstack_end >= thr->valstack_top); |
| 67175 | |
| 67176 | /* |
| 67177 | * Make the actual call. For Ecma-to-Ecma calls detect that |
| 67178 | * setup is complete, then return with a status code that allows |
| 67179 | * the caller to reuse the running executor. |
| 67180 | */ |
| 67181 | |
| 67182 | if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) { |
| 67183 | /* |
| 67184 | * ECMAScript call. |
| 67185 | */ |
| 67186 | |
| 67187 | DUK_ASSERT(func != NULL); |
| 67188 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func)); |
| 67189 | act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func); |
| 67190 | |
| 67191 | if (call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA) { |
| 67192 | DUK_DD(DUK_DDPRINT("avoid native call, use existing executor" )); |
| 67193 | DUK_STATS_INC(thr->heap, stats_call_ecmatoecma); |
| 67194 | DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); |
| 67195 | DUK_REFZERO_CHECK_FAST(thr); |
| 67196 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 67197 | thr->heap->call_recursion_depth--; /* No recursion increase for this case. */ |
| 67198 | return 1; /* 1=reuse executor */ |
| 67199 | } |
| 67200 | DUK_ASSERT(use_tailcall == 0); |
| 67201 | |
| 67202 | /* duk_hthread_activation_unwind_norz() will decrease this on unwind */ |
| 67203 | DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); |
| 67204 | act->flags |= DUK_ACT_FLAG_PREVENT_YIELD; |
| 67205 | thr->callstack_preventcount++; |
| 67206 | |
| 67207 | /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */ |
| 67208 | |
| 67209 | /* |
| 67210 | * Bytecode executor call. |
| 67211 | * |
| 67212 | * Execute bytecode, handling any recursive function calls and |
| 67213 | * thread resumptions. Returns when execution would return from |
| 67214 | * the entry level activation. When the executor returns, a |
| 67215 | * single return value is left on the stack top. |
| 67216 | * |
| 67217 | * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW), |
| 67218 | * other types are handled internally by the executor. |
| 67219 | */ |
| 67220 | |
| 67221 | /* thr->ptr_curr_pc is set by bytecode executor early on entry */ |
| 67222 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 67223 | DUK_DDD(DUK_DDDPRINT("entering bytecode execution" )); |
| 67224 | duk_js_execute_bytecode(thr); |
| 67225 | DUK_DDD(DUK_DDDPRINT("returned from bytecode execution" )); |
| 67226 | } else { |
| 67227 | /* |
| 67228 | * Native call. |
| 67229 | */ |
| 67230 | |
| 67231 | DUK_ASSERT(func == NULL || ((duk_hnatfunc *) func)->func != NULL); |
| 67232 | DUK_ASSERT(use_tailcall == 0); |
| 67233 | |
| 67234 | /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */ |
| 67235 | |
| 67236 | /* duk_hthread_activation_unwind_norz() will decrease this on unwind */ |
| 67237 | DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0); |
| 67238 | act->flags |= DUK_ACT_FLAG_PREVENT_YIELD; |
| 67239 | thr->callstack_preventcount++; |
| 67240 | |
| 67241 | /* For native calls must be NULL so we don't sync back */ |
| 67242 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 67243 | |
| 67244 | /* XXX: native funcptr could come out of call setup. */ |
| 67245 | if (func) { |
| 67246 | rc = ((duk_hnatfunc *) func)->func(thr); |
| 67247 | } else { |
| 67248 | duk_tval *tv_func; |
| 67249 | duk_c_function funcptr; |
| 67250 | |
| 67251 | tv_func = &act->tv_func; |
| 67252 | DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func)); |
| 67253 | funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func); |
| 67254 | rc = funcptr(thr); |
| 67255 | } |
| 67256 | |
| 67257 | /* Automatic error throwing, retval check. */ |
| 67258 | |
| 67259 | if (rc == 0) { |
| 67260 | DUK_ASSERT(thr->valstack < thr->valstack_end); |
| 67261 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); |
| 67262 | thr->valstack_top++; |
| 67263 | } else if (rc == 1) { |
| 67264 | ; |
| 67265 | } else if (rc < 0) { |
| 67266 | duk_error_throw_from_negative_rc(thr, rc); |
| 67267 | DUK_WO_NORETURN(return 0;); |
| 67268 | } else { |
| 67269 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC); |
| 67270 | DUK_WO_NORETURN(return 0;); |
| 67271 | } |
| 67272 | } |
| 67273 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 67274 | DUK_ASSERT(use_tailcall == 0); |
| 67275 | |
| 67276 | /* |
| 67277 | * Constructor call post processing. |
| 67278 | */ |
| 67279 | |
| 67280 | #if defined(DUK_USE_ES6_PROXY) |
| 67281 | if (call_flags & (DUK_CALL_FLAG_CONSTRUCT | DUK_CALL_FLAG_CONSTRUCT_PROXY)) { |
| 67282 | duk_call_construct_postprocess(thr, call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY); |
| 67283 | } |
| 67284 | #else |
| 67285 | if (call_flags & DUK_CALL_FLAG_CONSTRUCT) { |
| 67286 | duk_call_construct_postprocess(thr, 0); |
| 67287 | } |
| 67288 | #endif |
| 67289 | |
| 67290 | /* |
| 67291 | * Unwind, restore valstack bottom and other book-keeping. |
| 67292 | */ |
| 67293 | |
| 67294 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 67295 | DUK_ASSERT(thr->callstack_curr->parent == entry_act); |
| 67296 | DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1); |
| 67297 | duk_hthread_activation_unwind_norz(thr); |
| 67298 | DUK_ASSERT(thr->callstack_curr == entry_act); |
| 67299 | DUK_ASSERT(thr->callstack_top == entry_callstack_top); |
| 67300 | |
| 67301 | thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff); |
| 67302 | /* keep current valstack_top */ |
| 67303 | DUK_ASSERT(thr->valstack_bottom >= thr->valstack); |
| 67304 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 67305 | DUK_ASSERT(thr->valstack_end >= thr->valstack_top); |
| 67306 | DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1); |
| 67307 | |
| 67308 | /* Return value handling. */ |
| 67309 | |
| 67310 | /* [ ... func this (crud) retval ] */ |
| 67311 | |
| 67312 | { |
| 67313 | duk_tval *tv_ret; |
| 67314 | duk_tval *tv_funret; |
| 67315 | |
| 67316 | tv_ret = thr->valstack_bottom + idx_func; |
| 67317 | tv_funret = thr->valstack_top - 1; |
| 67318 | #if defined(DUK_USE_FASTINT) |
| 67319 | /* Explicit check for fastint downgrade. */ |
| 67320 | DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret); |
| 67321 | #endif |
| 67322 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */ |
| 67323 | } |
| 67324 | |
| 67325 | duk_set_top_unsafe(thr, idx_func + 1); |
| 67326 | |
| 67327 | /* [ ... retval ] */ |
| 67328 | |
| 67329 | /* Restore caller's value stack reserve (cannot fail). */ |
| 67330 | DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff >= (duk_uint8_t *) thr->valstack_top); |
| 67331 | DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff <= (duk_uint8_t *) thr->valstack_alloc_end); |
| 67332 | thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff); |
| 67333 | |
| 67334 | /* XXX: Trial value stack shrink would be OK here, but we'd need |
| 67335 | * to prevent side effects of the potential realloc. |
| 67336 | */ |
| 67337 | |
| 67338 | /* Restore entry thread executor curr_pc stack frame pointer. */ |
| 67339 | thr->ptr_curr_pc = entry_ptr_curr_pc; |
| 67340 | |
| 67341 | DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ |
| 67342 | thr->state = (duk_uint8_t) entry_thread_state; |
| 67343 | |
| 67344 | /* Disabled assert: triggered with some torture tests. */ |
| 67345 | #if 0 |
| 67346 | DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */ |
| 67347 | (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */ |
| 67348 | (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */ |
| 67349 | #endif |
| 67350 | |
| 67351 | thr->heap->call_recursion_depth = entry_call_recursion_depth; |
| 67352 | |
| 67353 | /* If the debugger is active we need to force an interrupt so that |
| 67354 | * debugger breakpoints are rechecked. This is important for function |
| 67355 | * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see |
| 67356 | * GH-303. Only needed for success path, error path always causes a |
| 67357 | * breakpoint recheck in the executor. It would be enough to set this |
| 67358 | * only when returning to an ECMAScript activation, but setting the flag |
| 67359 | * on every return should have no ill effect. |
| 67360 | */ |
| 67361 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 67362 | if (duk_debug_is_attached(thr->heap)) { |
| 67363 | DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt" )); |
| 67364 | DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); |
| 67365 | thr->interrupt_init -= thr->interrupt_counter; |
| 67366 | thr->interrupt_counter = 0; |
| 67367 | thr->heap->dbg_force_restart = 1; |
| 67368 | } |
| 67369 | #endif |
| 67370 | |
| 67371 | #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) |
| 67372 | duk__interrupt_fixup(thr, entry_curr_thread); |
| 67373 | #endif |
| 67374 | |
| 67375 | /* Restored by success path. */ |
| 67376 | DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); |
| 67377 | DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); |
| 67378 | DUK_ASSERT_LJSTATE_UNSET(thr->heap); |
| 67379 | |
| 67380 | DUK_REFZERO_CHECK_FAST(thr); |
| 67381 | |
| 67382 | return 0; /* 0=call handled inline */ |
| 67383 | } |
| 67384 | |
| 67385 | DUK_INTERNAL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, |
| 67386 | duk_idx_t nargs, |
| 67387 | duk_small_uint_t call_flags) { |
| 67388 | duk_idx_t idx_func; |
| 67389 | DUK_ASSERT(duk_get_top(thr) >= nargs + 2); |
| 67390 | idx_func = duk_get_top(thr) - (nargs + 2); |
| 67391 | DUK_ASSERT(idx_func >= 0); |
| 67392 | return duk_handle_call_unprotected(thr, idx_func, call_flags); |
| 67393 | } |
| 67394 | |
| 67395 | DUK_INTERNAL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, |
| 67396 | duk_idx_t idx_func, |
| 67397 | duk_small_uint_t call_flags) { |
| 67398 | DUK_ASSERT(duk_is_valid_index(thr, idx_func)); |
| 67399 | DUK_ASSERT(idx_func >= 0); |
| 67400 | return duk__handle_call_raw(thr, idx_func, call_flags); |
| 67401 | } |
| 67402 | |
| 67403 | /* |
| 67404 | * duk_handle_safe_call(): make a "C protected call" within the |
| 67405 | * current activation. |
| 67406 | * |
| 67407 | * The allowed thread states for making a call are the same as for |
| 67408 | * duk_handle_call_protected(). |
| 67409 | * |
| 67410 | * Even though this call is protected, errors are thrown for insane arguments |
| 67411 | * and may result in a fatal error unless there's another protected call which |
| 67412 | * catches such errors. |
| 67413 | * |
| 67414 | * The error handling path should be error free, even for out-of-memory |
| 67415 | * errors, to ensure safe sandboxing. (As of Duktape 2.2.0 this is not |
| 67416 | * yet the case for environment closing which may run out of memory, see |
| 67417 | * XXX notes below.) |
| 67418 | */ |
| 67419 | |
| 67420 | DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr, |
| 67421 | duk_safe_call_function func, |
| 67422 | void *udata, |
| 67423 | #if defined(DUK_USE_ASSERTIONS) |
| 67424 | duk_size_t entry_valstack_bottom_byteoff, |
| 67425 | duk_size_t entry_callstack_top, |
| 67426 | #endif |
| 67427 | duk_hthread *entry_curr_thread, |
| 67428 | duk_uint_fast8_t entry_thread_state, |
| 67429 | duk_idx_t idx_retbase, |
| 67430 | duk_idx_t num_stack_rets) { |
| 67431 | duk_ret_t rc; |
| 67432 | |
| 67433 | DUK_ASSERT(thr != NULL); |
| 67434 | DUK_CTX_ASSERT_VALID(thr); |
| 67435 | |
| 67436 | /* |
| 67437 | * Thread state check and book-keeping. |
| 67438 | */ |
| 67439 | |
| 67440 | duk__call_thread_state_update(thr); |
| 67441 | |
| 67442 | /* |
| 67443 | * Recursion limit check. |
| 67444 | */ |
| 67445 | |
| 67446 | duk__call_c_recursion_limit_check(thr); |
| 67447 | thr->heap->call_recursion_depth++; |
| 67448 | |
| 67449 | /* |
| 67450 | * Make the C call. |
| 67451 | */ |
| 67452 | |
| 67453 | rc = func(thr, udata); |
| 67454 | |
| 67455 | DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld" , (long) rc)); |
| 67456 | |
| 67457 | /* |
| 67458 | * Valstack manipulation for results. |
| 67459 | */ |
| 67460 | |
| 67461 | /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */ |
| 67462 | DUK_ASSERT(thr->callstack_top == entry_callstack_top); |
| 67463 | DUK_ASSERT(thr->valstack_bottom >= thr->valstack); |
| 67464 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff); |
| 67465 | DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom); |
| 67466 | DUK_ASSERT(thr->valstack_end >= thr->valstack_top); |
| 67467 | |
| 67468 | if (DUK_UNLIKELY(rc < 0)) { |
| 67469 | duk_error_throw_from_negative_rc(thr, rc); |
| 67470 | DUK_WO_NORETURN(return;); |
| 67471 | } |
| 67472 | DUK_ASSERT(rc >= 0); |
| 67473 | |
| 67474 | duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc); /* throws for insane rc */ |
| 67475 | |
| 67476 | DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ |
| 67477 | thr->state = (duk_uint8_t) entry_thread_state; |
| 67478 | } |
| 67479 | |
| 67480 | DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr, |
| 67481 | duk_activation *entry_act, |
| 67482 | #if defined(DUK_USE_ASSERTIONS) |
| 67483 | duk_size_t entry_callstack_top, |
| 67484 | #endif |
| 67485 | duk_hthread *entry_curr_thread, |
| 67486 | duk_uint_fast8_t entry_thread_state, |
| 67487 | duk_idx_t idx_retbase, |
| 67488 | duk_idx_t num_stack_rets, |
| 67489 | duk_size_t entry_valstack_bottom_byteoff, |
| 67490 | duk_jmpbuf *old_jmpbuf_ptr) { |
| 67491 | DUK_ASSERT(thr != NULL); |
| 67492 | DUK_CTX_ASSERT_VALID(thr); |
| 67493 | |
| 67494 | /* |
| 67495 | * Error during call. The error value is at heap->lj.value1. |
| 67496 | * |
| 67497 | * The very first thing we do is restore the previous setjmp catcher. |
| 67498 | * This means that any error in error handling will propagate outwards |
| 67499 | * instead of causing a setjmp() re-entry above. |
| 67500 | */ |
| 67501 | |
| 67502 | DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()" )); |
| 67503 | |
| 67504 | /* Other longjmp types are handled by executor before propagating |
| 67505 | * the error here. |
| 67506 | */ |
| 67507 | DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); |
| 67508 | DUK_ASSERT_LJSTATE_SET(thr->heap); |
| 67509 | |
| 67510 | /* Either pointer may be NULL (at entry), so don't assert. */ |
| 67511 | thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; |
| 67512 | |
| 67513 | /* XXX: callstack unwind may now throw an error when closing |
| 67514 | * scopes; this is a sandboxing issue, described in: |
| 67515 | * https://github.com/svaarala/duktape/issues/476 |
| 67516 | */ |
| 67517 | /* XXX: "unwind to" primitive? */ |
| 67518 | |
| 67519 | DUK_ASSERT(thr->callstack_top >= entry_callstack_top); |
| 67520 | while (thr->callstack_curr != entry_act) { |
| 67521 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 67522 | duk_hthread_activation_unwind_norz(thr); |
| 67523 | } |
| 67524 | DUK_ASSERT(thr->callstack_top == entry_callstack_top); |
| 67525 | |
| 67526 | /* Switch active thread before any side effects to avoid a |
| 67527 | * dangling curr_thread pointer. |
| 67528 | */ |
| 67529 | DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */ |
| 67530 | thr->state = (duk_uint8_t) entry_thread_state; |
| 67531 | |
| 67532 | DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread); |
| 67533 | DUK_ASSERT(thr->state == entry_thread_state); |
| 67534 | |
| 67535 | /* Restore valstack bottom. */ |
| 67536 | thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff); |
| 67537 | |
| 67538 | /* [ ... | (crud) ] */ |
| 67539 | |
| 67540 | /* XXX: ensure space in valstack (now relies on internal reserve)? */ |
| 67541 | duk_push_tval(thr, &thr->heap->lj.value1); |
| 67542 | |
| 67543 | /* [ ... | (crud) errobj ] */ |
| 67544 | |
| 67545 | DUK_ASSERT(duk_get_top(thr) >= 1); /* at least errobj must be on stack */ |
| 67546 | |
| 67547 | duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */ |
| 67548 | |
| 67549 | /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */ |
| 67550 | |
| 67551 | /* Reset longjmp state. */ |
| 67552 | thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN; |
| 67553 | thr->heap->lj.iserror = 0; |
| 67554 | DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value1); |
| 67555 | DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value2); |
| 67556 | |
| 67557 | /* Error handling complete, remove side effect protections. Caller |
| 67558 | * will process pending finalizers. |
| 67559 | */ |
| 67560 | #if defined(DUK_USE_ASSERTIONS) |
| 67561 | DUK_ASSERT(thr->heap->error_not_allowed == 1); |
| 67562 | thr->heap->error_not_allowed = 0; |
| 67563 | #endif |
| 67564 | DUK_ASSERT(thr->heap->pf_prevent_count > 0); |
| 67565 | thr->heap->pf_prevent_count--; |
| 67566 | DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld" , (long) thr->heap->pf_prevent_count)); |
| 67567 | |
| 67568 | /* thr->ptr_curr_pc is restored by |
| 67569 | * duk__handle_safe_call_shared_unwind() which is also used for |
| 67570 | * success path. |
| 67571 | */ |
| 67572 | } |
| 67573 | |
| 67574 | DUK_LOCAL void duk__handle_safe_call_shared_unwind(duk_hthread *thr, |
| 67575 | duk_idx_t idx_retbase, |
| 67576 | duk_idx_t num_stack_rets, |
| 67577 | #if defined(DUK_USE_ASSERTIONS) |
| 67578 | duk_size_t entry_callstack_top, |
| 67579 | #endif |
| 67580 | duk_int_t entry_call_recursion_depth, |
| 67581 | duk_hthread *entry_curr_thread, |
| 67582 | duk_instr_t **entry_ptr_curr_pc) { |
| 67583 | DUK_ASSERT(thr != NULL); |
| 67584 | DUK_CTX_ASSERT_VALID(thr); |
| 67585 | DUK_UNREF(idx_retbase); |
| 67586 | DUK_UNREF(num_stack_rets); |
| 67587 | DUK_UNREF(entry_curr_thread); |
| 67588 | |
| 67589 | DUK_ASSERT(thr->callstack_top == entry_callstack_top); |
| 67590 | |
| 67591 | /* Restore entry thread executor curr_pc stack frame pointer. |
| 67592 | * XXX: would be enough to do in error path only, should nest |
| 67593 | * cleanly in success path. |
| 67594 | */ |
| 67595 | thr->ptr_curr_pc = entry_ptr_curr_pc; |
| 67596 | |
| 67597 | thr->heap->call_recursion_depth = entry_call_recursion_depth; |
| 67598 | |
| 67599 | /* stack discipline consistency check */ |
| 67600 | DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets); |
| 67601 | |
| 67602 | /* A debugger forced interrupt check is not needed here, as |
| 67603 | * problematic safe calls are not caused by side effects. |
| 67604 | */ |
| 67605 | |
| 67606 | #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) |
| 67607 | duk__interrupt_fixup(thr, entry_curr_thread); |
| 67608 | #endif |
| 67609 | } |
| 67610 | |
| 67611 | DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr, |
| 67612 | duk_safe_call_function func, |
| 67613 | void *udata, |
| 67614 | duk_idx_t num_stack_args, |
| 67615 | duk_idx_t num_stack_rets) { |
| 67616 | duk_activation *entry_act; |
| 67617 | duk_size_t entry_valstack_bottom_byteoff; |
| 67618 | #if defined(DUK_USE_ASSERTIONS) |
| 67619 | duk_size_t entry_valstack_end_byteoff; |
| 67620 | duk_size_t entry_callstack_top; |
| 67621 | duk_size_t entry_callstack_preventcount; |
| 67622 | #endif |
| 67623 | duk_int_t entry_call_recursion_depth; |
| 67624 | duk_hthread *entry_curr_thread; |
| 67625 | duk_uint_fast8_t entry_thread_state; |
| 67626 | duk_instr_t **entry_ptr_curr_pc; |
| 67627 | duk_jmpbuf *old_jmpbuf_ptr = NULL; |
| 67628 | duk_jmpbuf our_jmpbuf; |
| 67629 | duk_idx_t idx_retbase; |
| 67630 | duk_int_t retval; |
| 67631 | |
| 67632 | DUK_ASSERT(thr != NULL); |
| 67633 | DUK_ASSERT(duk_get_top(thr) >= num_stack_args); /* Caller ensures. */ |
| 67634 | |
| 67635 | DUK_STATS_INC(thr->heap, stats_safecall_all); |
| 67636 | |
| 67637 | /* Value stack reserve handling: safe call assumes caller has reserved |
| 67638 | * space for nrets (assuming optimal unwind processing). Value stack |
| 67639 | * reserve is not stored/restored as for normal calls because a safe |
| 67640 | * call conceptually happens in the same activation. |
| 67641 | */ |
| 67642 | |
| 67643 | /* Careful with indices like '-x'; if 'x' is zero, it refers to bottom */ |
| 67644 | entry_act = thr->callstack_curr; |
| 67645 | entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack); |
| 67646 | #if defined(DUK_USE_ASSERTIONS) |
| 67647 | entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack); |
| 67648 | entry_callstack_top = thr->callstack_top; |
| 67649 | entry_callstack_preventcount = thr->callstack_preventcount; |
| 67650 | #endif |
| 67651 | entry_call_recursion_depth = thr->heap->call_recursion_depth; |
| 67652 | entry_curr_thread = thr->heap->curr_thread; /* may be NULL if first call */ |
| 67653 | entry_thread_state = thr->state; |
| 67654 | entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */ |
| 67655 | idx_retbase = duk_get_top(thr) - num_stack_args; /* not a valid stack index if num_stack_args == 0 */ |
| 67656 | DUK_ASSERT(idx_retbase >= 0); |
| 67657 | |
| 67658 | DUK_ASSERT((duk_idx_t) (thr->valstack_top - thr->valstack_bottom) >= num_stack_args); /* Caller ensures. */ |
| 67659 | DUK_ASSERT((duk_idx_t) (thr->valstack_end - (thr->valstack_bottom + idx_retbase)) >= num_stack_rets); /* Caller ensures. */ |
| 67660 | |
| 67661 | /* Cannot portably debug print a function pointer, hence 'func' not printed! */ |
| 67662 | DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, " |
| 67663 | "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, " |
| 67664 | "entry_act=%p, entry_valstack_bottom_byteoff=%ld, entry_call_recursion_depth=%ld, " |
| 67665 | "entry_curr_thread=%p, entry_thread_state=%ld" , |
| 67666 | (void *) thr, |
| 67667 | (long) num_stack_args, |
| 67668 | (long) num_stack_rets, |
| 67669 | (long) duk_get_top(thr), |
| 67670 | (long) idx_retbase, |
| 67671 | (long) thr->heap->call_recursion_depth, |
| 67672 | (long) thr->heap->call_recursion_limit, |
| 67673 | (void *) entry_act, |
| 67674 | (long) entry_valstack_bottom_byteoff, |
| 67675 | (long) entry_call_recursion_depth, |
| 67676 | (void *) entry_curr_thread, |
| 67677 | (long) entry_thread_state)); |
| 67678 | |
| 67679 | /* Setjmp catchpoint setup. */ |
| 67680 | old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr; |
| 67681 | thr->heap->lj.jmpbuf_ptr = &our_jmpbuf; |
| 67682 | |
| 67683 | /* Prevent yields for the duration of the safe call. This only |
| 67684 | * matters if the executor makes safe calls to functions that |
| 67685 | * yield, this doesn't currently happen. |
| 67686 | */ |
| 67687 | thr->callstack_preventcount++; |
| 67688 | |
| 67689 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 67690 | try { |
| 67691 | #else |
| 67692 | DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf); |
| 67693 | if (DUK_SETJMP(our_jmpbuf.jb) == 0) { |
| 67694 | /* Success path. */ |
| 67695 | #endif |
| 67696 | DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete" )); |
| 67697 | |
| 67698 | duk__handle_safe_call_inner(thr, |
| 67699 | func, |
| 67700 | udata, |
| 67701 | #if defined(DUK_USE_ASSERTIONS) |
| 67702 | entry_valstack_bottom_byteoff, |
| 67703 | entry_callstack_top, |
| 67704 | #endif |
| 67705 | entry_curr_thread, |
| 67706 | entry_thread_state, |
| 67707 | idx_retbase, |
| 67708 | num_stack_rets); |
| 67709 | |
| 67710 | DUK_STATS_INC(thr->heap, stats_safecall_nothrow); |
| 67711 | |
| 67712 | /* Either pointer may be NULL (at entry), so don't assert */ |
| 67713 | thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr; |
| 67714 | |
| 67715 | /* If calls happen inside the safe call, these are restored by |
| 67716 | * whatever calls are made. Reserve cannot decrease. |
| 67717 | */ |
| 67718 | DUK_ASSERT(thr->callstack_curr == entry_act); |
| 67719 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); |
| 67720 | |
| 67721 | retval = DUK_EXEC_SUCCESS; |
| 67722 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 67723 | } catch (duk_internal_exception &exc) { |
| 67724 | DUK_UNREF(exc); |
| 67725 | #else |
| 67726 | } else { |
| 67727 | /* Error path. */ |
| 67728 | #endif |
| 67729 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); |
| 67730 | |
| 67731 | DUK_STATS_INC(thr->heap, stats_safecall_throw); |
| 67732 | |
| 67733 | duk__handle_safe_call_error(thr, |
| 67734 | entry_act, |
| 67735 | #if defined(DUK_USE_ASSERTIONS) |
| 67736 | entry_callstack_top, |
| 67737 | #endif |
| 67738 | entry_curr_thread, |
| 67739 | entry_thread_state, |
| 67740 | idx_retbase, |
| 67741 | num_stack_rets, |
| 67742 | entry_valstack_bottom_byteoff, |
| 67743 | old_jmpbuf_ptr); |
| 67744 | |
| 67745 | retval = DUK_EXEC_ERROR; |
| 67746 | } |
| 67747 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 67748 | catch (duk_fatal_exception &exc) { |
| 67749 | DUK_D(DUK_DPRINT("rethrow duk_fatal_exception" )); |
| 67750 | DUK_UNREF(exc); |
| 67751 | throw; |
| 67752 | } catch (std::exception &exc) { |
| 67753 | const char *what = exc.what(); |
| 67754 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); |
| 67755 | DUK_STATS_INC(thr->heap, stats_safecall_throw); |
| 67756 | if (!what) { |
| 67757 | what = "unknown" ; |
| 67758 | } |
| 67759 | DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)" )); |
| 67760 | try { |
| 67761 | DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)" , what); |
| 67762 | DUK_WO_NORETURN(return 0;); |
| 67763 | } catch (duk_internal_exception exc) { |
| 67764 | DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception" )); |
| 67765 | DUK_UNREF(exc); |
| 67766 | duk__handle_safe_call_error(thr, |
| 67767 | entry_act, |
| 67768 | #if defined(DUK_USE_ASSERTIONS) |
| 67769 | entry_callstack_top, |
| 67770 | #endif |
| 67771 | entry_curr_thread, |
| 67772 | entry_thread_state, |
| 67773 | idx_retbase, |
| 67774 | num_stack_rets, |
| 67775 | entry_valstack_bottom_byteoff, |
| 67776 | old_jmpbuf_ptr); |
| 67777 | retval = DUK_EXEC_ERROR; |
| 67778 | } |
| 67779 | } catch (...) { |
| 67780 | DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)" )); |
| 67781 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); |
| 67782 | DUK_STATS_INC(thr->heap, stats_safecall_throw); |
| 67783 | try { |
| 67784 | DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)" ); |
| 67785 | DUK_WO_NORETURN(return 0;); |
| 67786 | } catch (duk_internal_exception exc) { |
| 67787 | DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception" )); |
| 67788 | DUK_UNREF(exc); |
| 67789 | duk__handle_safe_call_error(thr, |
| 67790 | entry_act, |
| 67791 | #if defined(DUK_USE_ASSERTIONS) |
| 67792 | entry_callstack_top, |
| 67793 | #endif |
| 67794 | entry_curr_thread, |
| 67795 | entry_thread_state, |
| 67796 | idx_retbase, |
| 67797 | num_stack_rets, |
| 67798 | entry_valstack_bottom_byteoff, |
| 67799 | old_jmpbuf_ptr); |
| 67800 | retval = DUK_EXEC_ERROR; |
| 67801 | } |
| 67802 | } |
| 67803 | #endif |
| 67804 | |
| 67805 | DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */ |
| 67806 | |
| 67807 | DUK_ASSERT_LJSTATE_UNSET(thr->heap); |
| 67808 | |
| 67809 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); |
| 67810 | duk__handle_safe_call_shared_unwind(thr, |
| 67811 | idx_retbase, |
| 67812 | num_stack_rets, |
| 67813 | #if defined(DUK_USE_ASSERTIONS) |
| 67814 | entry_callstack_top, |
| 67815 | #endif |
| 67816 | entry_call_recursion_depth, |
| 67817 | entry_curr_thread, |
| 67818 | entry_ptr_curr_pc); |
| 67819 | |
| 67820 | /* Restore preventcount. */ |
| 67821 | thr->callstack_preventcount--; |
| 67822 | DUK_ASSERT(thr->callstack_preventcount == entry_callstack_preventcount); |
| 67823 | |
| 67824 | /* Final asserts. */ |
| 67825 | DUK_ASSERT(thr->callstack_curr == entry_act); |
| 67826 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff); |
| 67827 | DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff); |
| 67828 | DUK_ASSERT(thr->callstack_top == entry_callstack_top); |
| 67829 | DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth); |
| 67830 | DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread); |
| 67831 | DUK_ASSERT(thr->state == entry_thread_state); |
| 67832 | DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc); |
| 67833 | DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets); |
| 67834 | DUK_ASSERT_LJSTATE_UNSET(thr->heap); |
| 67835 | |
| 67836 | /* Pending side effects. */ |
| 67837 | DUK_REFZERO_CHECK_FAST(thr); |
| 67838 | |
| 67839 | return retval; |
| 67840 | } |
| 67841 | |
| 67842 | /* |
| 67843 | * Property-based call (foo.noSuch()) error setup: replace target function |
| 67844 | * on stack top with a hidden Symbol tagged non-callable wrapper object |
| 67845 | * holding the error. The error gets thrown in call handling at the |
| 67846 | * proper spot to follow ECMAScript semantics. |
| 67847 | */ |
| 67848 | |
| 67849 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 67850 | DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_base, duk_tval *tv_key) { |
| 67851 | const char *str_targ, *str_key, *str_base; |
| 67852 | duk_idx_t entry_top; |
| 67853 | |
| 67854 | entry_top = duk_get_top(thr); |
| 67855 | |
| 67856 | /* [ <nargs> target ] */ |
| 67857 | |
| 67858 | /* Must stabilize pointers first. tv_targ is already on stack top. */ |
| 67859 | duk_push_tval(thr, tv_base); |
| 67860 | duk_push_tval(thr, tv_key); |
| 67861 | |
| 67862 | DUK_GC_TORTURE(thr->heap); |
| 67863 | |
| 67864 | duk_push_bare_object(thr); |
| 67865 | |
| 67866 | /* [ <nargs> target base key {} ] */ |
| 67867 | |
| 67868 | /* We only push a wrapped error, replacing the call target (at |
| 67869 | * idx_func) with the error to ensure side effects come out |
| 67870 | * correctly: |
| 67871 | * - Property read |
| 67872 | * - Call argument evaluation |
| 67873 | * - Callability check and error thrown |
| 67874 | * |
| 67875 | * A hidden Symbol on the wrapper object pushed above is used by |
| 67876 | * call handling to figure out the error is to be thrown as is. |
| 67877 | * It is CRITICAL that the hidden Symbol can never occur on a |
| 67878 | * user visible object that may get thrown. |
| 67879 | */ |
| 67880 | |
| 67881 | #if defined(DUK_USE_PARANOID_ERRORS) |
| 67882 | str_targ = duk_get_type_name(thr, -4); |
| 67883 | str_key = duk_get_type_name(thr, -2); |
| 67884 | str_base = duk_get_type_name(thr, -3); |
| 67885 | duk_push_error_object(thr, |
| 67886 | DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, |
| 67887 | "%s not callable (property %s of %s)" , str_targ, str_key, str_base); |
| 67888 | duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); /* Marker property, reuse _Target. */ |
| 67889 | /* [ <nargs> target base key { _Target: error } ] */ |
| 67890 | duk_replace(thr, entry_top - 1); |
| 67891 | #else |
| 67892 | str_targ = duk_push_string_readable(thr, -4); |
| 67893 | str_key = duk_push_string_readable(thr, -3); |
| 67894 | str_base = duk_push_string_readable(thr, -5); |
| 67895 | duk_push_error_object(thr, |
| 67896 | DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, |
| 67897 | "%s not callable (property %s of %s)" , str_targ, str_key, str_base); |
| 67898 | /* [ <nargs> target base key {} str_targ str_key str_base error ] */ |
| 67899 | duk_xdef_prop_stridx(thr, -5, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); /* Marker property, reuse _Target. */ |
| 67900 | /* [ <nargs> target base key { _Target: error } str_targ str_key str_base ] */ |
| 67901 | duk_swap(thr, -4, entry_top - 1); |
| 67902 | /* [ <nargs> { _Target: error } base key target str_targ str_key str_base ] */ |
| 67903 | #endif |
| 67904 | |
| 67905 | /* [ <nregs> { _Target: error } <variable> */ |
| 67906 | duk_set_top(thr, entry_top); |
| 67907 | |
| 67908 | /* [ <nregs> { _Target: error } */ |
| 67909 | DUK_ASSERT(!duk_is_callable(thr, -1)); /* Critical so that call handling will throw the error. */ |
| 67910 | } |
| 67911 | #endif /* DUK_USE_VERBOSE_ERRORS */ |
| 67912 | |
| 67913 | /* automatic undefs */ |
| 67914 | #undef DUK__AUGMENT_CALL_RELAX_COUNT |
| 67915 | #undef DUK__CALL_HANDLING_REQUIRE_STACK |
| 67916 | #line 1 "duk_js_compiler.c" |
| 67917 | /* |
| 67918 | * ECMAScript compiler. |
| 67919 | * |
| 67920 | * Parses an input string and generates a function template result. |
| 67921 | * Compilation may happen in multiple contexts (global code, eval |
| 67922 | * code, function code). |
| 67923 | * |
| 67924 | * The parser uses a traditional top-down recursive parsing for the |
| 67925 | * statement level, and an operator precedence based top-down approach |
| 67926 | * for the expression level. The attempt is to minimize the C stack |
| 67927 | * depth. Bytecode is generated directly without an intermediate |
| 67928 | * representation (tree), at the cost of needing two (and sometimes |
| 67929 | * three) passes over each function. |
| 67930 | * |
| 67931 | * The top-down recursive parser functions are named "duk__parse_XXX". |
| 67932 | * |
| 67933 | * Recursion limits are in key functions to prevent arbitrary C recursion: |
| 67934 | * function body parsing, statement parsing, and expression parsing. |
| 67935 | * |
| 67936 | * See doc/compiler.rst for discussion on the design. |
| 67937 | * |
| 67938 | * A few typing notes: |
| 67939 | * |
| 67940 | * - duk_regconst_t: signed, highest bit set (< 0) means constant, |
| 67941 | * some call sites use -1 for "none" (equivalent to constant 0x7fffffff) |
| 67942 | * - PC values: duk_int_t, negative values used as markers |
| 67943 | */ |
| 67944 | |
| 67945 | /* #include duk_internal.h -> already included */ |
| 67946 | |
| 67947 | /* If highest bit of a register number is set, it refers to a constant instead. |
| 67948 | * When interpreted as a signed value, this means const values are always |
| 67949 | * negative (when interpreted as two's complement). For example DUK__ISREG_TEMP() |
| 67950 | * uses this approach to avoid an explicit DUK__ISREG() check (the condition is |
| 67951 | * logically "'x' is a register AND 'x' >= temp_first"). |
| 67952 | */ |
| 67953 | #define DUK__CONST_MARKER DUK_REGCONST_CONST_MARKER |
| 67954 | #define DUK__REMOVECONST(x) ((x) & ~DUK__CONST_MARKER) |
| 67955 | #define DUK__ISREG(x) ((x) >= 0) |
| 67956 | #define DUK__ISCONST(x) ((x) < 0) |
| 67957 | #define DUK__ISREG_TEMP(comp_ctx,x) ((duk_int32_t) (x) >= (duk_int32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= temp_first && x >= 0 by comparing as signed. */ |
| 67958 | #define DUK__ISREG_NOTTEMP(comp_ctx,x) ((duk_uint32_t) (x) < (duk_uint32_t) ((comp_ctx)->curr_func.temp_first)) /* Check for x >= 0 && x < temp_first by interpreting as unsigned. */ |
| 67959 | #define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next) |
| 67960 | #define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */ |
| 67961 | #define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x)) |
| 67962 | #define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx)) |
| 67963 | #define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count)) |
| 67964 | |
| 67965 | /* Init value set size for array and object literals. */ |
| 67966 | #define DUK__MAX_ARRAY_INIT_VALUES 20 |
| 67967 | #define DUK__MAX_OBJECT_INIT_PAIRS 10 |
| 67968 | |
| 67969 | /* XXX: hack, remove when const lookup is not O(n) */ |
| 67970 | #define DUK__GETCONST_MAX_CONSTS_CHECK 256 |
| 67971 | |
| 67972 | /* These limits are based on bytecode limits. Max temps is limited |
| 67973 | * by duk_hcompfunc nargs/nregs fields being 16 bits. |
| 67974 | */ |
| 67975 | #define DUK__MAX_CONSTS DUK_BC_BC_MAX |
| 67976 | #define DUK__MAX_FUNCS DUK_BC_BC_MAX |
| 67977 | #define DUK__MAX_TEMPS 0xffffL |
| 67978 | |
| 67979 | /* Initial bytecode size allocation. */ |
| 67980 | #if defined(DUK_USE_PREFER_SIZE) |
| 67981 | #define DUK__BC_INITIAL_INSTS 16 |
| 67982 | #else |
| 67983 | #define DUK__BC_INITIAL_INSTS 256 |
| 67984 | #endif |
| 67985 | |
| 67986 | #define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \ |
| 67987 | DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \ |
| 67988 | duk__comp_recursion_increase((comp_ctx)); \ |
| 67989 | } while (0) |
| 67990 | |
| 67991 | #define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \ |
| 67992 | DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \ |
| 67993 | duk__comp_recursion_decrease((comp_ctx)); \ |
| 67994 | } while (0) |
| 67995 | |
| 67996 | /* Value stack slot limits: these are quite approximate right now, and |
| 67997 | * because they overlap in control flow, some could be eliminated. |
| 67998 | */ |
| 67999 | #define DUK__COMPILE_ENTRY_SLOTS 8 |
| 68000 | #define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16 |
| 68001 | #define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16 |
| 68002 | #define DUK__PARSE_STATEMENTS_SLOTS 16 |
| 68003 | #define DUK__PARSE_EXPR_SLOTS 16 |
| 68004 | |
| 68005 | /* Temporary structure used to pass a stack allocated region through |
| 68006 | * duk_safe_call(). |
| 68007 | */ |
| 68008 | typedef struct { |
| 68009 | duk_small_uint_t flags; |
| 68010 | duk_compiler_ctx comp_ctx_alloc; |
| 68011 | duk_lexer_point lex_pt_alloc; |
| 68012 | } duk__compiler_stkstate; |
| 68013 | |
| 68014 | /* |
| 68015 | * Prototypes |
| 68016 | */ |
| 68017 | |
| 68018 | /* lexing */ |
| 68019 | DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect); |
| 68020 | DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect); |
| 68021 | DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx); |
| 68022 | |
| 68023 | /* function helpers */ |
| 68024 | DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx); |
| 68025 | DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx); |
| 68026 | DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg); |
| 68027 | DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx); |
| 68028 | DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx); |
| 68029 | |
| 68030 | /* code emission */ |
| 68031 | DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx); |
| 68032 | DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc); |
| 68033 | DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins); |
| 68034 | DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op); |
| 68035 | DUK_LOCAL_DECL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c); |
| 68036 | DUK_LOCAL_DECL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b); |
| 68037 | DUK_LOCAL_DECL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c); |
| 68038 | #if 0 /* unused */ |
| 68039 | DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a); |
| 68040 | DUK_LOCAL_DECL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b); |
| 68041 | #endif |
| 68042 | DUK_LOCAL_DECL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc); |
| 68043 | DUK_LOCAL_DECL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc); |
| 68044 | DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc); |
| 68045 | DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val); |
| 68046 | DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val); |
| 68047 | DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc); |
| 68048 | DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx); |
| 68049 | DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc); |
| 68050 | DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc); |
| 68051 | DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc); |
| 68052 | DUK_LOCAL_DECL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags); |
| 68053 | DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst); |
| 68054 | DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst); |
| 68055 | DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx); |
| 68056 | |
| 68057 | /* ivalue/ispec helpers */ |
| 68058 | DUK_LOCAL_DECL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst); |
| 68059 | DUK_LOCAL_DECL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68060 | DUK_LOCAL_DECL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68061 | DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h); |
| 68062 | DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst); |
| 68063 | DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst); |
| 68064 | DUK_LOCAL_DECL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num); |
| 68065 | DUK_LOCAL_DECL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx); |
| 68066 | DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next); |
| 68067 | DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx); |
| 68068 | DUK_LOCAL_DECL |
| 68069 | duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx, |
| 68070 | duk_ispec *x, |
| 68071 | duk_regconst_t forced_reg, |
| 68072 | duk_small_uint_t flags); |
| 68073 | DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg); |
| 68074 | DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg); |
| 68075 | DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68076 | DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68077 | DUK_LOCAL_DECL |
| 68078 | duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx, |
| 68079 | duk_ivalue *x, |
| 68080 | duk_regconst_t forced_reg, |
| 68081 | duk_small_uint_t flags); |
| 68082 | DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68083 | #if 0 /* unused */ |
| 68084 | DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68085 | #endif |
| 68086 | DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg); |
| 68087 | DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68088 | DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x); |
| 68089 | |
| 68090 | /* identifier handling */ |
| 68091 | DUK_LOCAL_DECL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx); |
| 68092 | DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname); |
| 68093 | |
| 68094 | /* label handling */ |
| 68095 | DUK_LOCAL_DECL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id); |
| 68096 | DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags); |
| 68097 | DUK_LOCAL_DECL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest); |
| 68098 | DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len); |
| 68099 | |
| 68100 | /* top-down expression parser */ |
| 68101 | DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68102 | DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res); |
| 68103 | DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx); |
| 68104 | DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx); |
| 68105 | |
| 68106 | /* exprtop is the top level variant which resets nud/led counts */ |
| 68107 | DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68108 | DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68109 | |
| 68110 | /* convenience helpers */ |
| 68111 | #if 0 /* unused */ |
| 68112 | DUK_LOCAL_DECL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68113 | #endif |
| 68114 | #if 0 /* unused */ |
| 68115 | DUK_LOCAL_DECL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68116 | #endif |
| 68117 | DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg); |
| 68118 | DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68119 | #if 0 /* unused */ |
| 68120 | DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68121 | #endif |
| 68122 | DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68123 | DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68124 | DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68125 | #if 0 /* unused */ |
| 68126 | DUK_LOCAL_DECL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68127 | #endif |
| 68128 | DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg); |
| 68129 | DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68130 | #if 0 /* unused */ |
| 68131 | DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags); |
| 68132 | #endif |
| 68133 | |
| 68134 | /* expression parsing helpers */ |
| 68135 | DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68136 | DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68137 | DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68138 | |
| 68139 | /* statement parsing */ |
| 68140 | DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname); |
| 68141 | DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags); |
| 68142 | DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); |
| 68143 | DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); |
| 68144 | DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68145 | DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); |
| 68146 | DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site); |
| 68147 | DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68148 | DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68149 | DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68150 | DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68151 | DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res); |
| 68152 | DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem); |
| 68153 | DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id); |
| 68154 | DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof, duk_bool_t regexp_after); |
| 68155 | |
| 68156 | DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_bool_t regexp_after, duk_small_int_t expect_token); |
| 68157 | DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx); |
| 68158 | DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags); |
| 68159 | DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags); |
| 68160 | |
| 68161 | #define DUK__FUNC_FLAG_DECL (1 << 0) /* Parsing a function declaration. */ |
| 68162 | #define DUK__FUNC_FLAG_GETSET (1 << 1) /* Parsing an object literal getter/setter. */ |
| 68163 | #define DUK__FUNC_FLAG_METDEF (1 << 2) /* Parsing an object literal method definition shorthand. */ |
| 68164 | #define DUK__FUNC_FLAG_PUSHNAME_PASS1 (1 << 3) /* Push function name when creating template (first pass only). */ |
| 68165 | #define DUK__FUNC_FLAG_USE_PREVTOKEN (1 << 4) /* Use prev_token to start function parsing (workaround for object literal). */ |
| 68166 | |
| 68167 | /* |
| 68168 | * Parser control values for tokens. The token table is ordered by the |
| 68169 | * DUK_TOK_XXX defines. |
| 68170 | * |
| 68171 | * The binding powers are for lbp() use (i.e. for use in led() context). |
| 68172 | * Binding powers are positive for typing convenience, and bits at the |
| 68173 | * top should be reserved for flags. Binding power step must be higher |
| 68174 | * than 1 so that binding power "lbp - 1" can be used for right associative |
| 68175 | * operators. Currently a step of 2 is used (which frees one more bit for |
| 68176 | * flags). |
| 68177 | */ |
| 68178 | |
| 68179 | /* XXX: actually single step levels would work just fine, clean up */ |
| 68180 | |
| 68181 | /* binding power "levels" (see doc/compiler.rst) */ |
| 68182 | #define DUK__BP_INVALID 0 /* always terminates led() */ |
| 68183 | #define DUK__BP_EOF 2 |
| 68184 | #define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */ |
| 68185 | #define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */ |
| 68186 | #define DUK__BP_COMMA 6 |
| 68187 | #define DUK__BP_ASSIGNMENT 8 |
| 68188 | #define DUK__BP_CONDITIONAL 10 |
| 68189 | #define DUK__BP_LOR 12 |
| 68190 | #define DUK__BP_LAND 14 |
| 68191 | #define DUK__BP_BOR 16 |
| 68192 | #define DUK__BP_BXOR 18 |
| 68193 | #define DUK__BP_BAND 20 |
| 68194 | #define DUK__BP_EQUALITY 22 |
| 68195 | #define DUK__BP_RELATIONAL 24 |
| 68196 | #define DUK__BP_SHIFT 26 |
| 68197 | #define DUK__BP_ADDITIVE 28 |
| 68198 | #define DUK__BP_MULTIPLICATIVE 30 |
| 68199 | #define DUK__BP_EXPONENTIATION 32 |
| 68200 | #define DUK__BP_POSTFIX 34 |
| 68201 | #define DUK__BP_CALL 36 |
| 68202 | #define DUK__BP_MEMBER 38 |
| 68203 | |
| 68204 | #define DUK__TOKEN_LBP_BP_MASK 0x1f |
| 68205 | #define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */ |
| 68206 | #define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */ |
| 68207 | #define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* unused */ |
| 68208 | |
| 68209 | #define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2)) |
| 68210 | |
| 68211 | #define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */ |
| 68212 | #define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags)) |
| 68213 | |
| 68214 | DUK_LOCAL const duk_uint8_t duk__token_lbp[] = { |
| 68215 | DUK__MK_LBP(DUK__BP_EOF), /* DUK_TOK_EOF */ |
| 68216 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_IDENTIFIER */ |
| 68217 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BREAK */ |
| 68218 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CASE */ |
| 68219 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CATCH */ |
| 68220 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONTINUE */ |
| 68221 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEBUGGER */ |
| 68222 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEFAULT */ |
| 68223 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DELETE */ |
| 68224 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DO */ |
| 68225 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ELSE */ |
| 68226 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FINALLY */ |
| 68227 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FOR */ |
| 68228 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FUNCTION */ |
| 68229 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IF */ |
| 68230 | DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_IN */ |
| 68231 | DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_INSTANCEOF */ |
| 68232 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_NEW */ |
| 68233 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_RETURN */ |
| 68234 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SWITCH */ |
| 68235 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_THIS */ |
| 68236 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_THROW */ |
| 68237 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */ |
| 68238 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */ |
| 68239 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */ |
| 68240 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */ |
| 68241 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */ |
| 68242 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */ |
| 68243 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */ |
| 68244 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */ |
| 68245 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */ |
| 68246 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */ |
| 68247 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */ |
| 68248 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPORT */ |
| 68249 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SUPER */ |
| 68250 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NULL */ |
| 68251 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_TRUE */ |
| 68252 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_FALSE */ |
| 68253 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_GET */ |
| 68254 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SET */ |
| 68255 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPLEMENTS */ |
| 68256 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_INTERFACE */ |
| 68257 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LET */ |
| 68258 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PACKAGE */ |
| 68259 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PRIVATE */ |
| 68260 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PROTECTED */ |
| 68261 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PUBLIC */ |
| 68262 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_STATIC */ |
| 68263 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_YIELD */ |
| 68264 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LCURLY */ |
| 68265 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RCURLY */ |
| 68266 | DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_LBRACKET */ |
| 68267 | DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RBRACKET */ |
| 68268 | DUK__MK_LBP(DUK__BP_CALL), /* DUK_TOK_LPAREN */ |
| 68269 | DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RPAREN */ |
| 68270 | DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_PERIOD */ |
| 68271 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SEMICOLON */ |
| 68272 | DUK__MK_LBP(DUK__BP_COMMA), /* DUK_TOK_COMMA */ |
| 68273 | DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LT */ |
| 68274 | DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GT */ |
| 68275 | DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LE */ |
| 68276 | DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GE */ |
| 68277 | DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_EQ */ |
| 68278 | DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_NEQ */ |
| 68279 | DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SEQ */ |
| 68280 | DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SNEQ */ |
| 68281 | DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_ADD */ |
| 68282 | DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_SUB */ |
| 68283 | DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */ |
| 68284 | DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */ |
| 68285 | DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */ |
| 68286 | DUK__MK_LBP(DUK__BP_EXPONENTIATION), /* DUK_TOK_EXP */ |
| 68287 | DUK__MK_LBP_FLAGS(DUK__BP_POSTFIX, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_INCREMENT */ |
| 68288 | DUK__MK_LBP_FLAGS(DUK__BP_POSTFIX, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_DECREMENT */ |
| 68289 | DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */ |
| 68290 | DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ARSHIFT */ |
| 68291 | DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_RSHIFT */ |
| 68292 | DUK__MK_LBP(DUK__BP_BAND), /* DUK_TOK_BAND */ |
| 68293 | DUK__MK_LBP(DUK__BP_BOR), /* DUK_TOK_BOR */ |
| 68294 | DUK__MK_LBP(DUK__BP_BXOR), /* DUK_TOK_BXOR */ |
| 68295 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LNOT */ |
| 68296 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BNOT */ |
| 68297 | DUK__MK_LBP(DUK__BP_LAND), /* DUK_TOK_LAND */ |
| 68298 | DUK__MK_LBP(DUK__BP_LOR), /* DUK_TOK_LOR */ |
| 68299 | DUK__MK_LBP(DUK__BP_CONDITIONAL), /* DUK_TOK_QUESTION */ |
| 68300 | DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_COLON */ |
| 68301 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EQUALSIGN */ |
| 68302 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ADD_EQ */ |
| 68303 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_SUB_EQ */ |
| 68304 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */ |
| 68305 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */ |
| 68306 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */ |
| 68307 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EXP_EQ */ |
| 68308 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */ |
| 68309 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */ |
| 68310 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */ |
| 68311 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */ |
| 68312 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */ |
| 68313 | DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */ |
| 68314 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */ |
| 68315 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */ |
| 68316 | DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */ |
| 68317 | }; |
| 68318 | |
| 68319 | /* |
| 68320 | * Misc helpers |
| 68321 | */ |
| 68322 | |
| 68323 | DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) { |
| 68324 | DUK_ASSERT(comp_ctx != NULL); |
| 68325 | DUK_ASSERT(comp_ctx->recursion_depth >= 0); |
| 68326 | if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) { |
| 68327 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT); |
| 68328 | DUK_WO_NORETURN(return;); |
| 68329 | } |
| 68330 | comp_ctx->recursion_depth++; |
| 68331 | } |
| 68332 | |
| 68333 | DUK_LOCAL void duk__comp_recursion_decrease(duk_compiler_ctx *comp_ctx) { |
| 68334 | DUK_ASSERT(comp_ctx != NULL); |
| 68335 | DUK_ASSERT(comp_ctx->recursion_depth > 0); |
| 68336 | comp_ctx->recursion_depth--; |
| 68337 | } |
| 68338 | |
| 68339 | DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) { |
| 68340 | DUK_UNREF(comp_ctx); |
| 68341 | DUK_ASSERT(h != NULL); |
| 68342 | return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h); |
| 68343 | } |
| 68344 | |
| 68345 | DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) { |
| 68346 | DUK_ASSERT(h != NULL); |
| 68347 | return (comp_ctx->curr_func.is_strict && |
| 68348 | DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h)); |
| 68349 | } |
| 68350 | |
| 68351 | /* |
| 68352 | * Parser duk__advance() token eating functions |
| 68353 | */ |
| 68354 | |
| 68355 | /* XXX: valstack handling is awkward. Add a valstack helper which |
| 68356 | * avoids dup():ing; valstack_copy(src, dst)? |
| 68357 | */ |
| 68358 | |
| 68359 | DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) { |
| 68360 | duk_hthread *thr = comp_ctx->thr; |
| 68361 | duk_bool_t regexp; |
| 68362 | |
| 68363 | DUK_ASSERT_DISABLE(comp_ctx->curr_token.t >= 0); /* unsigned */ |
| 68364 | DUK_ASSERT(comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */ |
| 68365 | |
| 68366 | /* |
| 68367 | * Use current token to decide whether a RegExp can follow. |
| 68368 | * |
| 68369 | * We can use either 't' or 't_nores'; the latter would not |
| 68370 | * recognize keywords. Some keywords can be followed by a |
| 68371 | * RegExp (e.g. "return"), so using 't' is better. This is |
| 68372 | * not trivial, see doc/compiler.rst. |
| 68373 | */ |
| 68374 | |
| 68375 | regexp = 1; |
| 68376 | if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) { |
| 68377 | regexp = 0; |
| 68378 | } |
| 68379 | if (comp_ctx->curr_func.reject_regexp_in_adv) { |
| 68380 | comp_ctx->curr_func.reject_regexp_in_adv = 0; |
| 68381 | regexp = 0; |
| 68382 | } |
| 68383 | if (comp_ctx->curr_func.allow_regexp_in_adv) { |
| 68384 | comp_ctx->curr_func.allow_regexp_in_adv = 0; |
| 68385 | regexp = 1; |
| 68386 | } |
| 68387 | |
| 68388 | if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) { |
| 68389 | DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld" , |
| 68390 | (long) expect, (long) comp_ctx->curr_token.t)); |
| 68391 | DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); |
| 68392 | DUK_WO_NORETURN(return;); |
| 68393 | } |
| 68394 | |
| 68395 | /* make current token the previous; need to fiddle with valstack "backing store" */ |
| 68396 | duk_memcpy(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token)); |
| 68397 | duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx); |
| 68398 | duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx); |
| 68399 | |
| 68400 | /* parse new token */ |
| 68401 | duk_lexer_parse_js_input_element(&comp_ctx->lex, |
| 68402 | &comp_ctx->curr_token, |
| 68403 | comp_ctx->curr_func.is_strict, |
| 68404 | regexp); |
| 68405 | |
| 68406 | DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T " |
| 68407 | "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T" , |
| 68408 | (long) comp_ctx->curr_token.t, |
| 68409 | (long) comp_ctx->curr_token.t_nores, |
| 68410 | (long) comp_ctx->curr_token.start_line, |
| 68411 | (long) comp_ctx->curr_token.lineterm, |
| 68412 | (duk_tval *) duk_get_tval(thr, comp_ctx->tok11_idx), |
| 68413 | (duk_tval *) duk_get_tval(thr, comp_ctx->tok12_idx), |
| 68414 | (long) comp_ctx->prev_token.t, |
| 68415 | (long) comp_ctx->prev_token.t_nores, |
| 68416 | (long) comp_ctx->prev_token.start_line, |
| 68417 | (long) comp_ctx->prev_token.lineterm, |
| 68418 | (duk_tval *) duk_get_tval(thr, comp_ctx->tok21_idx), |
| 68419 | (duk_tval *) duk_get_tval(thr, comp_ctx->tok22_idx))); |
| 68420 | } |
| 68421 | |
| 68422 | /* advance, expecting current token to be a specific token; parse next token in regexp context */ |
| 68423 | DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) { |
| 68424 | duk__advance_helper(comp_ctx, expect); |
| 68425 | } |
| 68426 | |
| 68427 | /* advance, whatever the current token is; parse next token in regexp context */ |
| 68428 | DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) { |
| 68429 | duk__advance_helper(comp_ctx, -1); |
| 68430 | } |
| 68431 | |
| 68432 | /* |
| 68433 | * Helpers for duk_compiler_func. |
| 68434 | */ |
| 68435 | |
| 68436 | /* init function state: inits valstack allocations */ |
| 68437 | DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) { |
| 68438 | duk_compiler_func *func = &comp_ctx->curr_func; |
| 68439 | duk_hthread *thr = comp_ctx->thr; |
| 68440 | duk_idx_t entry_top; |
| 68441 | |
| 68442 | entry_top = duk_get_top(thr); |
| 68443 | |
| 68444 | duk_memzero(func, sizeof(*func)); /* intentional overlap with earlier memzero */ |
| 68445 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 68446 | func->h_name = NULL; |
| 68447 | func->h_consts = NULL; |
| 68448 | func->h_funcs = NULL; |
| 68449 | func->h_decls = NULL; |
| 68450 | func->h_labelnames = NULL; |
| 68451 | func->h_labelinfos = NULL; |
| 68452 | func->h_argnames = NULL; |
| 68453 | func->h_varmap = NULL; |
| 68454 | #endif |
| 68455 | |
| 68456 | duk_require_stack(thr, DUK__FUNCTION_INIT_REQUIRE_SLOTS); |
| 68457 | |
| 68458 | DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr)); |
| 68459 | /* code_idx = entry_top + 0 */ |
| 68460 | |
| 68461 | duk_push_bare_array(thr); |
| 68462 | func->consts_idx = entry_top + 1; |
| 68463 | func->h_consts = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 1); |
| 68464 | DUK_ASSERT(func->h_consts != NULL); |
| 68465 | |
| 68466 | duk_push_bare_array(thr); |
| 68467 | func->funcs_idx = entry_top + 2; |
| 68468 | func->h_funcs = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 2); |
| 68469 | DUK_ASSERT(func->h_funcs != NULL); |
| 68470 | DUK_ASSERT(func->fnum_next == 0); |
| 68471 | |
| 68472 | duk_push_bare_array(thr); |
| 68473 | func->decls_idx = entry_top + 3; |
| 68474 | func->h_decls = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 3); |
| 68475 | DUK_ASSERT(func->h_decls != NULL); |
| 68476 | |
| 68477 | duk_push_bare_array(thr); |
| 68478 | func->labelnames_idx = entry_top + 4; |
| 68479 | func->h_labelnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 4); |
| 68480 | DUK_ASSERT(func->h_labelnames != NULL); |
| 68481 | |
| 68482 | duk_push_dynamic_buffer(thr, 0); |
| 68483 | func->labelinfos_idx = entry_top + 5; |
| 68484 | func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 5); |
| 68485 | DUK_ASSERT(func->h_labelinfos != NULL); |
| 68486 | DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos)); |
| 68487 | |
| 68488 | duk_push_bare_array(thr); |
| 68489 | func->argnames_idx = entry_top + 6; |
| 68490 | func->h_argnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 6); |
| 68491 | DUK_ASSERT(func->h_argnames != NULL); |
| 68492 | |
| 68493 | duk_push_bare_object(thr); |
| 68494 | func->varmap_idx = entry_top + 7; |
| 68495 | func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 7); |
| 68496 | DUK_ASSERT(func->h_varmap != NULL); |
| 68497 | } |
| 68498 | |
| 68499 | /* reset function state (prepare for pass 2) */ |
| 68500 | DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) { |
| 68501 | duk_compiler_func *func = &comp_ctx->curr_func; |
| 68502 | duk_hthread *thr = comp_ctx->thr; |
| 68503 | |
| 68504 | /* reset bytecode buffer but keep current size; pass 2 will |
| 68505 | * require same amount or more. |
| 68506 | */ |
| 68507 | DUK_BW_RESET_SIZE(thr, &func->bw_code); |
| 68508 | |
| 68509 | duk_set_length(thr, func->consts_idx, 0); |
| 68510 | /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */ |
| 68511 | func->fnum_next = 0; |
| 68512 | /* duk_set_length(thr, func->funcs_idx, 0); */ |
| 68513 | duk_set_length(thr, func->labelnames_idx, 0); |
| 68514 | duk_hbuffer_reset(thr, func->h_labelinfos); |
| 68515 | /* keep func->h_argnames; it is fixed for all passes */ |
| 68516 | |
| 68517 | /* truncated in case pass 3 needed */ |
| 68518 | duk_push_bare_object(thr); |
| 68519 | duk_replace(thr, func->varmap_idx); |
| 68520 | func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, func->varmap_idx); |
| 68521 | DUK_ASSERT(func->h_varmap != NULL); |
| 68522 | } |
| 68523 | |
| 68524 | /* cleanup varmap from any null entries, compact it, etc; returns number |
| 68525 | * of final entries after cleanup. |
| 68526 | */ |
| 68527 | DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) { |
| 68528 | duk_hthread *thr = comp_ctx->thr; |
| 68529 | duk_hobject *h_varmap; |
| 68530 | duk_hstring *h_key; |
| 68531 | duk_tval *tv; |
| 68532 | duk_uint32_t i, e_next; |
| 68533 | duk_int_t ret; |
| 68534 | |
| 68535 | /* [ ... varmap ] */ |
| 68536 | |
| 68537 | h_varmap = DUK_GET_HOBJECT_NEGIDX(thr, -1); |
| 68538 | DUK_ASSERT(h_varmap != NULL); |
| 68539 | |
| 68540 | ret = 0; |
| 68541 | e_next = DUK_HOBJECT_GET_ENEXT(h_varmap); |
| 68542 | for (i = 0; i < e_next; i++) { |
| 68543 | h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i); |
| 68544 | if (!h_key) { |
| 68545 | continue; |
| 68546 | } |
| 68547 | |
| 68548 | DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i)); |
| 68549 | |
| 68550 | /* The entries can either be register numbers or 'null' values. |
| 68551 | * Thus, no need to DECREF them and get side effects. DECREF'ing |
| 68552 | * the keys (strings) can cause memory to be freed but no side |
| 68553 | * effects as strings don't have finalizers. This is why we can |
| 68554 | * rely on the object properties not changing from underneath us. |
| 68555 | */ |
| 68556 | |
| 68557 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i); |
| 68558 | if (!DUK_TVAL_IS_NUMBER(tv)) { |
| 68559 | DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); |
| 68560 | DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL); |
| 68561 | DUK_HSTRING_DECREF(thr, h_key); |
| 68562 | /* when key is NULL, value is garbage so no need to set */ |
| 68563 | } else { |
| 68564 | ret++; |
| 68565 | } |
| 68566 | } |
| 68567 | |
| 68568 | duk_compact_m1(thr); |
| 68569 | |
| 68570 | return ret; |
| 68571 | } |
| 68572 | |
| 68573 | /* Convert duk_compiler_func into a function template, leaving the result |
| 68574 | * on top of stack. |
| 68575 | */ |
| 68576 | /* XXX: awkward and bloated asm -- use faster internal accesses */ |
| 68577 | DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) { |
| 68578 | duk_compiler_func *func = &comp_ctx->curr_func; |
| 68579 | duk_hthread *thr = comp_ctx->thr; |
| 68580 | duk_hcompfunc *h_res; |
| 68581 | duk_hbuffer_fixed *h_data; |
| 68582 | duk_size_t consts_count; |
| 68583 | duk_size_t funcs_count; |
| 68584 | duk_size_t code_count; |
| 68585 | duk_size_t code_size; |
| 68586 | duk_size_t data_size; |
| 68587 | duk_size_t i; |
| 68588 | duk_tval *p_const; |
| 68589 | duk_hobject **p_func; |
| 68590 | duk_instr_t *p_instr; |
| 68591 | duk_compiler_instr *q_instr; |
| 68592 | duk_tval *tv; |
| 68593 | duk_bool_t keep_varmap; |
| 68594 | duk_bool_t keep_formals; |
| 68595 | #if !defined(DUK_USE_DEBUGGER_SUPPORT) |
| 68596 | duk_size_t formals_length; |
| 68597 | #endif |
| 68598 | |
| 68599 | DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template" )); |
| 68600 | |
| 68601 | /* |
| 68602 | * Push result object and init its flags |
| 68603 | */ |
| 68604 | |
| 68605 | /* Valstack should suffice here, required on function valstack init */ |
| 68606 | |
| 68607 | h_res = duk_push_hcompfunc(thr); |
| 68608 | DUK_ASSERT(h_res != NULL); |
| 68609 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_res) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 68610 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_res, NULL); /* Function templates are "bare objects". */ |
| 68611 | |
| 68612 | if (func->is_function) { |
| 68613 | DUK_DDD(DUK_DDDPRINT("function -> set NEWENV" )); |
| 68614 | DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res); |
| 68615 | |
| 68616 | if (!func->is_arguments_shadowed) { |
| 68617 | /* arguments object would be accessible; note that shadowing |
| 68618 | * bindings are arguments or function declarations, neither |
| 68619 | * of which are deletable, so this is safe. |
| 68620 | */ |
| 68621 | |
| 68622 | if (func->id_access_arguments || func->may_direct_eval) { |
| 68623 | DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or " |
| 68624 | "indirectly -> set CREATEARGS" )); |
| 68625 | DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res); |
| 68626 | } |
| 68627 | } |
| 68628 | } else if (func->is_eval && func->is_strict) { |
| 68629 | DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV" )); |
| 68630 | DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res); |
| 68631 | } else { |
| 68632 | /* non-strict eval: env is caller's env or global env (direct vs. indirect call) |
| 68633 | * global code: env is is global env |
| 68634 | */ |
| 68635 | DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV" )); |
| 68636 | DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res)); |
| 68637 | } |
| 68638 | |
| 68639 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 68640 | if (func->is_function && func->is_namebinding && func->h_name != NULL) { |
| 68641 | /* Object literal set/get functions have a name (property |
| 68642 | * name) but must not have a lexical name binding, see |
| 68643 | * test-bug-getset-func-name.js. |
| 68644 | */ |
| 68645 | DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING" )); |
| 68646 | DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res); |
| 68647 | } |
| 68648 | #endif |
| 68649 | |
| 68650 | if (func->is_strict) { |
| 68651 | DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT" )); |
| 68652 | DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res); |
| 68653 | } |
| 68654 | |
| 68655 | if (func->is_notail) { |
| 68656 | DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL" )); |
| 68657 | DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res); |
| 68658 | } |
| 68659 | |
| 68660 | if (func->is_constructable) { |
| 68661 | DUK_DDD(DUK_DDDPRINT("function is constructable -> set CONSTRUCTABLE" )); |
| 68662 | DUK_HOBJECT_SET_CONSTRUCTABLE((duk_hobject *) h_res); |
| 68663 | } |
| 68664 | |
| 68665 | /* |
| 68666 | * Build function fixed size 'data' buffer, which contains bytecode, |
| 68667 | * constants, and inner function references. |
| 68668 | * |
| 68669 | * During the building phase 'data' is reachable but incomplete. |
| 68670 | * Only incref's occur during building (no refzero or GC happens), |
| 68671 | * so the building process is atomic. |
| 68672 | */ |
| 68673 | |
| 68674 | consts_count = duk_hobject_get_length(thr, func->h_consts); |
| 68675 | funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3; |
| 68676 | code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr); |
| 68677 | code_size = code_count * sizeof(duk_instr_t); |
| 68678 | |
| 68679 | data_size = consts_count * sizeof(duk_tval) + |
| 68680 | funcs_count * sizeof(duk_hobject *) + |
| 68681 | code_size; |
| 68682 | |
| 68683 | DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> " |
| 68684 | "data_size=%ld*%ld + %ld*%ld + %ld = %ld" , |
| 68685 | (long) consts_count, (long) funcs_count, (long) code_size, |
| 68686 | (long) consts_count, (long) sizeof(duk_tval), |
| 68687 | (long) funcs_count, (long) sizeof(duk_hobject *), |
| 68688 | (long) code_size, (long) data_size)); |
| 68689 | |
| 68690 | duk_push_fixed_buffer_nozero(thr, data_size); |
| 68691 | h_data = (duk_hbuffer_fixed *) (void *) duk_known_hbuffer(thr, -1); |
| 68692 | |
| 68693 | DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data); |
| 68694 | DUK_HEAPHDR_INCREF(thr, h_data); |
| 68695 | |
| 68696 | p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data); |
| 68697 | for (i = 0; i < consts_count; i++) { |
| 68698 | DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* const limits */ |
| 68699 | tv = duk_hobject_find_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i); |
| 68700 | DUK_ASSERT(tv != NULL); |
| 68701 | DUK_TVAL_SET_TVAL(p_const, tv); |
| 68702 | p_const++; |
| 68703 | DUK_TVAL_INCREF(thr, tv); /* may be a string constant */ |
| 68704 | |
| 68705 | DUK_DDD(DUK_DDDPRINT("constant: %!T" , (duk_tval *) tv)); |
| 68706 | } |
| 68707 | |
| 68708 | p_func = (duk_hobject **) p_const; |
| 68709 | DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_res, p_func); |
| 68710 | for (i = 0; i < funcs_count; i++) { |
| 68711 | duk_hobject *h; |
| 68712 | DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */ |
| 68713 | tv = duk_hobject_find_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3)); |
| 68714 | DUK_ASSERT(tv != NULL); |
| 68715 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); |
| 68716 | h = DUK_TVAL_GET_OBJECT(tv); |
| 68717 | DUK_ASSERT(h != NULL); |
| 68718 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(h)); |
| 68719 | *p_func++ = h; |
| 68720 | DUK_HOBJECT_INCREF(thr, h); |
| 68721 | |
| 68722 | DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO" , |
| 68723 | (void *) h, (duk_heaphdr *) h)); |
| 68724 | } |
| 68725 | |
| 68726 | p_instr = (duk_instr_t *) p_func; |
| 68727 | DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_res, p_instr); |
| 68728 | |
| 68729 | /* copy bytecode instructions one at a time */ |
| 68730 | q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code); |
| 68731 | for (i = 0; i < code_count; i++) { |
| 68732 | p_instr[i] = q_instr[i].ins; |
| 68733 | } |
| 68734 | /* Note: 'q_instr' is still used below */ |
| 68735 | |
| 68736 | DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size); |
| 68737 | |
| 68738 | duk_pop(thr); /* 'data' (and everything in it) is reachable through h_res now */ |
| 68739 | |
| 68740 | /* |
| 68741 | * Init non-property result fields |
| 68742 | * |
| 68743 | * 'nregs' controls how large a register frame is allocated. |
| 68744 | * |
| 68745 | * 'nargs' controls how many formal arguments are written to registers: |
| 68746 | * r0, ... r(nargs-1). The remaining registers are initialized to |
| 68747 | * undefined. |
| 68748 | */ |
| 68749 | |
| 68750 | DUK_ASSERT(func->temp_max >= 0); |
| 68751 | h_res->nregs = (duk_uint16_t) func->temp_max; |
| 68752 | h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames); |
| 68753 | DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */ |
| 68754 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 68755 | h_res->start_line = (duk_uint32_t) func->min_line; |
| 68756 | h_res->end_line = (duk_uint32_t) func->max_line; |
| 68757 | #endif |
| 68758 | |
| 68759 | /* |
| 68760 | * Init object properties |
| 68761 | * |
| 68762 | * Properties should be added in decreasing order of access frequency. |
| 68763 | * (Not very critical for function templates.) |
| 68764 | */ |
| 68765 | |
| 68766 | DUK_DDD(DUK_DDDPRINT("init function properties" )); |
| 68767 | |
| 68768 | /* [ ... res ] */ |
| 68769 | |
| 68770 | /* _Varmap: omitted if function is guaranteed not to do a slow path |
| 68771 | * identifier access that might be caught by locally declared variables. |
| 68772 | * The varmap can also be omitted if it turns out empty of actual |
| 68773 | * register mappings after a cleanup. When debugging is enabled, we |
| 68774 | * always need the varmap to be able to lookup variables at any point. |
| 68775 | */ |
| 68776 | |
| 68777 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 68778 | DUK_DD(DUK_DDPRINT("keeping _Varmap because debugger support is enabled" )); |
| 68779 | keep_varmap = 1; |
| 68780 | #else |
| 68781 | if (func->id_access_slow_own || /* directly uses slow accesses that may match own variables */ |
| 68782 | func->id_access_arguments || /* accesses 'arguments' directly */ |
| 68783 | func->may_direct_eval || /* may indirectly slow access through a direct eval */ |
| 68784 | funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */ |
| 68785 | DUK_DD(DUK_DDPRINT("keeping _Varmap because of direct eval, slow path access that may match local variables, or presence of inner functions" )); |
| 68786 | keep_varmap = 1; |
| 68787 | } else { |
| 68788 | DUK_DD(DUK_DDPRINT("dropping _Varmap" )); |
| 68789 | keep_varmap = 0; |
| 68790 | } |
| 68791 | #endif |
| 68792 | |
| 68793 | if (keep_varmap) { |
| 68794 | duk_int_t num_used; |
| 68795 | duk_dup(thr, func->varmap_idx); |
| 68796 | num_used = duk__cleanup_varmap(comp_ctx); |
| 68797 | DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)" , |
| 68798 | (duk_tval *) duk_get_tval(thr, -1), (long) num_used)); |
| 68799 | |
| 68800 | if (num_used > 0) { |
| 68801 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); |
| 68802 | } else { |
| 68803 | DUK_DD(DUK_DDPRINT("varmap is empty after cleanup -> no need to add" )); |
| 68804 | duk_pop(thr); |
| 68805 | } |
| 68806 | } |
| 68807 | |
| 68808 | /* _Formals: omitted if function is guaranteed not to need a (non-strict) |
| 68809 | * arguments object, and _Formals.length matches nargs exactly. |
| 68810 | * |
| 68811 | * Non-arrow functions can't see an outer function's 'argument' binding |
| 68812 | * (because they have their own), but arrow functions can. When arrow |
| 68813 | * functions are added, this condition would need to be added: |
| 68814 | * inner_arrow_funcs_count > 0 inner arrow functions may access 'arguments' |
| 68815 | */ |
| 68816 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 68817 | DUK_DD(DUK_DDPRINT("keeping _Formals because debugger support is enabled" )); |
| 68818 | keep_formals = 1; |
| 68819 | #else |
| 68820 | formals_length = duk_get_length(thr, func->argnames_idx); |
| 68821 | if (formals_length != (duk_size_t) h_res->nargs) { |
| 68822 | /* Nargs not enough for closure .length: keep _Formals regardless |
| 68823 | * of its length. Shouldn't happen in practice at the moment. |
| 68824 | */ |
| 68825 | DUK_DD(DUK_DDPRINT("keeping _Formals because _Formals.length != nargs" )); |
| 68826 | keep_formals = 1; |
| 68827 | } else if ((func->id_access_arguments || func->may_direct_eval) && |
| 68828 | (formals_length > 0)) { |
| 68829 | /* Direct eval (may access 'arguments') or accesses 'arguments' |
| 68830 | * explicitly: keep _Formals unless it is zero length. |
| 68831 | */ |
| 68832 | DUK_DD(DUK_DDPRINT("keeping _Formals because of direct eval or explicit access to 'arguments', and _Formals.length != 0" )); |
| 68833 | keep_formals = 1; |
| 68834 | } else { |
| 68835 | DUK_DD(DUK_DDPRINT("omitting _Formals, nargs matches _Formals.length, so no properties added" )); |
| 68836 | keep_formals = 0; |
| 68837 | } |
| 68838 | #endif |
| 68839 | |
| 68840 | if (keep_formals) { |
| 68841 | duk_dup(thr, func->argnames_idx); |
| 68842 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); |
| 68843 | } |
| 68844 | |
| 68845 | /* name */ |
| 68846 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 68847 | if (func->h_name) { |
| 68848 | duk_push_hstring(thr, func->h_name); |
| 68849 | DUK_DD(DUK_DDPRINT("setting function template .name to %!T" , duk_get_tval(thr, -1))); |
| 68850 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); |
| 68851 | } |
| 68852 | #endif /* DUK_USE_FUNC_NAME_PROPERTY */ |
| 68853 | |
| 68854 | /* _Source */ |
| 68855 | #if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY) |
| 68856 | if (0) { |
| 68857 | /* XXX: Currently function source code is not stored, as it is not |
| 68858 | * required by the standard. Source code should not be stored by |
| 68859 | * default (user should enable it explicitly), and the source should |
| 68860 | * probably be compressed with a trivial text compressor; average |
| 68861 | * compression of 20-30% is quite easy to achieve even with a trivial |
| 68862 | * compressor (RLE + backwards lookup). |
| 68863 | * |
| 68864 | * Debugging needs source code to be useful: sometimes input code is |
| 68865 | * not found in files as it may be generated and then eval()'d, given |
| 68866 | * by dynamic C code, etc. |
| 68867 | * |
| 68868 | * Other issues: |
| 68869 | * |
| 68870 | * - Need tokenizer indices for start and end to substring |
| 68871 | * - Always normalize function declaration part? |
| 68872 | * - If we keep _Formals, only need to store body |
| 68873 | */ |
| 68874 | |
| 68875 | /* |
| 68876 | * For global or eval code this is straightforward. For functions |
| 68877 | * created with the Function constructor we only get the source for |
| 68878 | * the body and must manufacture the "function ..." part. |
| 68879 | * |
| 68880 | * For instance, for constructed functions (v8): |
| 68881 | * |
| 68882 | * > a = new Function("foo", "bar", "print(foo)"); |
| 68883 | * [Function] |
| 68884 | * > a.toString() |
| 68885 | * 'function anonymous(foo,bar) {\nprint(foo)\n}' |
| 68886 | * |
| 68887 | * Similarly for e.g. getters (v8): |
| 68888 | * |
| 68889 | * > x = { get a(foo,bar) { print(foo); } } |
| 68890 | * { a: [Getter] } |
| 68891 | * > Object.getOwnPropertyDescriptor(x, 'a').get.toString() |
| 68892 | * 'function a(foo,bar) { print(foo); }' |
| 68893 | */ |
| 68894 | |
| 68895 | #if 0 |
| 68896 | duk_push_literal(thr, "XXX" ); |
| 68897 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE); |
| 68898 | #endif |
| 68899 | } |
| 68900 | #endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */ |
| 68901 | |
| 68902 | /* _Pc2line */ |
| 68903 | #if defined(DUK_USE_PC2LINE) |
| 68904 | if (1) { |
| 68905 | /* |
| 68906 | * Size-optimized pc->line mapping. |
| 68907 | */ |
| 68908 | |
| 68909 | DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH); |
| 68910 | duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */ |
| 68911 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE); |
| 68912 | |
| 68913 | /* XXX: if assertions enabled, walk through all valid PCs |
| 68914 | * and check line mapping. |
| 68915 | */ |
| 68916 | } |
| 68917 | #endif /* DUK_USE_PC2LINE */ |
| 68918 | |
| 68919 | /* fileName */ |
| 68920 | #if defined(DUK_USE_FUNC_FILENAME_PROPERTY) |
| 68921 | if (comp_ctx->h_filename) { |
| 68922 | /* |
| 68923 | * Source filename (or equivalent), for identifying thrown errors. |
| 68924 | */ |
| 68925 | |
| 68926 | duk_push_hstring(thr, comp_ctx->h_filename); |
| 68927 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE); |
| 68928 | } |
| 68929 | #endif |
| 68930 | |
| 68931 | DUK_DD(DUK_DDPRINT("converted function: %!ixT" , |
| 68932 | (duk_tval *) duk_get_tval(thr, -1))); |
| 68933 | |
| 68934 | /* |
| 68935 | * Compact the function template. |
| 68936 | */ |
| 68937 | |
| 68938 | duk_compact_m1(thr); |
| 68939 | |
| 68940 | /* |
| 68941 | * Debug dumping |
| 68942 | */ |
| 68943 | |
| 68944 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 68945 | { |
| 68946 | duk_hcompfunc *h; |
| 68947 | duk_instr_t *p, *p_start, *p_end; |
| 68948 | |
| 68949 | h = (duk_hcompfunc *) duk_get_hobject(thr, -1); |
| 68950 | p_start = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, h); |
| 68951 | p_end = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, h); |
| 68952 | |
| 68953 | p = p_start; |
| 68954 | while (p < p_end) { |
| 68955 | DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!X) a=%ld b=%ld c=%ld" , |
| 68956 | (long) (p - p_start), |
| 68957 | (duk_instr_t) (*p), |
| 68958 | (unsigned long) (*p), |
| 68959 | (long) DUK_DEC_OP(*p), |
| 68960 | (long) DUK_DEC_OP(*p), |
| 68961 | (long) DUK_DEC_A(*p), |
| 68962 | (long) DUK_DEC_B(*p), |
| 68963 | (long) DUK_DEC_C(*p))); |
| 68964 | p++; |
| 68965 | } |
| 68966 | } |
| 68967 | #endif |
| 68968 | } |
| 68969 | |
| 68970 | /* |
| 68971 | * Code emission helpers |
| 68972 | * |
| 68973 | * Some emission helpers understand the range of target and source reg/const |
| 68974 | * values and automatically emit shuffling code if necessary. This is the |
| 68975 | * case when the slot in question (A, B, C) is used in the standard way and |
| 68976 | * for opcodes the emission helpers explicitly understand (like DUK_OP_MPUTOBJ). |
| 68977 | * |
| 68978 | * The standard way is that: |
| 68979 | * - slot A is a target register |
| 68980 | * - slot B is a source register/constant |
| 68981 | * - slot C is a source register/constant |
| 68982 | * |
| 68983 | * If a slot is used in a non-standard way the caller must indicate this |
| 68984 | * somehow. If a slot is used as a target instead of a source (or vice |
| 68985 | * versa), this can be indicated with a flag to trigger proper shuffling |
| 68986 | * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not |
| 68987 | * register/const related at all, the caller must ensure that the raw value |
| 68988 | * fits into the corresponding slot so as to not trigger shuffling. The |
| 68989 | * caller must set a "no shuffle" flag to ensure compilation fails if |
| 68990 | * shuffling were to be triggered because of an internal error. |
| 68991 | * |
| 68992 | * For slots B and C the raw slot size is 9 bits but one bit is reserved for |
| 68993 | * the reg/const indicator. To use the full 9-bit range for a raw value, |
| 68994 | * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag. |
| 68995 | * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots. |
| 68996 | * |
| 68997 | * There is call handling specific understanding in the A-B-C emitter to |
| 68998 | * convert call setup and call instructions into indirect ones if necessary. |
| 68999 | */ |
| 69000 | |
| 69001 | /* Code emission flags, passed in the 'opcode' field. Opcode + flags |
| 69002 | * fit into 16 bits for now, so use duk_small_uint_t. |
| 69003 | */ |
| 69004 | #define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8) |
| 69005 | #define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9) |
| 69006 | #define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10) |
| 69007 | #define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */ |
| 69008 | #define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */ |
| 69009 | #define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */ |
| 69010 | #define DUK__EMIT_FLAG_BC_REGCONST (1 << 14) /* slots B and C are reg/const */ |
| 69011 | #define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */ |
| 69012 | |
| 69013 | /* XXX: macro smaller than call? */ |
| 69014 | DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) { |
| 69015 | duk_compiler_func *func; |
| 69016 | func = &comp_ctx->curr_func; |
| 69017 | return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr)); |
| 69018 | } |
| 69019 | |
| 69020 | DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) { |
| 69021 | DUK_ASSERT(pc >= 0); |
| 69022 | DUK_ASSERT((duk_size_t) pc < (duk_size_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr))); |
| 69023 | return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc; |
| 69024 | } |
| 69025 | |
| 69026 | /* emit instruction; could return PC but that's not needed in the majority |
| 69027 | * of cases. |
| 69028 | */ |
| 69029 | DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) { |
| 69030 | #if defined(DUK_USE_PC2LINE) |
| 69031 | duk_int_t line; |
| 69032 | #endif |
| 69033 | duk_compiler_instr *instr; |
| 69034 | |
| 69035 | DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I" , |
| 69036 | (unsigned long) ins, |
| 69037 | (long) comp_ctx->curr_token.start_line, |
| 69038 | (long) comp_ctx->prev_token.start_line, |
| 69039 | (long) duk__get_current_pc(comp_ctx), |
| 69040 | (duk_instr_t) ins)); |
| 69041 | |
| 69042 | instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr)); |
| 69043 | DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr)); |
| 69044 | |
| 69045 | #if defined(DUK_USE_PC2LINE) |
| 69046 | /* The line number tracking is a bit inconsistent right now, which |
| 69047 | * affects debugger accuracy. Mostly call sites emit opcodes when |
| 69048 | * they have parsed a token (say a terminating semicolon) and called |
| 69049 | * duk__advance(). In this case the line number of the previous |
| 69050 | * token is the most accurate one (except in prologue where |
| 69051 | * prev_token.start_line is 0). This is probably not 100% correct |
| 69052 | * right now. |
| 69053 | */ |
| 69054 | /* approximation, close enough */ |
| 69055 | line = comp_ctx->prev_token.start_line; |
| 69056 | if (line == 0) { |
| 69057 | line = comp_ctx->curr_token.start_line; |
| 69058 | } |
| 69059 | #endif |
| 69060 | |
| 69061 | instr->ins = ins; |
| 69062 | #if defined(DUK_USE_PC2LINE) |
| 69063 | instr->line = (duk_uint32_t) line; |
| 69064 | #endif |
| 69065 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 69066 | if (line < comp_ctx->curr_func.min_line) { |
| 69067 | comp_ctx->curr_func.min_line = line; |
| 69068 | } |
| 69069 | if (line > comp_ctx->curr_func.max_line) { |
| 69070 | comp_ctx->curr_func.max_line = line; |
| 69071 | } |
| 69072 | #endif |
| 69073 | |
| 69074 | /* Limit checks for bytecode byte size and line number. */ |
| 69075 | if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) { |
| 69076 | goto fail_bc_limit; |
| 69077 | } |
| 69078 | #if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS) |
| 69079 | #if defined(DUK_USE_BUFLEN16) |
| 69080 | /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */ |
| 69081 | if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) { |
| 69082 | goto fail_bc_limit; |
| 69083 | } |
| 69084 | #else |
| 69085 | if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) { |
| 69086 | goto fail_bc_limit; |
| 69087 | } |
| 69088 | #endif |
| 69089 | #endif |
| 69090 | |
| 69091 | return; |
| 69092 | |
| 69093 | fail_bc_limit: |
| 69094 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT); |
| 69095 | DUK_WO_NORETURN(return;); |
| 69096 | } |
| 69097 | |
| 69098 | /* Update function min/max line from current token. Needed to improve |
| 69099 | * function line range information for debugging, so that e.g. opening |
| 69100 | * curly brace is covered by line range even when no opcodes are emitted |
| 69101 | * for the line containing the brace. |
| 69102 | */ |
| 69103 | DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) { |
| 69104 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 69105 | duk_int_t line; |
| 69106 | |
| 69107 | line = comp_ctx->curr_token.start_line; |
| 69108 | if (line == 0) { |
| 69109 | return; |
| 69110 | } |
| 69111 | if (line < comp_ctx->curr_func.min_line) { |
| 69112 | comp_ctx->curr_func.min_line = line; |
| 69113 | } |
| 69114 | if (line > comp_ctx->curr_func.max_line) { |
| 69115 | comp_ctx->curr_func.max_line = line; |
| 69116 | } |
| 69117 | #else |
| 69118 | DUK_UNREF(comp_ctx); |
| 69119 | #endif |
| 69120 | } |
| 69121 | |
| 69122 | DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) { |
| 69123 | duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0)); |
| 69124 | } |
| 69125 | |
| 69126 | /* Important main primitive. */ |
| 69127 | DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c) { |
| 69128 | duk_instr_t ins = 0; |
| 69129 | duk_int_t a_out = -1; |
| 69130 | duk_int_t b_out = -1; |
| 69131 | duk_int_t c_out = -1; |
| 69132 | duk_int_t tmp; |
| 69133 | duk_small_uint_t op = op_flags & 0xffU; |
| 69134 | |
| 69135 | DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld" , |
| 69136 | (unsigned long) op_flags, (long) a, (long) b, (long) c)); |
| 69137 | |
| 69138 | /* We could rely on max temp/const checks: if they don't exceed BC |
| 69139 | * limit, nothing here can either (just asserts would be enough). |
| 69140 | * Currently we check for the limits, which provides additional |
| 69141 | * protection against creating invalid bytecode due to compiler |
| 69142 | * bugs. |
| 69143 | */ |
| 69144 | |
| 69145 | DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */ |
| 69146 | DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX); |
| 69147 | DUK_ASSERT(DUK__ISREG(a)); |
| 69148 | DUK_ASSERT(b != -1); /* Not 'none'. */ |
| 69149 | DUK_ASSERT(c != -1); /* Not 'none'. */ |
| 69150 | |
| 69151 | /* Input shuffling happens before the actual operation, while output |
| 69152 | * shuffling happens afterwards. Output shuffling decisions are still |
| 69153 | * made at the same time to reduce branch clutter; output shuffle decisions |
| 69154 | * are recorded into X_out variables. |
| 69155 | */ |
| 69156 | |
| 69157 | /* Slot A: currently no support for reg/const. */ |
| 69158 | |
| 69159 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69160 | if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) { |
| 69161 | #else |
| 69162 | if (a <= DUK_BC_A_MAX) { |
| 69163 | #endif |
| 69164 | ; |
| 69165 | } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) { |
| 69166 | DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld" , (long) a)); |
| 69167 | goto error_outofregs; |
| 69168 | } else if (a <= DUK_BC_BC_MAX) { |
| 69169 | comp_ctx->curr_func.needs_shuffle = 1; |
| 69170 | tmp = comp_ctx->curr_func.shuffle1; |
| 69171 | if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) { |
| 69172 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a)); |
| 69173 | } else { |
| 69174 | /* Output shuffle needed after main operation */ |
| 69175 | a_out = a; |
| 69176 | |
| 69177 | /* The DUK_OP_CSVAR output shuffle assumes shuffle registers are |
| 69178 | * consecutive. |
| 69179 | */ |
| 69180 | DUK_ASSERT((comp_ctx->curr_func.shuffle1 == 0 && comp_ctx->curr_func.shuffle2 == 0) || |
| 69181 | (comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1)); |
| 69182 | if (op == DUK_OP_CSVAR) { |
| 69183 | /* For CSVAR the limit is one smaller because output shuffle |
| 69184 | * must be able to express 'a + 1' in BC. |
| 69185 | */ |
| 69186 | if (a + 1 > DUK_BC_BC_MAX) { |
| 69187 | goto error_outofregs; |
| 69188 | } |
| 69189 | } |
| 69190 | } |
| 69191 | a = tmp; |
| 69192 | } else { |
| 69193 | DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld" , (long) a)); |
| 69194 | goto error_outofregs; |
| 69195 | } |
| 69196 | |
| 69197 | /* Slot B: reg/const support, mapped to bit 0 of opcode. */ |
| 69198 | |
| 69199 | if ((b & DUK__CONST_MARKER) != 0) { |
| 69200 | DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0); |
| 69201 | DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0); |
| 69202 | b = b & ~DUK__CONST_MARKER; |
| 69203 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69204 | if (0) { |
| 69205 | #else |
| 69206 | if (b <= 0xff) { |
| 69207 | #endif |
| 69208 | if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) { |
| 69209 | /* Opcode follows B/C reg/const convention. */ |
| 69210 | DUK_ASSERT((op & 0x01) == 0); |
| 69211 | ins |= DUK_ENC_OP_A_B_C(0x01, 0, 0, 0); /* const flag for B */ |
| 69212 | } else { |
| 69213 | DUK_D(DUK_DPRINT("B is const, opcode is not B/C reg/const: %x" , op_flags)); |
| 69214 | } |
| 69215 | } else if (b <= DUK_BC_BC_MAX) { |
| 69216 | comp_ctx->curr_func.needs_shuffle = 1; |
| 69217 | tmp = comp_ctx->curr_func.shuffle2; |
| 69218 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b)); |
| 69219 | b = tmp; |
| 69220 | } else { |
| 69221 | DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld" , (long) b)); |
| 69222 | goto error_outofregs; |
| 69223 | } |
| 69224 | } else { |
| 69225 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69226 | if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) { |
| 69227 | #else |
| 69228 | if (b <= 0xff) { |
| 69229 | #endif |
| 69230 | ; |
| 69231 | } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) { |
| 69232 | if (b > DUK_BC_B_MAX) { |
| 69233 | /* Note: 0xff != DUK_BC_B_MAX */ |
| 69234 | DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld" , (long) b)); |
| 69235 | goto error_outofregs; |
| 69236 | } |
| 69237 | } else if (b <= DUK_BC_BC_MAX) { |
| 69238 | comp_ctx->curr_func.needs_shuffle = 1; |
| 69239 | tmp = comp_ctx->curr_func.shuffle2; |
| 69240 | if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) { |
| 69241 | /* Output shuffle needed after main operation */ |
| 69242 | b_out = b; |
| 69243 | } |
| 69244 | if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET)) { |
| 69245 | if (op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) { |
| 69246 | /* Special handling for MPUTOBJ/MPUTARR shuffling. |
| 69247 | * For each, slot B identifies the first register of a range |
| 69248 | * of registers, so normal shuffling won't work. Instead, |
| 69249 | * an indirect version of the opcode is used. |
| 69250 | */ |
| 69251 | DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0); |
| 69252 | duk__emit_load_int32_noshuffle(comp_ctx, tmp, b); |
| 69253 | DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1); |
| 69254 | DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1); |
| 69255 | op_flags++; /* indirect opcode follows direct */ |
| 69256 | } else { |
| 69257 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b)); |
| 69258 | } |
| 69259 | } |
| 69260 | b = tmp; |
| 69261 | } else { |
| 69262 | DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld" , (long) b)); |
| 69263 | goto error_outofregs; |
| 69264 | } |
| 69265 | } |
| 69266 | |
| 69267 | /* Slot C: reg/const support, mapped to bit 1 of opcode. */ |
| 69268 | |
| 69269 | if ((c & DUK__CONST_MARKER) != 0) { |
| 69270 | DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0); |
| 69271 | DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0); |
| 69272 | c = c & ~DUK__CONST_MARKER; |
| 69273 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69274 | if (0) { |
| 69275 | #else |
| 69276 | if (c <= 0xff) { |
| 69277 | #endif |
| 69278 | if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) { |
| 69279 | /* Opcode follows B/C reg/const convention. */ |
| 69280 | DUK_ASSERT((op & 0x02) == 0); |
| 69281 | ins |= DUK_ENC_OP_A_B_C(0x02, 0, 0, 0); /* const flag for C */ |
| 69282 | } else { |
| 69283 | DUK_D(DUK_DPRINT("C is const, opcode is not B/C reg/const: %x" , op_flags)); |
| 69284 | } |
| 69285 | } else if (c <= DUK_BC_BC_MAX) { |
| 69286 | comp_ctx->curr_func.needs_shuffle = 1; |
| 69287 | tmp = comp_ctx->curr_func.shuffle3; |
| 69288 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c)); |
| 69289 | c = tmp; |
| 69290 | } else { |
| 69291 | DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld" , (long) c)); |
| 69292 | goto error_outofregs; |
| 69293 | } |
| 69294 | } else { |
| 69295 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69296 | if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) { |
| 69297 | #else |
| 69298 | if (c <= 0xff) { |
| 69299 | #endif |
| 69300 | ; |
| 69301 | } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) { |
| 69302 | if (c > DUK_BC_C_MAX) { |
| 69303 | /* Note: 0xff != DUK_BC_C_MAX */ |
| 69304 | DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld" , (long) c)); |
| 69305 | goto error_outofregs; |
| 69306 | } |
| 69307 | } else if (c <= DUK_BC_BC_MAX) { |
| 69308 | comp_ctx->curr_func.needs_shuffle = 1; |
| 69309 | tmp = comp_ctx->curr_func.shuffle3; |
| 69310 | if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) { |
| 69311 | /* Output shuffle needed after main operation */ |
| 69312 | c_out = c; |
| 69313 | } else { |
| 69314 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c)); |
| 69315 | } |
| 69316 | c = tmp; |
| 69317 | } else { |
| 69318 | DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld" , (long) c)); |
| 69319 | goto error_outofregs; |
| 69320 | } |
| 69321 | } |
| 69322 | |
| 69323 | /* Main operation */ |
| 69324 | |
| 69325 | DUK_ASSERT(a >= DUK_BC_A_MIN); |
| 69326 | DUK_ASSERT(a <= DUK_BC_A_MAX); |
| 69327 | DUK_ASSERT(b >= DUK_BC_B_MIN); |
| 69328 | DUK_ASSERT(b <= DUK_BC_B_MAX); |
| 69329 | DUK_ASSERT(c >= DUK_BC_C_MIN); |
| 69330 | DUK_ASSERT(c <= DUK_BC_C_MAX); |
| 69331 | |
| 69332 | ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c); |
| 69333 | duk__emit(comp_ctx, ins); |
| 69334 | |
| 69335 | /* NEXTENUM needs a jump slot right after the main instruction. |
| 69336 | * When the JUMP is taken, output spilling is not needed so this |
| 69337 | * workaround is possible. The jump slot PC is exceptionally |
| 69338 | * plumbed through comp_ctx to minimize call sites. |
| 69339 | */ |
| 69340 | if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) { |
| 69341 | comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx); |
| 69342 | duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0); |
| 69343 | } |
| 69344 | |
| 69345 | /* Output shuffling: only one output register is realistically possible. |
| 69346 | * |
| 69347 | * (Zero would normally be an OK marker value: if the target register |
| 69348 | * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE |
| 69349 | * this is no longer true, so use -1 as a marker instead.) |
| 69350 | */ |
| 69351 | |
| 69352 | if (a_out >= 0) { |
| 69353 | DUK_ASSERT(b_out < 0); |
| 69354 | DUK_ASSERT(c_out < 0); |
| 69355 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out)); |
| 69356 | |
| 69357 | if (op == DUK_OP_CSVAR) { |
| 69358 | /* Special handling for CSVAR shuffling. The variable lookup |
| 69359 | * results in a <value, this binding> pair in successive |
| 69360 | * registers so use two shuffle registers and two output |
| 69361 | * loads. (In practice this is dead code because temp/const |
| 69362 | * limit is reached first.) |
| 69363 | */ |
| 69364 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a + 1, a_out + 1)); |
| 69365 | } |
| 69366 | } else if (b_out >= 0) { |
| 69367 | DUK_ASSERT(a_out < 0); |
| 69368 | DUK_ASSERT(c_out < 0); |
| 69369 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out)); |
| 69370 | } else if (c_out >= 0) { |
| 69371 | DUK_ASSERT(b_out < 0); |
| 69372 | DUK_ASSERT(c_out < 0); |
| 69373 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out)); |
| 69374 | } |
| 69375 | |
| 69376 | return; |
| 69377 | |
| 69378 | error_outofregs: |
| 69379 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); |
| 69380 | DUK_WO_NORETURN(return;); |
| 69381 | } |
| 69382 | |
| 69383 | /* For many of the helpers below it'd be technically correct to add |
| 69384 | * "no shuffle" flags for parameters passed in as zero. For example, |
| 69385 | * duk__emit_a_b() should call duk__emit_a_b_c() with C set to 0, and |
| 69386 | * DUK__EMIT_FLAG_NO_SHUFFLE_C added to op_flags. However, since the |
| 69387 | * C value is 0, it'll never get shuffled so adding the flag is just |
| 69388 | * unnecessary additional code. This is unfortunately not true for |
| 69389 | * "shuffle torture" mode which needs special handling. |
| 69390 | */ |
| 69391 | |
| 69392 | DUK_LOCAL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b) { |
| 69393 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69394 | op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_C; |
| 69395 | #endif |
| 69396 | duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0); |
| 69397 | } |
| 69398 | |
| 69399 | DUK_LOCAL void duk__emit_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b, duk_regconst_t c) { |
| 69400 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69401 | op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A; |
| 69402 | #endif |
| 69403 | duk__emit_a_b_c(comp_ctx, op_flags, 0, b, c); |
| 69404 | } |
| 69405 | |
| 69406 | #if 0 /* unused */ |
| 69407 | DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) { |
| 69408 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69409 | op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C; |
| 69410 | #endif |
| 69411 | duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0); |
| 69412 | } |
| 69413 | #endif |
| 69414 | |
| 69415 | #if 0 /* unused */ |
| 69416 | DUK_LOCAL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b) { |
| 69417 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69418 | op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C; |
| 69419 | #endif |
| 69420 | duk__emit_a_b_c(comp_ctx, op_flags, 0, b, 0); |
| 69421 | } |
| 69422 | #endif |
| 69423 | |
| 69424 | DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc) { |
| 69425 | duk_instr_t ins; |
| 69426 | duk_int_t tmp; |
| 69427 | |
| 69428 | /* allow caller to give a const number with the DUK__CONST_MARKER */ |
| 69429 | DUK_ASSERT(bc != -1); /* Not 'none'. */ |
| 69430 | bc = bc & (~DUK__CONST_MARKER); |
| 69431 | |
| 69432 | DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */ |
| 69433 | DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX); |
| 69434 | DUK_ASSERT(bc >= DUK_BC_BC_MIN); |
| 69435 | DUK_ASSERT(bc <= DUK_BC_BC_MAX); |
| 69436 | DUK_ASSERT((bc & DUK__CONST_MARKER) == 0); |
| 69437 | |
| 69438 | if (bc <= DUK_BC_BC_MAX) { |
| 69439 | ; |
| 69440 | } else { |
| 69441 | /* No BC shuffling now. */ |
| 69442 | goto error_outofregs; |
| 69443 | } |
| 69444 | |
| 69445 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69446 | if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) { |
| 69447 | #else |
| 69448 | if (a <= DUK_BC_A_MAX) { |
| 69449 | #endif |
| 69450 | ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc); |
| 69451 | duk__emit(comp_ctx, ins); |
| 69452 | } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) { |
| 69453 | goto error_outofregs; |
| 69454 | } else if ((op_flags & 0xf0U) == DUK_OP_CALL0) { |
| 69455 | comp_ctx->curr_func.needs_shuffle = 1; |
| 69456 | tmp = comp_ctx->curr_func.shuffle1; |
| 69457 | duk__emit_load_int32_noshuffle(comp_ctx, tmp, a); |
| 69458 | op_flags |= DUK_BC_CALL_FLAG_INDIRECT; |
| 69459 | ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc); |
| 69460 | duk__emit(comp_ctx, ins); |
| 69461 | } else if (a <= DUK_BC_BC_MAX) { |
| 69462 | comp_ctx->curr_func.needs_shuffle = 1; |
| 69463 | tmp = comp_ctx->curr_func.shuffle1; |
| 69464 | ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc); |
| 69465 | if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) { |
| 69466 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a)); |
| 69467 | duk__emit(comp_ctx, ins); |
| 69468 | } else { |
| 69469 | duk__emit(comp_ctx, ins); |
| 69470 | duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a)); |
| 69471 | } |
| 69472 | } else { |
| 69473 | goto error_outofregs; |
| 69474 | } |
| 69475 | return; |
| 69476 | |
| 69477 | error_outofregs: |
| 69478 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); |
| 69479 | DUK_WO_NORETURN(return;); |
| 69480 | } |
| 69481 | |
| 69482 | DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) { |
| 69483 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69484 | op |= DUK__EMIT_FLAG_NO_SHUFFLE_A; |
| 69485 | #endif |
| 69486 | duk__emit_a_bc(comp_ctx, op, 0, bc); |
| 69487 | } |
| 69488 | |
| 69489 | DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) { |
| 69490 | duk_instr_t ins; |
| 69491 | |
| 69492 | DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN); /* unsigned */ |
| 69493 | DUK_ASSERT(op <= DUK_BC_OP_MAX); |
| 69494 | DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */ |
| 69495 | DUK_ASSERT(abc <= DUK_BC_ABC_MAX); |
| 69496 | DUK_ASSERT((abc & DUK__CONST_MARKER) == 0); |
| 69497 | DUK_ASSERT(abc != -1); /* Not 'none'. */ |
| 69498 | |
| 69499 | if (abc <= DUK_BC_ABC_MAX) { |
| 69500 | ; |
| 69501 | } else { |
| 69502 | goto error_outofregs; |
| 69503 | } |
| 69504 | ins = DUK_ENC_OP_ABC(op, abc); |
| 69505 | DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!X) abc=%ld (%!I)" , |
| 69506 | (unsigned long) ins, (long) comp_ctx->curr_token.start_line, |
| 69507 | (long) duk__get_current_pc(comp_ctx), (long) op, (long) op, |
| 69508 | (long) abc, (duk_instr_t) ins)); |
| 69509 | duk__emit(comp_ctx, ins); |
| 69510 | return; |
| 69511 | |
| 69512 | error_outofregs: |
| 69513 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); |
| 69514 | DUK_WO_NORETURN(return;); |
| 69515 | } |
| 69516 | |
| 69517 | DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val, duk_small_uint_t op_flags) { |
| 69518 | /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX |
| 69519 | * would only shuffle once (instead of twice). The current code works |
| 69520 | * though, and has a smaller compiler footprint. |
| 69521 | */ |
| 69522 | |
| 69523 | if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) && |
| 69524 | (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) { |
| 69525 | DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld" , (long) reg, (long) val)); |
| 69526 | duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS)); |
| 69527 | } else { |
| 69528 | duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT; |
| 69529 | duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1); |
| 69530 | DUK_ASSERT(lo >= 0); |
| 69531 | DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld" , |
| 69532 | (long) reg, (long) val, (long) hi, (long) lo)); |
| 69533 | duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS)); |
| 69534 | duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo); |
| 69535 | } |
| 69536 | } |
| 69537 | |
| 69538 | DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) { |
| 69539 | duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/); |
| 69540 | } |
| 69541 | |
| 69542 | #if defined(DUK_USE_SHUFFLE_TORTURE) |
| 69543 | /* Used by duk__emit*() calls so that we don't shuffle the loadints that |
| 69544 | * are needed to handle indirect opcodes. |
| 69545 | */ |
| 69546 | DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) { |
| 69547 | duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/); |
| 69548 | } |
| 69549 | #else |
| 69550 | DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) { |
| 69551 | /* When torture not enabled, can just use the same helper because |
| 69552 | * 'reg' won't get spilled. |
| 69553 | */ |
| 69554 | DUK_ASSERT(reg <= DUK_BC_A_MAX); |
| 69555 | duk__emit_load_int32(comp_ctx, reg, val); |
| 69556 | } |
| 69557 | #endif |
| 69558 | |
| 69559 | DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) { |
| 69560 | duk_int_t curr_pc; |
| 69561 | duk_int_t offset; |
| 69562 | |
| 69563 | curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr)); |
| 69564 | offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1; |
| 69565 | DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN); |
| 69566 | DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX); |
| 69567 | duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS)); |
| 69568 | } |
| 69569 | |
| 69570 | DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) { |
| 69571 | duk_int_t ret; |
| 69572 | |
| 69573 | ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */ |
| 69574 | duk__emit_op_only(comp_ctx, DUK_OP_JUMP); |
| 69575 | return ret; |
| 69576 | } |
| 69577 | |
| 69578 | /* Insert an empty jump in the middle of code emitted earlier. This is |
| 69579 | * currently needed for compiling for-in. |
| 69580 | */ |
| 69581 | DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) { |
| 69582 | #if defined(DUK_USE_PC2LINE) |
| 69583 | duk_int_t line; |
| 69584 | #endif |
| 69585 | duk_compiler_instr *instr; |
| 69586 | duk_size_t offset; |
| 69587 | |
| 69588 | DUK_ASSERT(jump_pc >= 0); |
| 69589 | offset = (duk_size_t) jump_pc * sizeof(duk_compiler_instr); |
| 69590 | instr = (duk_compiler_instr *) (void *) |
| 69591 | DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr, |
| 69592 | &comp_ctx->curr_func.bw_code, |
| 69593 | offset, |
| 69594 | sizeof(duk_compiler_instr)); |
| 69595 | |
| 69596 | #if defined(DUK_USE_PC2LINE) |
| 69597 | line = comp_ctx->curr_token.start_line; /* approximation, close enough */ |
| 69598 | #endif |
| 69599 | instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0); |
| 69600 | #if defined(DUK_USE_PC2LINE) |
| 69601 | instr->line = (duk_uint32_t) line; |
| 69602 | #endif |
| 69603 | |
| 69604 | DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr)); |
| 69605 | if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) { |
| 69606 | goto fail_bc_limit; |
| 69607 | } |
| 69608 | return; |
| 69609 | |
| 69610 | fail_bc_limit: |
| 69611 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT); |
| 69612 | DUK_WO_NORETURN(return;); |
| 69613 | } |
| 69614 | |
| 69615 | /* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional |
| 69616 | * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this). |
| 69617 | */ |
| 69618 | DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) { |
| 69619 | duk_compiler_instr *instr; |
| 69620 | duk_int_t offset; |
| 69621 | |
| 69622 | /* allow negative PCs, behave as a no-op */ |
| 69623 | if (jump_pc < 0) { |
| 69624 | DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld" , |
| 69625 | (long) jump_pc, (long) target_pc)); |
| 69626 | return; |
| 69627 | } |
| 69628 | DUK_ASSERT(jump_pc >= 0); |
| 69629 | |
| 69630 | /* XXX: range assert */ |
| 69631 | instr = duk__get_instr_ptr(comp_ctx, jump_pc); |
| 69632 | DUK_ASSERT(instr != NULL); |
| 69633 | |
| 69634 | /* XXX: range assert */ |
| 69635 | offset = target_pc - jump_pc - 1; |
| 69636 | |
| 69637 | instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS); |
| 69638 | DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld" , |
| 69639 | (long) jump_pc, (long) target_pc, (long) offset)); |
| 69640 | } |
| 69641 | |
| 69642 | DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) { |
| 69643 | duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx)); |
| 69644 | } |
| 69645 | |
| 69646 | DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags) { |
| 69647 | duk_compiler_instr *instr; |
| 69648 | |
| 69649 | DUK_ASSERT(DUK__ISREG(reg_catch)); |
| 69650 | |
| 69651 | instr = duk__get_instr_ptr(comp_ctx, ldconst_pc); |
| 69652 | DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST); |
| 69653 | DUK_ASSERT(instr != NULL); |
| 69654 | if (const_varname & DUK__CONST_MARKER) { |
| 69655 | /* Have a catch variable. */ |
| 69656 | const_varname = const_varname & (~DUK__CONST_MARKER); |
| 69657 | if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) { |
| 69658 | /* Catch attempts to use out-of-range reg/const. Without this |
| 69659 | * check Duktape 0.12.0 could generate invalid code which caused |
| 69660 | * an assert failure on execution. This error is triggered e.g. |
| 69661 | * for functions with a lot of constants and a try-catch statement. |
| 69662 | * Shuffling or opcode semantics change is needed to fix the issue. |
| 69663 | * See: test-bug-trycatch-many-constants.js. |
| 69664 | */ |
| 69665 | DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)" , |
| 69666 | (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname)); |
| 69667 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT); |
| 69668 | DUK_WO_NORETURN(return;); |
| 69669 | } |
| 69670 | instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname); |
| 69671 | } else { |
| 69672 | /* No catch variable, e.g. a try-finally; replace LDCONST with |
| 69673 | * NOP to avoid a bogus LDCONST. |
| 69674 | */ |
| 69675 | instr->ins = DUK_ENC_OP(DUK_OP_NOP); |
| 69676 | } |
| 69677 | |
| 69678 | instr = duk__get_instr_ptr(comp_ctx, trycatch_pc); |
| 69679 | DUK_ASSERT(instr != NULL); |
| 69680 | DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN); |
| 69681 | DUK_ASSERT(flags <= DUK_BC_A_MAX); |
| 69682 | instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch); |
| 69683 | } |
| 69684 | |
| 69685 | DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) { |
| 69686 | duk_small_uint_t op; |
| 69687 | |
| 69688 | op = DUK__ISREG(regconst) ? DUK_OP_IFFALSE_R : DUK_OP_IFFALSE_C; |
| 69689 | duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */ |
| 69690 | } |
| 69691 | |
| 69692 | DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) { |
| 69693 | duk_small_uint_t op; |
| 69694 | |
| 69695 | op = DUK__ISREG(regconst) ? DUK_OP_IFTRUE_R : DUK_OP_IFTRUE_C; |
| 69696 | duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */ |
| 69697 | } |
| 69698 | |
| 69699 | DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) { |
| 69700 | duk__emit_op_only(comp_ctx, DUK_OP_INVALID); |
| 69701 | } |
| 69702 | |
| 69703 | /* |
| 69704 | * Peephole optimizer for finished bytecode. |
| 69705 | * |
| 69706 | * Does not remove opcodes; currently only straightens out unconditional |
| 69707 | * jump chains which are generated by several control structures. |
| 69708 | */ |
| 69709 | |
| 69710 | DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) { |
| 69711 | duk_compiler_instr *bc; |
| 69712 | duk_small_uint_t iter; |
| 69713 | duk_int_t i, n; |
| 69714 | duk_int_t count_opt; |
| 69715 | |
| 69716 | bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code); |
| 69717 | #if defined(DUK_USE_BUFLEN16) |
| 69718 | /* No need to assert, buffer size maximum is 0xffff. */ |
| 69719 | #else |
| 69720 | DUK_ASSERT((duk_size_t) DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr) <= (duk_size_t) DUK_INT_MAX); /* bytecode limits */ |
| 69721 | #endif |
| 69722 | n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr)); |
| 69723 | |
| 69724 | for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) { |
| 69725 | count_opt = 0; |
| 69726 | |
| 69727 | for (i = 0; i < n; i++) { |
| 69728 | duk_instr_t ins; |
| 69729 | duk_int_t target_pc1; |
| 69730 | duk_int_t target_pc2; |
| 69731 | |
| 69732 | ins = bc[i].ins; |
| 69733 | if (DUK_DEC_OP(ins) != DUK_OP_JUMP) { |
| 69734 | continue; |
| 69735 | } |
| 69736 | |
| 69737 | target_pc1 = i + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS; |
| 69738 | DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld" , (long) i, (long) target_pc1)); |
| 69739 | DUK_ASSERT(target_pc1 >= 0); |
| 69740 | DUK_ASSERT(target_pc1 < n); |
| 69741 | |
| 69742 | /* Note: if target_pc1 == i, we'll optimize a jump to itself. |
| 69743 | * This does not need to be checked for explicitly; the case |
| 69744 | * is rare and max iter breaks us out. |
| 69745 | */ |
| 69746 | |
| 69747 | ins = bc[target_pc1].ins; |
| 69748 | if (DUK_DEC_OP(ins) != DUK_OP_JUMP) { |
| 69749 | continue; |
| 69750 | } |
| 69751 | |
| 69752 | target_pc2 = target_pc1 + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS; |
| 69753 | |
| 69754 | DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld" , |
| 69755 | (long) i, (long) target_pc1, (long) target_pc2)); |
| 69756 | |
| 69757 | bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS); |
| 69758 | |
| 69759 | count_opt++; |
| 69760 | } |
| 69761 | |
| 69762 | DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld" , (long) count_opt, (long) (iter + 1))); |
| 69763 | |
| 69764 | if (count_opt == 0) { |
| 69765 | break; |
| 69766 | } |
| 69767 | } |
| 69768 | } |
| 69769 | |
| 69770 | /* |
| 69771 | * Intermediate value helpers |
| 69772 | */ |
| 69773 | |
| 69774 | /* Flags for intermediate value coercions. A flag for using a forced reg |
| 69775 | * is not needed, the forced_reg argument suffices and generates better |
| 69776 | * code (it is checked as it is used). |
| 69777 | */ |
| 69778 | /* XXX: DUK__IVAL_FLAG_REQUIRE_SHORT is passed but not currently implemented |
| 69779 | * by ispec/ivalue operations. |
| 69780 | */ |
| 69781 | #define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */ |
| 69782 | #define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */ |
| 69783 | #define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */ |
| 69784 | |
| 69785 | /* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(thr,x) */ |
| 69786 | |
| 69787 | #if 0 /* enable manually for dumping */ |
| 69788 | #define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0) |
| 69789 | #define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0) |
| 69790 | |
| 69791 | DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) { |
| 69792 | DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T" , |
| 69793 | (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx, |
| 69794 | duk_get_tval(comp_ctx->thr, x->valstack_idx))); |
| 69795 | } |
| 69796 | DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 69797 | DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld " |
| 69798 | "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} " |
| 69799 | "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}" , |
| 69800 | (long) x->t, (long) x->op, |
| 69801 | (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx, |
| 69802 | duk_get_tval(comp_ctx->thr, x->x1.valstack_idx), |
| 69803 | (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx, |
| 69804 | duk_get_tval(comp_ctx->thr, x->x2.valstack_idx))); |
| 69805 | } |
| 69806 | #else |
| 69807 | #define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0) |
| 69808 | #define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0) |
| 69809 | #endif |
| 69810 | |
| 69811 | DUK_LOCAL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst) { |
| 69812 | x->t = DUK_IVAL_PLAIN; |
| 69813 | x->x1.t = DUK_ISPEC_REGCONST; |
| 69814 | x->x1.regconst = regconst; |
| 69815 | } |
| 69816 | |
| 69817 | DUK_LOCAL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 69818 | x->t = DUK_IVAL_PLAIN; |
| 69819 | x->x1.t = DUK_ISPEC_VALUE; |
| 69820 | duk_replace(comp_ctx->thr, x->x1.valstack_idx); |
| 69821 | } |
| 69822 | |
| 69823 | DUK_LOCAL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 69824 | x->t = DUK_IVAL_VAR; |
| 69825 | x->x1.t = DUK_ISPEC_VALUE; |
| 69826 | duk_replace(comp_ctx->thr, x->x1.valstack_idx); |
| 69827 | } |
| 69828 | |
| 69829 | DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h) { |
| 69830 | DUK_ASSERT(h != NULL); |
| 69831 | duk_push_hstring(comp_ctx->thr, h); |
| 69832 | duk__ivalue_var_fromstack(comp_ctx, x); |
| 69833 | } |
| 69834 | |
| 69835 | DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) { |
| 69836 | dst->t = src->t; |
| 69837 | dst->regconst = src->regconst; |
| 69838 | duk_copy(comp_ctx->thr, src->valstack_idx, dst->valstack_idx); |
| 69839 | } |
| 69840 | |
| 69841 | DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) { |
| 69842 | dst->t = src->t; |
| 69843 | dst->op = src->op; |
| 69844 | dst->x1.t = src->x1.t; |
| 69845 | dst->x1.regconst = src->x1.regconst; |
| 69846 | dst->x2.t = src->x2.t; |
| 69847 | dst->x2.regconst = src->x2.regconst; |
| 69848 | duk_copy(comp_ctx->thr, src->x1.valstack_idx, dst->x1.valstack_idx); |
| 69849 | duk_copy(comp_ctx->thr, src->x2.valstack_idx, dst->x2.valstack_idx); |
| 69850 | } |
| 69851 | |
| 69852 | DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) { |
| 69853 | duk_regconst_t res; |
| 69854 | |
| 69855 | res = comp_ctx->curr_func.temp_next; |
| 69856 | comp_ctx->curr_func.temp_next += num; |
| 69857 | |
| 69858 | if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */ |
| 69859 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT); |
| 69860 | DUK_WO_NORETURN(return 0;); |
| 69861 | } |
| 69862 | |
| 69863 | /* maintain highest 'used' temporary, needed to figure out nregs of function */ |
| 69864 | if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) { |
| 69865 | comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next; |
| 69866 | } |
| 69867 | |
| 69868 | return res; |
| 69869 | } |
| 69870 | |
| 69871 | DUK_LOCAL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx) { |
| 69872 | return duk__alloctemps(comp_ctx, 1); |
| 69873 | } |
| 69874 | |
| 69875 | DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next) { |
| 69876 | comp_ctx->curr_func.temp_next = temp_next; |
| 69877 | if (temp_next > comp_ctx->curr_func.temp_max) { |
| 69878 | comp_ctx->curr_func.temp_max = temp_next; |
| 69879 | } |
| 69880 | } |
| 69881 | |
| 69882 | /* get const for value at valstack top */ |
| 69883 | DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) { |
| 69884 | duk_hthread *thr = comp_ctx->thr; |
| 69885 | duk_compiler_func *f = &comp_ctx->curr_func; |
| 69886 | duk_tval *tv1; |
| 69887 | duk_int_t i, n, n_check; |
| 69888 | |
| 69889 | n = (duk_int_t) duk_get_length(thr, f->consts_idx); |
| 69890 | |
| 69891 | tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 69892 | DUK_ASSERT(tv1 != NULL); |
| 69893 | |
| 69894 | #if defined(DUK_USE_FASTINT) |
| 69895 | /* Explicit check for fastint downgrade. */ |
| 69896 | DUK_TVAL_CHKFAST_INPLACE_SLOW(tv1); |
| 69897 | #endif |
| 69898 | |
| 69899 | /* Sanity workaround for handling functions with a large number of |
| 69900 | * constants at least somewhat reasonably. Otherwise checking whether |
| 69901 | * we already have the constant would grow very slow (as it is O(N^2)). |
| 69902 | */ |
| 69903 | n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n); |
| 69904 | for (i = 0; i < n_check; i++) { |
| 69905 | duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i); |
| 69906 | |
| 69907 | /* Strict equality is NOT enough, because we cannot use the same |
| 69908 | * constant for e.g. +0 and -0. |
| 69909 | */ |
| 69910 | if (duk_js_samevalue(tv1, tv2)) { |
| 69911 | DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld" , |
| 69912 | (duk_tval *) tv1, (long) i)); |
| 69913 | duk_pop(thr); |
| 69914 | return (duk_regconst_t) i | (duk_regconst_t) DUK__CONST_MARKER; |
| 69915 | } |
| 69916 | } |
| 69917 | |
| 69918 | if (n > DUK__MAX_CONSTS) { |
| 69919 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT); |
| 69920 | DUK_WO_NORETURN(return 0;); |
| 69921 | } |
| 69922 | |
| 69923 | DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld" , |
| 69924 | (duk_tval *) tv1, (long) n)); |
| 69925 | (void) duk_put_prop_index(thr, f->consts_idx, (duk_uarridx_t) n); /* invalidates tv1, tv2 */ |
| 69926 | return (duk_regconst_t) n | (duk_regconst_t) DUK__CONST_MARKER; |
| 69927 | } |
| 69928 | |
| 69929 | DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_regconst_t rc) { |
| 69930 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 69931 | duk_compiler_func *f = &comp_ctx->curr_func; |
| 69932 | duk_bool_t ret; |
| 69933 | |
| 69934 | DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ |
| 69935 | (void) duk_get_prop_index(comp_ctx->thr, f->consts_idx, (duk_uarridx_t) rc); |
| 69936 | ret = !duk_is_number(comp_ctx->thr, -1); /* now only number/string, so conservative check */ |
| 69937 | duk_pop(comp_ctx->thr); |
| 69938 | return ret; |
| 69939 | #else |
| 69940 | DUK_UNREF(comp_ctx); |
| 69941 | DUK_UNREF(rc); |
| 69942 | DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */ |
| 69943 | return 0; |
| 69944 | #endif |
| 69945 | } |
| 69946 | |
| 69947 | /* Get the value represented by an duk_ispec to a register or constant. |
| 69948 | * The caller can control the result by indicating whether or not: |
| 69949 | * |
| 69950 | * (1) a constant is allowed (sometimes the caller needs the result to |
| 69951 | * be in a register) |
| 69952 | * |
| 69953 | * (2) a temporary register is required (usually when caller requires |
| 69954 | * the register to be safely mutable; normally either a bound |
| 69955 | * register or a temporary register are both OK) |
| 69956 | * |
| 69957 | * (3) a forced register target needs to be used |
| 69958 | * |
| 69959 | * Bytecode may be emitted to generate the necessary value. The return |
| 69960 | * value is either a register or a constant. |
| 69961 | */ |
| 69962 | |
| 69963 | DUK_LOCAL |
| 69964 | duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx, |
| 69965 | duk_ispec *x, |
| 69966 | duk_regconst_t forced_reg, |
| 69967 | duk_small_uint_t flags) { |
| 69968 | duk_hthread *thr = comp_ctx->thr; |
| 69969 | |
| 69970 | DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, " |
| 69971 | "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld" , |
| 69972 | (long) x->t, |
| 69973 | (long) x->regconst, |
| 69974 | (duk_tval *) duk_get_tval(thr, x->valstack_idx), |
| 69975 | (long) forced_reg, |
| 69976 | (unsigned long) flags, |
| 69977 | (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0), |
| 69978 | (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0), |
| 69979 | (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0))); |
| 69980 | |
| 69981 | switch (x->t) { |
| 69982 | case DUK_ISPEC_VALUE: { |
| 69983 | duk_tval *tv; |
| 69984 | |
| 69985 | tv = DUK_GET_TVAL_POSIDX(thr, x->valstack_idx); |
| 69986 | DUK_ASSERT(tv != NULL); |
| 69987 | |
| 69988 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 69989 | case DUK_TAG_UNDEFINED: { |
| 69990 | /* Note: although there is no 'undefined' literal, undefined |
| 69991 | * values can occur during compilation as a result of e.g. |
| 69992 | * the 'void' operator. |
| 69993 | */ |
| 69994 | duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); |
| 69995 | duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, dest); |
| 69996 | return dest; |
| 69997 | } |
| 69998 | case DUK_TAG_NULL: { |
| 69999 | duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); |
| 70000 | duk__emit_bc(comp_ctx, DUK_OP_LDNULL, dest); |
| 70001 | return dest; |
| 70002 | } |
| 70003 | case DUK_TAG_BOOLEAN: { |
| 70004 | duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); |
| 70005 | duk__emit_bc(comp_ctx, |
| 70006 | (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_OP_LDTRUE : DUK_OP_LDFALSE), |
| 70007 | dest); |
| 70008 | return dest; |
| 70009 | } |
| 70010 | case DUK_TAG_POINTER: { |
| 70011 | DUK_UNREACHABLE(); |
| 70012 | break; |
| 70013 | } |
| 70014 | case DUK_TAG_STRING: { |
| 70015 | duk_hstring *h; |
| 70016 | duk_regconst_t dest; |
| 70017 | duk_regconst_t constidx; |
| 70018 | |
| 70019 | h = DUK_TVAL_GET_STRING(tv); |
| 70020 | DUK_UNREF(h); |
| 70021 | DUK_ASSERT(h != NULL); |
| 70022 | |
| 70023 | #if 0 /* XXX: to be implemented? */ |
| 70024 | /* Use special opcodes to load short strings */ |
| 70025 | if (DUK_HSTRING_GET_BYTELEN(h) <= 2) { |
| 70026 | /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */ |
| 70027 | } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) { |
| 70028 | /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */ |
| 70029 | } |
| 70030 | #endif |
| 70031 | duk_dup(thr, x->valstack_idx); |
| 70032 | constidx = duk__getconst(comp_ctx); |
| 70033 | |
| 70034 | if (flags & DUK__IVAL_FLAG_ALLOW_CONST) { |
| 70035 | return constidx; |
| 70036 | } |
| 70037 | |
| 70038 | dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); |
| 70039 | duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx); |
| 70040 | return dest; |
| 70041 | } |
| 70042 | case DUK_TAG_OBJECT: { |
| 70043 | DUK_UNREACHABLE(); |
| 70044 | break; |
| 70045 | } |
| 70046 | case DUK_TAG_BUFFER: { |
| 70047 | DUK_UNREACHABLE(); |
| 70048 | break; |
| 70049 | } |
| 70050 | case DUK_TAG_LIGHTFUNC: { |
| 70051 | DUK_UNREACHABLE(); |
| 70052 | break; |
| 70053 | } |
| 70054 | #if defined(DUK_USE_FASTINT) |
| 70055 | case DUK_TAG_FASTINT: |
| 70056 | #endif |
| 70057 | default: { |
| 70058 | /* number */ |
| 70059 | duk_regconst_t dest; |
| 70060 | duk_regconst_t constidx; |
| 70061 | duk_double_t dval; |
| 70062 | duk_int32_t ival; |
| 70063 | |
| 70064 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 70065 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 70066 | dval = DUK_TVAL_GET_NUMBER(tv); |
| 70067 | |
| 70068 | if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) { |
| 70069 | /* A number can be loaded either through a constant, using |
| 70070 | * LDINT, or using LDINT+LDINTX. LDINT is always a size win, |
| 70071 | * LDINT+LDINTX is not if the constant is used multiple times. |
| 70072 | * Currently always prefer LDINT+LDINTX over a double constant. |
| 70073 | */ |
| 70074 | |
| 70075 | if (duk_is_whole_get_int32_nonegzero(dval, &ival)) { |
| 70076 | dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); |
| 70077 | duk__emit_load_int32(comp_ctx, dest, ival); |
| 70078 | return dest; |
| 70079 | } |
| 70080 | } |
| 70081 | |
| 70082 | duk_dup(thr, x->valstack_idx); |
| 70083 | constidx = duk__getconst(comp_ctx); |
| 70084 | |
| 70085 | if (flags & DUK__IVAL_FLAG_ALLOW_CONST) { |
| 70086 | return constidx; |
| 70087 | } else { |
| 70088 | dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); |
| 70089 | duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx); |
| 70090 | return dest; |
| 70091 | } |
| 70092 | } |
| 70093 | } /* end switch */ |
| 70094 | goto fail_internal; /* never here */ |
| 70095 | } |
| 70096 | case DUK_ISPEC_REGCONST: { |
| 70097 | if (forced_reg >= 0) { |
| 70098 | if (DUK__ISCONST(x->regconst)) { |
| 70099 | duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst); |
| 70100 | } else if (x->regconst != forced_reg) { |
| 70101 | duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst); |
| 70102 | } else { |
| 70103 | ; /* already in correct reg */ |
| 70104 | } |
| 70105 | return forced_reg; |
| 70106 | } |
| 70107 | |
| 70108 | DUK_ASSERT(forced_reg < 0); |
| 70109 | if (DUK__ISCONST(x->regconst)) { |
| 70110 | if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) { |
| 70111 | duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx); |
| 70112 | duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst); |
| 70113 | return dest; |
| 70114 | } |
| 70115 | return x->regconst; |
| 70116 | } |
| 70117 | |
| 70118 | DUK_ASSERT(forced_reg < 0 && !DUK__ISCONST(x->regconst)); |
| 70119 | if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISREG_TEMP(comp_ctx, x->regconst)) { |
| 70120 | duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx); |
| 70121 | duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst); |
| 70122 | return dest; |
| 70123 | } |
| 70124 | return x->regconst; |
| 70125 | } |
| 70126 | default: { |
| 70127 | break; /* never here */ |
| 70128 | } |
| 70129 | } |
| 70130 | |
| 70131 | fail_internal: |
| 70132 | DUK_ERROR_INTERNAL(thr); |
| 70133 | DUK_WO_NORETURN(return 0;); |
| 70134 | } |
| 70135 | |
| 70136 | DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) { |
| 70137 | DUK_ASSERT(forced_reg >= 0); |
| 70138 | (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/); |
| 70139 | } |
| 70140 | |
| 70141 | /* Coerce an duk_ivalue to a 'plain' value by generating the necessary |
| 70142 | * arithmetic operations, property access, or variable access bytecode. |
| 70143 | * The duk_ivalue argument ('x') is converted into a plain value as a |
| 70144 | * side effect. |
| 70145 | */ |
| 70146 | DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg) { |
| 70147 | duk_hthread *thr = comp_ctx->thr; |
| 70148 | |
| 70149 | DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, " |
| 70150 | "forced_reg=%ld" , |
| 70151 | (long) x->t, (long) x->op, |
| 70152 | (long) x->x1.t, (long) x->x1.regconst, |
| 70153 | (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx), |
| 70154 | (long) x->x2.t, (long) x->x2.regconst, |
| 70155 | (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx), |
| 70156 | (long) forced_reg)); |
| 70157 | |
| 70158 | switch (x->t) { |
| 70159 | case DUK_IVAL_PLAIN: { |
| 70160 | return; |
| 70161 | } |
| 70162 | /* XXX: support unary arithmetic ivalues (useful?) */ |
| 70163 | case DUK_IVAL_ARITH: { |
| 70164 | duk_regconst_t arg1; |
| 70165 | duk_regconst_t arg2; |
| 70166 | duk_regconst_t dest; |
| 70167 | duk_tval *tv1; |
| 70168 | duk_tval *tv2; |
| 70169 | |
| 70170 | DUK_DDD(DUK_DDDPRINT("arith to plain conversion" )); |
| 70171 | |
| 70172 | /* inline arithmetic check for constant values */ |
| 70173 | /* XXX: use the exactly same arithmetic function here as in executor */ |
| 70174 | if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) { |
| 70175 | tv1 = DUK_GET_TVAL_POSIDX(thr, x->x1.valstack_idx); |
| 70176 | tv2 = DUK_GET_TVAL_POSIDX(thr, x->x2.valstack_idx); |
| 70177 | DUK_ASSERT(tv1 != NULL); |
| 70178 | DUK_ASSERT(tv2 != NULL); |
| 70179 | |
| 70180 | DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T" , |
| 70181 | (duk_tval *) tv1, |
| 70182 | (duk_tval *) tv2)); |
| 70183 | |
| 70184 | if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) { |
| 70185 | duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1); |
| 70186 | duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2); |
| 70187 | duk_double_t d3; |
| 70188 | duk_bool_t accept_fold = 1; |
| 70189 | |
| 70190 | DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld" , |
| 70191 | (double) d1, (double) d2, (long) x->op)); |
| 70192 | switch (x->op) { |
| 70193 | case DUK_OP_ADD: { |
| 70194 | d3 = d1 + d2; |
| 70195 | break; |
| 70196 | } |
| 70197 | case DUK_OP_SUB: { |
| 70198 | d3 = d1 - d2; |
| 70199 | break; |
| 70200 | } |
| 70201 | case DUK_OP_MUL: { |
| 70202 | d3 = d1 * d2; |
| 70203 | break; |
| 70204 | } |
| 70205 | case DUK_OP_DIV: { |
| 70206 | /* Division-by-zero is undefined |
| 70207 | * behavior, so rely on a helper. |
| 70208 | */ |
| 70209 | d3 = duk_double_div(d1, d2); |
| 70210 | break; |
| 70211 | } |
| 70212 | case DUK_OP_EXP: { |
| 70213 | d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); |
| 70214 | break; |
| 70215 | } |
| 70216 | default: { |
| 70217 | d3 = 0.0; /* Won't be used, but silence MSVC /W4 warning. */ |
| 70218 | accept_fold = 0; |
| 70219 | break; |
| 70220 | } |
| 70221 | } |
| 70222 | |
| 70223 | if (accept_fold) { |
| 70224 | duk_double_union du; |
| 70225 | du.d = d3; |
| 70226 | DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); |
| 70227 | d3 = du.d; |
| 70228 | |
| 70229 | x->t = DUK_IVAL_PLAIN; |
| 70230 | DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE); |
| 70231 | DUK_TVAL_SET_NUMBER(tv1, d3); /* old value is number: no refcount */ |
| 70232 | return; |
| 70233 | } |
| 70234 | } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) { |
| 70235 | /* Inline string concatenation. No need to check for |
| 70236 | * symbols, as all inputs are valid ECMAScript strings. |
| 70237 | */ |
| 70238 | duk_dup(thr, x->x1.valstack_idx); |
| 70239 | duk_dup(thr, x->x2.valstack_idx); |
| 70240 | duk_concat(thr, 2); |
| 70241 | duk_replace(thr, x->x1.valstack_idx); |
| 70242 | x->t = DUK_IVAL_PLAIN; |
| 70243 | DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE); |
| 70244 | return; |
| 70245 | } |
| 70246 | } |
| 70247 | |
| 70248 | arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); |
| 70249 | arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); |
| 70250 | |
| 70251 | /* If forced reg, use it as destination. Otherwise try to |
| 70252 | * use either coerced ispec if it is a temporary. |
| 70253 | */ |
| 70254 | if (forced_reg >= 0) { |
| 70255 | dest = forced_reg; |
| 70256 | } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) { |
| 70257 | dest = arg1; |
| 70258 | } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) { |
| 70259 | dest = arg2; |
| 70260 | } else { |
| 70261 | dest = DUK__ALLOCTEMP(comp_ctx); |
| 70262 | } |
| 70263 | |
| 70264 | DUK_ASSERT(DUK__ISREG(dest)); |
| 70265 | duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, dest, arg1, arg2); |
| 70266 | |
| 70267 | duk__ivalue_regconst(x, dest); |
| 70268 | return; |
| 70269 | } |
| 70270 | case DUK_IVAL_PROP: { |
| 70271 | /* XXX: very similar to DUK_IVAL_ARITH - merge? */ |
| 70272 | duk_regconst_t arg1; |
| 70273 | duk_regconst_t arg2; |
| 70274 | duk_regconst_t dest; |
| 70275 | |
| 70276 | /* Need a short reg/const, does not have to be a mutable temp. */ |
| 70277 | arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); |
| 70278 | arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/); |
| 70279 | |
| 70280 | /* Pick a destination register. If either base value or key |
| 70281 | * happens to be a temp value, reuse it as the destination. |
| 70282 | * |
| 70283 | * XXX: The temp must be a "mutable" one, i.e. such that no |
| 70284 | * other expression is using it anymore. Here this should be |
| 70285 | * the case because the value of a property access expression |
| 70286 | * is neither the base nor the key, but the lookup result. |
| 70287 | */ |
| 70288 | |
| 70289 | if (forced_reg >= 0) { |
| 70290 | dest = forced_reg; |
| 70291 | } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) { |
| 70292 | dest = arg1; |
| 70293 | } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) { |
| 70294 | dest = arg2; |
| 70295 | } else { |
| 70296 | dest = DUK__ALLOCTEMP(comp_ctx); |
| 70297 | } |
| 70298 | |
| 70299 | duk__emit_a_b_c(comp_ctx, |
| 70300 | DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST, |
| 70301 | dest, |
| 70302 | arg1, |
| 70303 | arg2); |
| 70304 | |
| 70305 | duk__ivalue_regconst(x, dest); |
| 70306 | return; |
| 70307 | } |
| 70308 | case DUK_IVAL_VAR: { |
| 70309 | /* x1 must be a string */ |
| 70310 | duk_regconst_t dest; |
| 70311 | duk_regconst_t reg_varbind; |
| 70312 | duk_regconst_t rc_varname; |
| 70313 | |
| 70314 | DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE); |
| 70315 | |
| 70316 | duk_dup(thr, x->x1.valstack_idx); |
| 70317 | if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { |
| 70318 | duk__ivalue_regconst(x, reg_varbind); |
| 70319 | } else { |
| 70320 | dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx)); |
| 70321 | duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, dest, rc_varname); |
| 70322 | duk__ivalue_regconst(x, dest); |
| 70323 | } |
| 70324 | return; |
| 70325 | } |
| 70326 | case DUK_IVAL_NONE: |
| 70327 | default: { |
| 70328 | DUK_D(DUK_DPRINT("invalid ivalue type: %ld" , (long) x->t)); |
| 70329 | break; |
| 70330 | } |
| 70331 | } |
| 70332 | |
| 70333 | DUK_ERROR_INTERNAL(thr); |
| 70334 | DUK_WO_NORETURN(return;); |
| 70335 | } |
| 70336 | |
| 70337 | /* evaluate to plain value, no forced register (temp/bound reg both ok) */ |
| 70338 | DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 70339 | duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/); |
| 70340 | } |
| 70341 | |
| 70342 | /* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */ |
| 70343 | DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 70344 | duk_regconst_t temp; |
| 70345 | |
| 70346 | /* If duk__ivalue_toplain_raw() allocates a temp, forget it and |
| 70347 | * restore next temp state. |
| 70348 | */ |
| 70349 | temp = DUK__GETTEMP(comp_ctx); |
| 70350 | duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/); |
| 70351 | DUK__SETTEMP(comp_ctx, temp); |
| 70352 | } |
| 70353 | |
| 70354 | /* Coerce an duk_ivalue to a register or constant; result register may |
| 70355 | * be a temp or a bound register. |
| 70356 | * |
| 70357 | * The duk_ivalue argument ('x') is converted into a regconst as a |
| 70358 | * side effect. |
| 70359 | */ |
| 70360 | DUK_LOCAL |
| 70361 | duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx, |
| 70362 | duk_ivalue *x, |
| 70363 | duk_regconst_t forced_reg, |
| 70364 | duk_small_uint_t flags) { |
| 70365 | duk_hthread *thr = comp_ctx->thr; |
| 70366 | duk_regconst_t reg; |
| 70367 | DUK_UNREF(thr); |
| 70368 | |
| 70369 | DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, " |
| 70370 | "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld" , |
| 70371 | (long) x->t, (long) x->op, |
| 70372 | (long) x->x1.t, (long) x->x1.regconst, |
| 70373 | (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx), |
| 70374 | (long) x->x2.t, (long) x->x2.regconst, |
| 70375 | (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx), |
| 70376 | (long) forced_reg, |
| 70377 | (unsigned long) flags, |
| 70378 | (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0), |
| 70379 | (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0), |
| 70380 | (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0))); |
| 70381 | |
| 70382 | /* first coerce to a plain value */ |
| 70383 | duk__ivalue_toplain_raw(comp_ctx, x, forced_reg); |
| 70384 | DUK_ASSERT(x->t == DUK_IVAL_PLAIN); |
| 70385 | |
| 70386 | /* then to a register */ |
| 70387 | reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags); |
| 70388 | duk__ivalue_regconst(x, reg); |
| 70389 | |
| 70390 | return reg; |
| 70391 | } |
| 70392 | |
| 70393 | DUK_LOCAL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 70394 | return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/); |
| 70395 | } |
| 70396 | |
| 70397 | #if 0 /* unused */ |
| 70398 | DUK_LOCAL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 70399 | return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/); |
| 70400 | } |
| 70401 | #endif |
| 70402 | |
| 70403 | DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) { |
| 70404 | DUK_ASSERT(forced_reg >= 0); |
| 70405 | (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/); |
| 70406 | } |
| 70407 | |
| 70408 | DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 70409 | return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); |
| 70410 | } |
| 70411 | |
| 70412 | DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) { |
| 70413 | return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/); |
| 70414 | } |
| 70415 | |
| 70416 | /* The issues below can be solved with better flags */ |
| 70417 | |
| 70418 | /* XXX: many operations actually want toforcedtemp() -- brand new temp? */ |
| 70419 | /* XXX: need a toplain_ignore() which will only coerce a value to a temp |
| 70420 | * register if it might have a side effect. Side-effect free values do not |
| 70421 | * need to be coerced. |
| 70422 | */ |
| 70423 | |
| 70424 | /* |
| 70425 | * Identifier handling |
| 70426 | */ |
| 70427 | |
| 70428 | DUK_LOCAL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) { |
| 70429 | duk_hthread *thr = comp_ctx->thr; |
| 70430 | duk_hstring *h_varname; |
| 70431 | duk_regconst_t ret; |
| 70432 | |
| 70433 | DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'" , |
| 70434 | (duk_tval *) duk_get_tval(thr, -1))); |
| 70435 | |
| 70436 | /* |
| 70437 | * Special name handling |
| 70438 | */ |
| 70439 | |
| 70440 | h_varname = duk_known_hstring(thr, -1); |
| 70441 | |
| 70442 | if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) { |
| 70443 | DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'" )); |
| 70444 | comp_ctx->curr_func.id_access_arguments = 1; |
| 70445 | } |
| 70446 | |
| 70447 | /* |
| 70448 | * Inside one or more 'with' statements fall back to slow path always. |
| 70449 | * (See e.g. test-stmt-with.js.) |
| 70450 | */ |
| 70451 | |
| 70452 | if (comp_ctx->curr_func.with_depth > 0) { |
| 70453 | DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path" )); |
| 70454 | goto slow_path_own; |
| 70455 | } |
| 70456 | |
| 70457 | /* |
| 70458 | * Any catch bindings ("catch (e)") also affect identifier binding. |
| 70459 | * |
| 70460 | * Currently, the varmap is modified for the duration of the catch |
| 70461 | * clause to ensure any identifier accesses with the catch variable |
| 70462 | * name will use slow path. |
| 70463 | */ |
| 70464 | |
| 70465 | duk_get_prop(thr, comp_ctx->curr_func.varmap_idx); |
| 70466 | if (duk_is_number(thr, -1)) { |
| 70467 | ret = duk_to_int(thr, -1); |
| 70468 | duk_pop(thr); |
| 70469 | } else { |
| 70470 | duk_pop(thr); |
| 70471 | if (comp_ctx->curr_func.catch_depth > 0 || comp_ctx->curr_func.with_depth > 0) { |
| 70472 | DUK_DDD(DUK_DDDPRINT("slow path access from inside a try-catch or with needs _Varmap" )); |
| 70473 | goto slow_path_own; |
| 70474 | } else { |
| 70475 | /* In this case we're doing a variable lookup that doesn't |
| 70476 | * match our own variables, so _Varmap won't be needed at |
| 70477 | * run time. |
| 70478 | */ |
| 70479 | DUK_DDD(DUK_DDDPRINT("slow path access outside of try-catch and with, no need for _Varmap" )); |
| 70480 | goto slow_path_notown; |
| 70481 | } |
| 70482 | } |
| 70483 | |
| 70484 | DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld" , (long) ret)); |
| 70485 | return ret; |
| 70486 | |
| 70487 | slow_path_notown: |
| 70488 | DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, not own variable" )); |
| 70489 | |
| 70490 | comp_ctx->curr_func.id_access_slow = 1; |
| 70491 | return (duk_regconst_t) -1; |
| 70492 | |
| 70493 | slow_path_own: |
| 70494 | DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, may be own variable" )); |
| 70495 | |
| 70496 | comp_ctx->curr_func.id_access_slow = 1; |
| 70497 | comp_ctx->curr_func.id_access_slow_own = 1; |
| 70498 | return (duk_regconst_t) -1; |
| 70499 | } |
| 70500 | |
| 70501 | /* Lookup an identifier name in the current varmap, indicating whether the |
| 70502 | * identifier is register-bound and if not, allocating a constant for the |
| 70503 | * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can |
| 70504 | * also check (out_reg_varbind >= 0) to check whether or not identifier is |
| 70505 | * register bound. The caller must NOT use out_rc_varname at all unless |
| 70506 | * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname |
| 70507 | * is unsigned and doesn't have a "unused" / none value. |
| 70508 | */ |
| 70509 | DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) { |
| 70510 | duk_hthread *thr = comp_ctx->thr; |
| 70511 | duk_regconst_t reg_varbind; |
| 70512 | duk_regconst_t rc_varname; |
| 70513 | |
| 70514 | /* [ ... varname ] */ |
| 70515 | |
| 70516 | duk_dup_top(thr); |
| 70517 | reg_varbind = duk__lookup_active_register_binding(comp_ctx); |
| 70518 | |
| 70519 | if (reg_varbind >= 0) { |
| 70520 | *out_reg_varbind = reg_varbind; |
| 70521 | *out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */ |
| 70522 | duk_pop(thr); |
| 70523 | return 1; |
| 70524 | } else { |
| 70525 | rc_varname = duk__getconst(comp_ctx); |
| 70526 | *out_reg_varbind = -1; |
| 70527 | *out_rc_varname = rc_varname; |
| 70528 | return 0; |
| 70529 | } |
| 70530 | } |
| 70531 | |
| 70532 | /* |
| 70533 | * Label handling |
| 70534 | * |
| 70535 | * Labels are initially added with flags prohibiting both break and continue. |
| 70536 | * When the statement type is finally uncovered (after potentially multiple |
| 70537 | * labels), all the labels are updated to allow/prohibit break and continue. |
| 70538 | */ |
| 70539 | |
| 70540 | DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) { |
| 70541 | duk_hthread *thr = comp_ctx->thr; |
| 70542 | duk_size_t n; |
| 70543 | duk_size_t new_size; |
| 70544 | duk_uint8_t *p; |
| 70545 | duk_labelinfo *li_start, *li; |
| 70546 | |
| 70547 | /* Duplicate (shadowing) labels are not allowed, except for the empty |
| 70548 | * labels (which are used as default labels for switch and iteration |
| 70549 | * statements). |
| 70550 | * |
| 70551 | * We could also allow shadowing of non-empty pending labels without any |
| 70552 | * other issues than breaking the required label shadowing requirements |
| 70553 | * of the E5 specification, see Section 12.12. |
| 70554 | */ |
| 70555 | |
| 70556 | p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos); |
| 70557 | li_start = (duk_labelinfo *) (void *) p; |
| 70558 | li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); |
| 70559 | n = (duk_size_t) (li - li_start); |
| 70560 | |
| 70561 | while (li > li_start) { |
| 70562 | li--; |
| 70563 | |
| 70564 | if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) { |
| 70565 | DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL); |
| 70566 | DUK_WO_NORETURN(return;); |
| 70567 | } |
| 70568 | } |
| 70569 | |
| 70570 | duk_push_hstring(thr, h_label); |
| 70571 | DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */ |
| 70572 | (void) duk_put_prop_index(thr, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n); |
| 70573 | |
| 70574 | new_size = (n + 1) * sizeof(duk_labelinfo); |
| 70575 | duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size); |
| 70576 | /* XXX: slack handling, slow now */ |
| 70577 | |
| 70578 | /* relookup after possible realloc */ |
| 70579 | p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos); |
| 70580 | li_start = (duk_labelinfo *) (void *) p; |
| 70581 | DUK_UNREF(li_start); /* silence scan-build warning */ |
| 70582 | li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); |
| 70583 | li--; |
| 70584 | |
| 70585 | /* Labels can be used for iteration statements but also for other statements, |
| 70586 | * in particular a label can be used for a block statement. All cases of a |
| 70587 | * named label accept a 'break' so that flag is set here. Iteration statements |
| 70588 | * also allow 'continue', so that flag is updated when we figure out the |
| 70589 | * statement type. |
| 70590 | */ |
| 70591 | |
| 70592 | li->flags = DUK_LABEL_FLAG_ALLOW_BREAK; |
| 70593 | li->label_id = label_id; |
| 70594 | li->h_label = h_label; |
| 70595 | li->catch_depth = comp_ctx->curr_func.catch_depth; /* catch depth from current func */ |
| 70596 | li->pc_label = pc_label; |
| 70597 | |
| 70598 | DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld" , |
| 70599 | (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label, |
| 70600 | (long) li->catch_depth, (long) li->pc_label)); |
| 70601 | } |
| 70602 | |
| 70603 | /* Update all labels with matching label_id. */ |
| 70604 | DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) { |
| 70605 | duk_uint8_t *p; |
| 70606 | duk_labelinfo *li_start, *li; |
| 70607 | |
| 70608 | p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos); |
| 70609 | li_start = (duk_labelinfo *) (void *) p; |
| 70610 | li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); |
| 70611 | |
| 70612 | /* Match labels starting from latest; once label_id no longer matches, we can |
| 70613 | * safely exit without checking the rest of the labels (only the topmost labels |
| 70614 | * are ever updated). |
| 70615 | */ |
| 70616 | while (li > li_start) { |
| 70617 | li--; |
| 70618 | |
| 70619 | if (li->label_id != label_id) { |
| 70620 | break; |
| 70621 | } |
| 70622 | |
| 70623 | DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld" , |
| 70624 | (void *) li, (long) label_id, (long) flags)); |
| 70625 | |
| 70626 | li->flags = flags; |
| 70627 | } |
| 70628 | } |
| 70629 | |
| 70630 | /* Lookup active label information. Break/continue distinction is necessary to handle switch |
| 70631 | * statement related labels correctly: a switch will only catch a 'break', not a 'continue'. |
| 70632 | * |
| 70633 | * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled |
| 70634 | * iteration and switch statements) can. A break will match the closest unlabelled or labelled |
| 70635 | * statement. A continue will match the closest unlabelled or labelled iteration statement. It is |
| 70636 | * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot |
| 70637 | * be duplicated, the continue cannot match any valid label outside the switch. |
| 70638 | * |
| 70639 | * A side effect of these rules is that a LABEL statement related to a switch should never actually |
| 70640 | * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the |
| 70641 | * continue slot of the switch's LABEL statement. |
| 70642 | */ |
| 70643 | |
| 70644 | /* XXX: awkward, especially the bunch of separate output values -> output struct? */ |
| 70645 | DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest) { |
| 70646 | duk_hthread *thr = comp_ctx->thr; |
| 70647 | duk_uint8_t *p; |
| 70648 | duk_labelinfo *li_start, *li_end, *li; |
| 70649 | duk_bool_t match = 0; |
| 70650 | |
| 70651 | DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld" , |
| 70652 | (duk_heaphdr *) h_label, (long) is_break)); |
| 70653 | |
| 70654 | DUK_UNREF(thr); |
| 70655 | |
| 70656 | p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos); |
| 70657 | li_start = (duk_labelinfo *) (void *) p; |
| 70658 | li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos)); |
| 70659 | li = li_end; |
| 70660 | |
| 70661 | /* Match labels starting from latest label because there can be duplicate empty |
| 70662 | * labels in the label set. |
| 70663 | */ |
| 70664 | while (li > li_start) { |
| 70665 | li--; |
| 70666 | |
| 70667 | if (li->h_label != h_label) { |
| 70668 | DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O" , |
| 70669 | (long) (li - li_start), |
| 70670 | (duk_heaphdr *) li->h_label, |
| 70671 | (duk_heaphdr *) h_label)); |
| 70672 | continue; |
| 70673 | } |
| 70674 | |
| 70675 | DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)" , |
| 70676 | (long) (li - li_start), (duk_heaphdr *) h_label)); |
| 70677 | |
| 70678 | /* currently all labels accept a break, so no explicit check for it now */ |
| 70679 | DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK); |
| 70680 | |
| 70681 | if (is_break) { |
| 70682 | /* break matches always */ |
| 70683 | match = 1; |
| 70684 | break; |
| 70685 | } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) { |
| 70686 | /* iteration statements allow continue */ |
| 70687 | match = 1; |
| 70688 | break; |
| 70689 | } else { |
| 70690 | /* continue matched this label -- we can only continue if this is the empty |
| 70691 | * label, for which duplication is allowed, and thus there is hope of |
| 70692 | * finding a match deeper in the label stack. |
| 70693 | */ |
| 70694 | if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) { |
| 70695 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL); |
| 70696 | DUK_WO_NORETURN(return;); |
| 70697 | } else { |
| 70698 | DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not " |
| 70699 | "allow a continue -> continue lookup deeper in label stack" )); |
| 70700 | } |
| 70701 | } |
| 70702 | } |
| 70703 | /* XXX: match flag is awkward, rework */ |
| 70704 | if (!match) { |
| 70705 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL); |
| 70706 | DUK_WO_NORETURN(return;); |
| 70707 | } |
| 70708 | |
| 70709 | DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld" , |
| 70710 | (duk_heaphdr *) h_label, (long) li->label_id, |
| 70711 | (long) li->catch_depth, (long) li->pc_label)); |
| 70712 | |
| 70713 | *out_label_id = li->label_id; |
| 70714 | *out_label_catch_depth = li->catch_depth; |
| 70715 | *out_label_pc = li->pc_label; |
| 70716 | *out_is_closest = (li == li_end - 1); |
| 70717 | } |
| 70718 | |
| 70719 | DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len) { |
| 70720 | duk_hthread *thr = comp_ctx->thr; |
| 70721 | |
| 70722 | duk_set_length(thr, comp_ctx->curr_func.labelnames_idx, len); |
| 70723 | duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * len); |
| 70724 | } |
| 70725 | |
| 70726 | /* |
| 70727 | * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers. |
| 70728 | * |
| 70729 | * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal) |
| 70730 | * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator) |
| 70731 | * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token |
| 70732 | */ |
| 70733 | |
| 70734 | /* object literal key tracking flags */ |
| 70735 | #define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */ |
| 70736 | #define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */ |
| 70737 | #define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */ |
| 70738 | |
| 70739 | DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 70740 | duk_hthread *thr = comp_ctx->thr; |
| 70741 | duk_regconst_t reg_obj; /* result reg */ |
| 70742 | duk_regconst_t reg_temp; /* temp reg */ |
| 70743 | duk_regconst_t temp_start; /* temp reg value for start of loop */ |
| 70744 | duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */ |
| 70745 | duk_small_uint_t num_values; /* number of values in current MPUTARR set */ |
| 70746 | duk_uarridx_t curr_idx; /* current (next) array index */ |
| 70747 | duk_uarridx_t start_idx; /* start array index of current MPUTARR set */ |
| 70748 | duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */ |
| 70749 | duk_bool_t require_comma; /* next loop requires a comma */ |
| 70750 | #if !defined(DUK_USE_PREFER_SIZE) |
| 70751 | duk_int_t pc_newarr; |
| 70752 | duk_compiler_instr *instr; |
| 70753 | #endif |
| 70754 | |
| 70755 | /* DUK_TOK_LBRACKET already eaten, current token is right after that */ |
| 70756 | DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET); |
| 70757 | |
| 70758 | max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */ |
| 70759 | |
| 70760 | reg_obj = DUK__ALLOCTEMP(comp_ctx); |
| 70761 | #if !defined(DUK_USE_PREFER_SIZE) |
| 70762 | pc_newarr = duk__get_current_pc(comp_ctx); |
| 70763 | #endif |
| 70764 | duk__emit_bc(comp_ctx, DUK_OP_NEWARR, reg_obj); /* XXX: patch initial size hint afterwards? */ |
| 70765 | temp_start = DUK__GETTEMP(comp_ctx); |
| 70766 | |
| 70767 | /* |
| 70768 | * Emit initializers in sets of maximum max_init_values. |
| 70769 | * Corner cases such as single value initializers do not have |
| 70770 | * special handling now. |
| 70771 | * |
| 70772 | * Elided elements must not be emitted as 'undefined' values, |
| 70773 | * because such values would be enumerable (which is incorrect). |
| 70774 | * Also note that trailing elisions must be reflected in the |
| 70775 | * length of the final array but cause no elements to be actually |
| 70776 | * inserted. |
| 70777 | */ |
| 70778 | |
| 70779 | curr_idx = 0; |
| 70780 | init_idx = 0; /* tracks maximum initialized index + 1 */ |
| 70781 | start_idx = 0; |
| 70782 | require_comma = 0; |
| 70783 | |
| 70784 | for (;;) { |
| 70785 | num_values = 0; |
| 70786 | DUK__SETTEMP(comp_ctx, temp_start); |
| 70787 | |
| 70788 | if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) { |
| 70789 | break; |
| 70790 | } |
| 70791 | |
| 70792 | for (;;) { |
| 70793 | if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) { |
| 70794 | /* the outer loop will recheck and exit */ |
| 70795 | break; |
| 70796 | } |
| 70797 | |
| 70798 | /* comma check */ |
| 70799 | if (require_comma) { |
| 70800 | if (comp_ctx->curr_token.t == DUK_TOK_COMMA) { |
| 70801 | /* comma after a value, expected */ |
| 70802 | duk__advance(comp_ctx); |
| 70803 | require_comma = 0; |
| 70804 | continue; |
| 70805 | } else { |
| 70806 | goto syntax_error; |
| 70807 | } |
| 70808 | } else { |
| 70809 | if (comp_ctx->curr_token.t == DUK_TOK_COMMA) { |
| 70810 | /* elision - flush */ |
| 70811 | curr_idx++; |
| 70812 | duk__advance(comp_ctx); |
| 70813 | /* if num_values > 0, MPUTARR emitted by outer loop after break */ |
| 70814 | break; |
| 70815 | } |
| 70816 | } |
| 70817 | /* else an array initializer element */ |
| 70818 | |
| 70819 | /* initial index */ |
| 70820 | if (num_values == 0) { |
| 70821 | start_idx = curr_idx; |
| 70822 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 70823 | duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx); |
| 70824 | } |
| 70825 | |
| 70826 | reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */ |
| 70827 | DUK__SETTEMP(comp_ctx, reg_temp); |
| 70828 | duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); |
| 70829 | DUK__SETTEMP(comp_ctx, reg_temp + 1); |
| 70830 | |
| 70831 | num_values++; |
| 70832 | curr_idx++; |
| 70833 | require_comma = 1; |
| 70834 | |
| 70835 | if (num_values >= max_init_values) { |
| 70836 | /* MPUTARR emitted by outer loop */ |
| 70837 | break; |
| 70838 | } |
| 70839 | } |
| 70840 | |
| 70841 | if (num_values > 0) { |
| 70842 | /* - A is a source register (it's not a write target, but used |
| 70843 | * to identify the target object) but can be shuffled. |
| 70844 | * - B cannot be shuffled normally because it identifies a range |
| 70845 | * of registers, the emitter has special handling for this |
| 70846 | * (the "no shuffle" flag must not be set). |
| 70847 | * - C is a non-register number and cannot be shuffled, but |
| 70848 | * never needs to be. |
| 70849 | */ |
| 70850 | duk__emit_a_b_c(comp_ctx, |
| 70851 | DUK_OP_MPUTARR | |
| 70852 | DUK__EMIT_FLAG_NO_SHUFFLE_C | |
| 70853 | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 70854 | reg_obj, |
| 70855 | temp_start, |
| 70856 | (duk_regconst_t) (num_values + 1)); |
| 70857 | init_idx = start_idx + num_values; |
| 70858 | |
| 70859 | /* num_values and temp_start reset at top of outer loop */ |
| 70860 | } |
| 70861 | } |
| 70862 | |
| 70863 | /* Update initil size for NEWARR, doesn't need to be exact and is |
| 70864 | * capped at A field limit. |
| 70865 | */ |
| 70866 | #if !defined(DUK_USE_PREFER_SIZE) |
| 70867 | instr = duk__get_instr_ptr(comp_ctx, pc_newarr); |
| 70868 | instr->ins |= DUK_ENC_OP_A(0, curr_idx > DUK_BC_A_MAX ? DUK_BC_A_MAX : curr_idx); |
| 70869 | #endif |
| 70870 | |
| 70871 | DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET); |
| 70872 | duk__advance(comp_ctx); |
| 70873 | |
| 70874 | DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld" , |
| 70875 | (long) curr_idx, (long) init_idx)); |
| 70876 | |
| 70877 | /* trailing elisions? */ |
| 70878 | if (curr_idx > init_idx) { |
| 70879 | /* yes, must set array length explicitly */ |
| 70880 | DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length" )); |
| 70881 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 70882 | duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx); |
| 70883 | duk__emit_a_bc(comp_ctx, |
| 70884 | DUK_OP_SETALEN | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 70885 | reg_obj, |
| 70886 | reg_temp); |
| 70887 | } |
| 70888 | |
| 70889 | DUK__SETTEMP(comp_ctx, temp_start); |
| 70890 | |
| 70891 | duk__ivalue_regconst(res, reg_obj); |
| 70892 | return; |
| 70893 | |
| 70894 | syntax_error: |
| 70895 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL); |
| 70896 | DUK_WO_NORETURN(return;); |
| 70897 | } |
| 70898 | |
| 70899 | typedef struct { |
| 70900 | duk_regconst_t reg_obj; |
| 70901 | duk_regconst_t temp_start; |
| 70902 | duk_small_uint_t num_pairs; |
| 70903 | duk_small_uint_t num_total_pairs; |
| 70904 | } duk__objlit_state; |
| 70905 | |
| 70906 | DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_state *st) { |
| 70907 | if (st->num_pairs > 0) { |
| 70908 | /* - A is a source register (it's not a write target, but used |
| 70909 | * to identify the target object) but can be shuffled. |
| 70910 | * - B cannot be shuffled normally because it identifies a range |
| 70911 | * of registers, the emitter has special handling for this |
| 70912 | * (the "no shuffle" flag must not be set). |
| 70913 | * - C is a non-register number and cannot be shuffled, but |
| 70914 | * never needs to be. |
| 70915 | */ |
| 70916 | DUK_ASSERT(st->num_pairs > 0); |
| 70917 | duk__emit_a_b_c(comp_ctx, |
| 70918 | DUK_OP_MPUTOBJ | |
| 70919 | DUK__EMIT_FLAG_NO_SHUFFLE_C | |
| 70920 | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 70921 | st->reg_obj, |
| 70922 | st->temp_start, |
| 70923 | (duk_regconst_t) (st->num_pairs * 2)); |
| 70924 | st->num_total_pairs += st->num_pairs; |
| 70925 | st->num_pairs = 0; |
| 70926 | } |
| 70927 | DUK__SETTEMP(comp_ctx, st->temp_start); |
| 70928 | } |
| 70929 | |
| 70930 | DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_regconst_t reg_temp) { |
| 70931 | if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t_nores == DUK_TOK_STRING) { |
| 70932 | /* same handling for identifiers and strings */ |
| 70933 | DUK_ASSERT(tok->str1 != NULL); |
| 70934 | duk_push_hstring(comp_ctx->thr, tok->str1); |
| 70935 | } else if (tok->t == DUK_TOK_NUMBER) { |
| 70936 | /* numbers can be loaded as numbers and coerced on the fly */ |
| 70937 | duk_push_number(comp_ctx->thr, tok->num); |
| 70938 | } else { |
| 70939 | return 1; /* error */ |
| 70940 | } |
| 70941 | |
| 70942 | duk__ivalue_plain_fromstack(comp_ctx, res); |
| 70943 | DUK__SETTEMP(comp_ctx, reg_temp + 1); |
| 70944 | duk__ivalue_toforcedreg(comp_ctx, res, reg_temp); |
| 70945 | DUK__SETTEMP(comp_ctx, reg_temp + 1); |
| 70946 | return 0; |
| 70947 | } |
| 70948 | |
| 70949 | DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 70950 | duk_hthread *thr = comp_ctx->thr; |
| 70951 | duk__objlit_state st; |
| 70952 | duk_regconst_t reg_temp; /* temp reg */ |
| 70953 | duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */ |
| 70954 | duk_bool_t first; /* first value: comma must not precede the value */ |
| 70955 | duk_bool_t is_set, is_get; /* temps */ |
| 70956 | #if !defined(DUK_USE_PREFER_SIZE) |
| 70957 | duk_int_t pc_newobj; |
| 70958 | duk_compiler_instr *instr; |
| 70959 | #endif |
| 70960 | |
| 70961 | DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY); |
| 70962 | |
| 70963 | max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */ |
| 70964 | |
| 70965 | st.reg_obj = DUK__ALLOCTEMP(comp_ctx); /* target object */ |
| 70966 | st.temp_start = DUK__GETTEMP(comp_ctx); /* start of MPUTOBJ argument list */ |
| 70967 | st.num_pairs = 0; /* number of key/value pairs emitted for current MPUTOBJ set */ |
| 70968 | st.num_total_pairs = 0; /* number of key/value pairs emitted overall */ |
| 70969 | |
| 70970 | #if !defined(DUK_USE_PREFER_SIZE) |
| 70971 | pc_newobj = duk__get_current_pc(comp_ctx); |
| 70972 | #endif |
| 70973 | duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj); |
| 70974 | |
| 70975 | /* |
| 70976 | * Emit initializers in sets of maximum max_init_pairs keys. |
| 70977 | * Setter/getter is handled separately and terminates the |
| 70978 | * current set of initializer values. Corner cases such as |
| 70979 | * single value initializers do not have special handling now. |
| 70980 | */ |
| 70981 | |
| 70982 | first = 1; |
| 70983 | for (;;) { |
| 70984 | /* |
| 70985 | * ES5 and ES2015+ provide a lot of different PropertyDefinition |
| 70986 | * formats, see http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer. |
| 70987 | * |
| 70988 | * PropertyName can be IdentifierName (includes reserved words), a string |
| 70989 | * literal, or a number literal. Note that IdentifierName allows 'get' and |
| 70990 | * 'set' too, so we need to look ahead to the next token to distinguish: |
| 70991 | * |
| 70992 | * { get : 1 } |
| 70993 | * |
| 70994 | * and |
| 70995 | * |
| 70996 | * { get foo() { return 1 } } |
| 70997 | * { get get() { return 1 } } // 'get' as getter propertyname |
| 70998 | * |
| 70999 | * Finally, a trailing comma is allowed. |
| 71000 | * |
| 71001 | * Key name is coerced to string at compile time (and ends up as a |
| 71002 | * a string constant) even for numeric keys (e.g. "{1:'foo'}"). |
| 71003 | * These could be emitted using e.g. LDINT, but that seems hardly |
| 71004 | * worth the effort and would increase code size. |
| 71005 | */ |
| 71006 | |
| 71007 | DUK_DDD(DUK_DDDPRINT("object literal loop, curr_token->t = %ld" , |
| 71008 | (long) comp_ctx->curr_token.t)); |
| 71009 | |
| 71010 | if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { |
| 71011 | break; |
| 71012 | } |
| 71013 | |
| 71014 | if (first) { |
| 71015 | first = 0; |
| 71016 | } else { |
| 71017 | if (comp_ctx->curr_token.t != DUK_TOK_COMMA) { |
| 71018 | goto syntax_error; |
| 71019 | } |
| 71020 | duk__advance(comp_ctx); |
| 71021 | if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { |
| 71022 | /* trailing comma followed by rcurly */ |
| 71023 | break; |
| 71024 | } |
| 71025 | } |
| 71026 | |
| 71027 | /* Advance to get one step of lookup. */ |
| 71028 | duk__advance(comp_ctx); |
| 71029 | |
| 71030 | /* Flush current MPUTOBJ if enough many pairs gathered. */ |
| 71031 | if (st.num_pairs >= max_init_pairs) { |
| 71032 | duk__objlit_flush_keys(comp_ctx, &st); |
| 71033 | DUK_ASSERT(st.num_pairs == 0); |
| 71034 | } |
| 71035 | |
| 71036 | /* Reset temp register state and reserve reg_temp and |
| 71037 | * reg_temp + 1 for handling the current property. |
| 71038 | */ |
| 71039 | DUK__SETTEMP(comp_ctx, st.temp_start + 2 * (duk_regconst_t) st.num_pairs); |
| 71040 | reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2); |
| 71041 | |
| 71042 | /* NOTE: "get" and "set" are not officially ReservedWords and the lexer |
| 71043 | * currently treats them always like ordinary identifiers (DUK_TOK_GET |
| 71044 | * and DUK_TOK_SET are unused). They need to be detected based on the |
| 71045 | * identifier string content. |
| 71046 | */ |
| 71047 | |
| 71048 | is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && |
| 71049 | comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr)); |
| 71050 | is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && |
| 71051 | comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr)); |
| 71052 | if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) { |
| 71053 | /* getter/setter */ |
| 71054 | duk_int_t fnum; |
| 71055 | |
| 71056 | duk__objlit_flush_keys(comp_ctx, &st); |
| 71057 | DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start); /* 2 regs are guaranteed to be allocated w.r.t. temp_max */ |
| 71058 | reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2); |
| 71059 | |
| 71060 | if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->curr_token, reg_temp) != 0) { |
| 71061 | goto syntax_error; |
| 71062 | } |
| 71063 | |
| 71064 | /* curr_token = get/set name */ |
| 71065 | fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_GETSET); |
| 71066 | |
| 71067 | duk__emit_a_bc(comp_ctx, |
| 71068 | DUK_OP_CLOSURE, |
| 71069 | st.temp_start + 1, |
| 71070 | (duk_regconst_t) fnum); |
| 71071 | |
| 71072 | /* Slot C is used in a non-standard fashion (range of regs), |
| 71073 | * emitter code has special handling for it (must not set the |
| 71074 | * "no shuffle" flag). |
| 71075 | */ |
| 71076 | duk__emit_a_bc(comp_ctx, |
| 71077 | (is_get ? DUK_OP_INITGET : DUK_OP_INITSET) | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 71078 | st.reg_obj, |
| 71079 | st.temp_start); /* temp_start+0 = key, temp_start+1 = closure */ |
| 71080 | |
| 71081 | DUK_ASSERT(st.num_pairs == 0); /* temp state is reset on next loop */ |
| 71082 | #if defined(DUK_USE_ES6) |
| 71083 | } else if (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && |
| 71084 | (comp_ctx->curr_token.t == DUK_TOK_COMMA || comp_ctx->curr_token.t == DUK_TOK_RCURLY)) { |
| 71085 | duk_bool_t load_rc; |
| 71086 | |
| 71087 | load_rc = duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp); |
| 71088 | DUK_UNREF(load_rc); |
| 71089 | DUK_ASSERT(load_rc == 0); /* always succeeds because token is identifier */ |
| 71090 | |
| 71091 | duk__ivalue_var_hstring(comp_ctx, res, comp_ctx->prev_token.str1); |
| 71092 | DUK_ASSERT(DUK__GETTEMP(comp_ctx) == reg_temp + 1); |
| 71093 | duk__ivalue_toforcedreg(comp_ctx, res, reg_temp + 1); |
| 71094 | |
| 71095 | st.num_pairs++; |
| 71096 | } else if ((comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER || |
| 71097 | comp_ctx->prev_token.t == DUK_TOK_STRING || |
| 71098 | comp_ctx->prev_token.t == DUK_TOK_NUMBER) && |
| 71099 | comp_ctx->curr_token.t == DUK_TOK_LPAREN) { |
| 71100 | duk_int_t fnum; |
| 71101 | |
| 71102 | /* Parsing-wise there's a small hickup here: the token parsing |
| 71103 | * state is one step too advanced for the function parse helper |
| 71104 | * compared to other cases. The current solution is an extra |
| 71105 | * flag to indicate whether function parsing should use the |
| 71106 | * current or the previous token to starting parsing from. |
| 71107 | */ |
| 71108 | |
| 71109 | if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) { |
| 71110 | goto syntax_error; |
| 71111 | } |
| 71112 | |
| 71113 | fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_USE_PREVTOKEN | DUK__FUNC_FLAG_METDEF); |
| 71114 | |
| 71115 | duk__emit_a_bc(comp_ctx, |
| 71116 | DUK_OP_CLOSURE, |
| 71117 | reg_temp + 1, |
| 71118 | (duk_regconst_t) fnum); |
| 71119 | |
| 71120 | st.num_pairs++; |
| 71121 | #endif /* DUK_USE_ES6 */ |
| 71122 | } else { |
| 71123 | #if defined(DUK_USE_ES6) |
| 71124 | if (comp_ctx->prev_token.t == DUK_TOK_LBRACKET) { |
| 71125 | /* ES2015 computed property name. Executor ToPropertyKey() |
| 71126 | * coerces the key at runtime. |
| 71127 | */ |
| 71128 | DUK__SETTEMP(comp_ctx, reg_temp); |
| 71129 | duk__expr_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR, reg_temp); |
| 71130 | duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET); |
| 71131 | |
| 71132 | /* XXX: If next token is '(' we're dealing with |
| 71133 | * the method shorthand with a computed name, |
| 71134 | * e.g. { [Symbol.for('foo')](a,b) {} }. This |
| 71135 | * form is not yet supported and causes a |
| 71136 | * SyntaxError on the DUK_TOK_COLON check below. |
| 71137 | */ |
| 71138 | } |
| 71139 | else |
| 71140 | #endif /* DUK_USE_ES6 */ |
| 71141 | { |
| 71142 | if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) { |
| 71143 | goto syntax_error; |
| 71144 | } |
| 71145 | } |
| 71146 | |
| 71147 | duk__advance_expect(comp_ctx, DUK_TOK_COLON); |
| 71148 | |
| 71149 | DUK__SETTEMP(comp_ctx, reg_temp + 1); |
| 71150 | duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp + 1 /*forced_reg*/); |
| 71151 | |
| 71152 | st.num_pairs++; |
| 71153 | } |
| 71154 | } /* property loop */ |
| 71155 | |
| 71156 | /* Flush remaining properties. */ |
| 71157 | duk__objlit_flush_keys(comp_ctx, &st); |
| 71158 | DUK_ASSERT(st.num_pairs == 0); |
| 71159 | DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start); |
| 71160 | |
| 71161 | /* Update initial size for NEWOBJ. The init size doesn't need to be |
| 71162 | * exact as the purpose is just to avoid object resizes in common |
| 71163 | * cases. The size is capped to field A limit, and will be too high |
| 71164 | * if the object literal contains duplicate keys (this is harmless but |
| 71165 | * increases memory traffic if the object is compacted later on). |
| 71166 | */ |
| 71167 | #if !defined(DUK_USE_PREFER_SIZE) |
| 71168 | instr = duk__get_instr_ptr(comp_ctx, pc_newobj); |
| 71169 | instr->ins |= DUK_ENC_OP_A(0, st.num_total_pairs > DUK_BC_A_MAX ? DUK_BC_A_MAX : st.num_total_pairs); |
| 71170 | #endif |
| 71171 | |
| 71172 | DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY); |
| 71173 | duk__advance(comp_ctx); /* No RegExp after object literal. */ |
| 71174 | |
| 71175 | duk__ivalue_regconst(res, st.reg_obj); |
| 71176 | return; |
| 71177 | |
| 71178 | syntax_error: |
| 71179 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL); |
| 71180 | DUK_WO_NORETURN(return;); |
| 71181 | } |
| 71182 | |
| 71183 | /* Parse argument list. Arguments are written to temps starting from |
| 71184 | * "next temp". Returns number of arguments parsed. Expects left paren |
| 71185 | * to be already eaten, and eats the right paren before returning. |
| 71186 | */ |
| 71187 | DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 71188 | duk_int_t nargs = 0; |
| 71189 | duk_regconst_t reg_temp; |
| 71190 | |
| 71191 | /* Note: expect that caller has already eaten the left paren */ |
| 71192 | |
| 71193 | DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld" , |
| 71194 | (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t)); |
| 71195 | |
| 71196 | for (;;) { |
| 71197 | if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) { |
| 71198 | break; |
| 71199 | } |
| 71200 | if (nargs > 0) { |
| 71201 | duk__advance_expect(comp_ctx, DUK_TOK_COMMA); |
| 71202 | } |
| 71203 | |
| 71204 | /* We want the argument expression value to go to "next temp" |
| 71205 | * without additional moves. That should almost always be the |
| 71206 | * case, but we double check after expression parsing. |
| 71207 | * |
| 71208 | * This is not the cleanest possible approach. |
| 71209 | */ |
| 71210 | |
| 71211 | reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */ |
| 71212 | DUK__SETTEMP(comp_ctx, reg_temp); |
| 71213 | |
| 71214 | /* binding power must be high enough to NOT allow comma expressions directly */ |
| 71215 | duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp); /* always allow 'in', coerce to 'tr' just in case */ |
| 71216 | |
| 71217 | DUK__SETTEMP(comp_ctx, reg_temp + 1); |
| 71218 | nargs++; |
| 71219 | |
| 71220 | DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld" , (long) nargs, (long) reg_temp)); |
| 71221 | } |
| 71222 | |
| 71223 | /* eat the right paren */ |
| 71224 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* RegExp mode does not matter. */ |
| 71225 | |
| 71226 | DUK_DDD(DUK_DDDPRINT("end parsing arguments" )); |
| 71227 | |
| 71228 | return nargs; |
| 71229 | } |
| 71230 | |
| 71231 | DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) { |
| 71232 | /* empty expressions can be detected conveniently with nud/led counts */ |
| 71233 | return (comp_ctx->curr_func.nud_count == 0) && |
| 71234 | (comp_ctx->curr_func.led_count == 0); |
| 71235 | } |
| 71236 | |
| 71237 | DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 71238 | duk_hthread *thr = comp_ctx->thr; |
| 71239 | duk_token *tk; |
| 71240 | duk_regconst_t temp_at_entry; |
| 71241 | duk_small_uint_t tok; |
| 71242 | duk_uint32_t args; /* temp variable to pass constants and flags to shared code */ |
| 71243 | |
| 71244 | /* |
| 71245 | * ctx->prev_token token to process with duk__expr_nud() |
| 71246 | * ctx->curr_token updated by caller |
| 71247 | * |
| 71248 | * Note: the token in the switch below has already been eaten. |
| 71249 | */ |
| 71250 | |
| 71251 | temp_at_entry = DUK__GETTEMP(comp_ctx); |
| 71252 | |
| 71253 | comp_ctx->curr_func.nud_count++; |
| 71254 | |
| 71255 | tk = &comp_ctx->prev_token; |
| 71256 | tok = tk->t; |
| 71257 | res->t = DUK_IVAL_NONE; |
| 71258 | |
| 71259 | DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld" , |
| 71260 | (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level)); |
| 71261 | |
| 71262 | switch (tok) { |
| 71263 | |
| 71264 | /* PRIMARY EXPRESSIONS */ |
| 71265 | |
| 71266 | case DUK_TOK_THIS: { |
| 71267 | duk_regconst_t reg_temp; |
| 71268 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 71269 | duk__emit_bc(comp_ctx, |
| 71270 | DUK_OP_LDTHIS, |
| 71271 | reg_temp); |
| 71272 | duk__ivalue_regconst(res, reg_temp); |
| 71273 | return; |
| 71274 | } |
| 71275 | case DUK_TOK_IDENTIFIER: { |
| 71276 | duk__ivalue_var_hstring(comp_ctx, res, tk->str1); |
| 71277 | return; |
| 71278 | } |
| 71279 | case DUK_TOK_NULL: { |
| 71280 | duk_push_null(thr); |
| 71281 | goto plain_value; |
| 71282 | } |
| 71283 | case DUK_TOK_TRUE: { |
| 71284 | duk_push_true(thr); |
| 71285 | goto plain_value; |
| 71286 | } |
| 71287 | case DUK_TOK_FALSE: { |
| 71288 | duk_push_false(thr); |
| 71289 | goto plain_value; |
| 71290 | } |
| 71291 | case DUK_TOK_NUMBER: { |
| 71292 | duk_push_number(thr, tk->num); |
| 71293 | goto plain_value; |
| 71294 | } |
| 71295 | case DUK_TOK_STRING: { |
| 71296 | DUK_ASSERT(tk->str1 != NULL); |
| 71297 | duk_push_hstring(thr, tk->str1); |
| 71298 | goto plain_value; |
| 71299 | } |
| 71300 | case DUK_TOK_REGEXP: { |
| 71301 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 71302 | duk_regconst_t reg_temp; |
| 71303 | duk_regconst_t rc_re_bytecode; /* const */ |
| 71304 | duk_regconst_t rc_re_source; /* const */ |
| 71305 | |
| 71306 | DUK_ASSERT(tk->str1 != NULL); |
| 71307 | DUK_ASSERT(tk->str2 != NULL); |
| 71308 | |
| 71309 | DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O" , |
| 71310 | (duk_heaphdr *) tk->str1, |
| 71311 | (duk_heaphdr *) tk->str2)); |
| 71312 | |
| 71313 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 71314 | duk_push_hstring(thr, tk->str1); |
| 71315 | duk_push_hstring(thr, tk->str2); |
| 71316 | |
| 71317 | /* [ ... pattern flags ] */ |
| 71318 | |
| 71319 | duk_regexp_compile(thr); |
| 71320 | |
| 71321 | /* [ ... escaped_source bytecode ] */ |
| 71322 | |
| 71323 | rc_re_bytecode = duk__getconst(comp_ctx); |
| 71324 | rc_re_source = duk__getconst(comp_ctx); |
| 71325 | |
| 71326 | duk__emit_a_b_c(comp_ctx, |
| 71327 | DUK_OP_REGEXP | DUK__EMIT_FLAG_BC_REGCONST, |
| 71328 | reg_temp /*a*/, |
| 71329 | rc_re_bytecode /*b*/, |
| 71330 | rc_re_source /*c*/); |
| 71331 | |
| 71332 | duk__ivalue_regconst(res, reg_temp); |
| 71333 | return; |
| 71334 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 71335 | goto syntax_error; |
| 71336 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 71337 | } |
| 71338 | case DUK_TOK_LBRACKET: { |
| 71339 | DUK_DDD(DUK_DDDPRINT("parsing array literal" )); |
| 71340 | duk__nud_array_literal(comp_ctx, res); |
| 71341 | return; |
| 71342 | } |
| 71343 | case DUK_TOK_LCURLY: { |
| 71344 | DUK_DDD(DUK_DDDPRINT("parsing object literal" )); |
| 71345 | duk__nud_object_literal(comp_ctx, res); |
| 71346 | return; |
| 71347 | } |
| 71348 | case DUK_TOK_LPAREN: { |
| 71349 | duk_bool_t prev_allow_in; |
| 71350 | |
| 71351 | comp_ctx->curr_func.paren_level++; |
| 71352 | prev_allow_in = comp_ctx->curr_func.allow_in; |
| 71353 | comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */ |
| 71354 | |
| 71355 | duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */ |
| 71356 | |
| 71357 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* No RegExp after parenthesized expression. */ |
| 71358 | comp_ctx->curr_func.allow_in = prev_allow_in; |
| 71359 | comp_ctx->curr_func.paren_level--; |
| 71360 | return; |
| 71361 | } |
| 71362 | |
| 71363 | /* MEMBER/NEW/CALL EXPRESSIONS */ |
| 71364 | |
| 71365 | case DUK_TOK_NEW: { |
| 71366 | /* |
| 71367 | * Parsing an expression starting with 'new' is tricky because |
| 71368 | * there are multiple possible productions deriving from |
| 71369 | * LeftHandSideExpression which begin with 'new'. |
| 71370 | * |
| 71371 | * We currently resort to one-token lookahead to distinguish the |
| 71372 | * cases. Hopefully this is correct. The binding power must be |
| 71373 | * such that parsing ends at an LPAREN (CallExpression) but not at |
| 71374 | * a PERIOD or LBRACKET (MemberExpression). |
| 71375 | * |
| 71376 | * See doc/compiler.rst for discussion on the parsing approach, |
| 71377 | * and testcases/test-dev-new.js for a bunch of documented tests. |
| 71378 | */ |
| 71379 | |
| 71380 | duk_regconst_t reg_target; |
| 71381 | duk_int_t nargs; |
| 71382 | |
| 71383 | DUK_DDD(DUK_DDDPRINT("begin parsing new expression" )); |
| 71384 | |
| 71385 | reg_target = DUK__ALLOCTEMPS(comp_ctx, 2); |
| 71386 | |
| 71387 | #if defined(DUK_USE_ES6) |
| 71388 | if (comp_ctx->curr_token.t == DUK_TOK_PERIOD) { |
| 71389 | /* new.target */ |
| 71390 | DUK_DDD(DUK_DDDPRINT("new.target" )); |
| 71391 | duk__advance(comp_ctx); |
| 71392 | if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER || |
| 71393 | !duk_hstring_equals_ascii_cstring(comp_ctx->curr_token.str1, "target" )) { |
| 71394 | goto syntax_error_newtarget; |
| 71395 | } |
| 71396 | if (comp_ctx->curr_func.is_global) { |
| 71397 | goto syntax_error_newtarget; |
| 71398 | } |
| 71399 | duk__advance(comp_ctx); |
| 71400 | duk__emit_bc(comp_ctx, |
| 71401 | DUK_OP_NEWTARGET, |
| 71402 | reg_target); |
| 71403 | duk__ivalue_regconst(res, reg_target); |
| 71404 | return; |
| 71405 | } |
| 71406 | #endif /* DUK_USE_ES6 */ |
| 71407 | |
| 71408 | duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/); |
| 71409 | duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, reg_target + 1); /* default instance */ |
| 71410 | DUK__SETTEMP(comp_ctx, reg_target + 2); |
| 71411 | |
| 71412 | /* XXX: 'new obj.noSuch()' doesn't use GETPROPC now which |
| 71413 | * makes the error message worse than for obj.noSuch(). |
| 71414 | */ |
| 71415 | |
| 71416 | if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) { |
| 71417 | /* 'new' MemberExpression Arguments */ |
| 71418 | DUK_DDD(DUK_DDDPRINT("new expression has argument list" )); |
| 71419 | duk__advance(comp_ctx); |
| 71420 | nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp", reg_target + 1 */ |
| 71421 | /* right paren eaten */ |
| 71422 | } else { |
| 71423 | /* 'new' MemberExpression */ |
| 71424 | DUK_DDD(DUK_DDDPRINT("new expression has no argument list" )); |
| 71425 | nargs = 0; |
| 71426 | } |
| 71427 | |
| 71428 | duk__emit_a_bc(comp_ctx, |
| 71429 | DUK_OP_CALL0 | DUK_BC_CALL_FLAG_CONSTRUCT, |
| 71430 | nargs /*num_args*/, |
| 71431 | reg_target /*target*/); |
| 71432 | |
| 71433 | DUK_DDD(DUK_DDDPRINT("end parsing new expression" )); |
| 71434 | |
| 71435 | duk__ivalue_regconst(res, reg_target); |
| 71436 | return; |
| 71437 | } |
| 71438 | |
| 71439 | /* FUNCTION EXPRESSIONS */ |
| 71440 | |
| 71441 | case DUK_TOK_FUNCTION: { |
| 71442 | /* Function expression. Note that any statement beginning with 'function' |
| 71443 | * is handled by the statement parser as a function declaration, or a |
| 71444 | * non-standard function expression/statement (or a SyntaxError). We only |
| 71445 | * handle actual function expressions (occurring inside an expression) here. |
| 71446 | * |
| 71447 | * O(depth^2) parse count for inner functions is handled by recording a |
| 71448 | * lexer offset on the first compilation pass, so that the function can |
| 71449 | * be efficiently skipped on the second pass. This is encapsulated into |
| 71450 | * duk__parse_func_like_fnum(). |
| 71451 | */ |
| 71452 | |
| 71453 | duk_regconst_t reg_temp; |
| 71454 | duk_int_t fnum; |
| 71455 | |
| 71456 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 71457 | |
| 71458 | /* curr_token follows 'function' */ |
| 71459 | fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*flags*/); |
| 71460 | DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld" , (long) fnum)); |
| 71461 | |
| 71462 | duk__emit_a_bc(comp_ctx, |
| 71463 | DUK_OP_CLOSURE, |
| 71464 | reg_temp /*a*/, |
| 71465 | (duk_regconst_t) fnum /*bc*/); |
| 71466 | |
| 71467 | duk__ivalue_regconst(res, reg_temp); |
| 71468 | return; |
| 71469 | } |
| 71470 | |
| 71471 | /* UNARY EXPRESSIONS */ |
| 71472 | |
| 71473 | case DUK_TOK_DELETE: { |
| 71474 | /* Delete semantics are a bit tricky. The description in E5 specification |
| 71475 | * is kind of confusing, because it distinguishes between resolvability of |
| 71476 | * a reference (which is only known at runtime) seemingly at compile time |
| 71477 | * (= SyntaxError throwing). |
| 71478 | */ |
| 71479 | duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71480 | if (res->t == DUK_IVAL_VAR) { |
| 71481 | /* not allowed in strict mode, regardless of whether resolves; |
| 71482 | * in non-strict mode DELVAR handles both non-resolving and |
| 71483 | * resolving cases (the specification description is a bit confusing). |
| 71484 | */ |
| 71485 | |
| 71486 | duk_regconst_t reg_temp; |
| 71487 | duk_regconst_t reg_varbind; |
| 71488 | duk_regconst_t rc_varname; |
| 71489 | |
| 71490 | if (comp_ctx->curr_func.is_strict) { |
| 71491 | DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER); |
| 71492 | DUK_WO_NORETURN(return;); |
| 71493 | } |
| 71494 | |
| 71495 | DUK__SETTEMP(comp_ctx, temp_at_entry); |
| 71496 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 71497 | |
| 71498 | duk_dup(thr, res->x1.valstack_idx); |
| 71499 | if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { |
| 71500 | /* register bound variables are non-configurable -> always false */ |
| 71501 | duk__emit_bc(comp_ctx, |
| 71502 | DUK_OP_LDFALSE, |
| 71503 | reg_temp); |
| 71504 | } else { |
| 71505 | duk_dup(thr, res->x1.valstack_idx); |
| 71506 | rc_varname = duk__getconst(comp_ctx); |
| 71507 | duk__emit_a_bc(comp_ctx, |
| 71508 | DUK_OP_DELVAR, |
| 71509 | reg_temp, |
| 71510 | rc_varname); |
| 71511 | } |
| 71512 | duk__ivalue_regconst(res, reg_temp); |
| 71513 | } else if (res->t == DUK_IVAL_PROP) { |
| 71514 | duk_regconst_t reg_temp; |
| 71515 | duk_regconst_t reg_obj; |
| 71516 | duk_regconst_t rc_key; |
| 71517 | |
| 71518 | DUK__SETTEMP(comp_ctx, temp_at_entry); |
| 71519 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 71520 | reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ |
| 71521 | rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); |
| 71522 | duk__emit_a_b_c(comp_ctx, |
| 71523 | DUK_OP_DELPROP | DUK__EMIT_FLAG_BC_REGCONST, |
| 71524 | reg_temp, |
| 71525 | reg_obj, |
| 71526 | rc_key); |
| 71527 | |
| 71528 | duk__ivalue_regconst(res, reg_temp); |
| 71529 | } else { |
| 71530 | /* non-Reference deletion is always 'true', even in strict mode */ |
| 71531 | duk_push_true(thr); |
| 71532 | goto plain_value; |
| 71533 | } |
| 71534 | return; |
| 71535 | } |
| 71536 | case DUK_TOK_VOID: { |
| 71537 | duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71538 | duk_push_undefined(thr); |
| 71539 | goto plain_value; |
| 71540 | } |
| 71541 | case DUK_TOK_TYPEOF: { |
| 71542 | /* 'typeof' must handle unresolvable references without throwing |
| 71543 | * a ReferenceError (E5 Section 11.4.3). Register mapped values |
| 71544 | * will never be unresolvable so special handling is only required |
| 71545 | * when an identifier is a "slow path" one. |
| 71546 | */ |
| 71547 | duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71548 | |
| 71549 | if (res->t == DUK_IVAL_VAR) { |
| 71550 | duk_regconst_t reg_varbind; |
| 71551 | duk_regconst_t rc_varname; |
| 71552 | duk_regconst_t reg_temp; |
| 71553 | |
| 71554 | duk_dup(thr, res->x1.valstack_idx); |
| 71555 | if (!duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { |
| 71556 | DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved " |
| 71557 | "at compile time, need to use special run-time handling" )); |
| 71558 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 71559 | duk__emit_a_bc(comp_ctx, |
| 71560 | DUK_OP_TYPEOFID, |
| 71561 | reg_temp, |
| 71562 | rc_varname); |
| 71563 | duk__ivalue_regconst(res, reg_temp); |
| 71564 | return; |
| 71565 | } |
| 71566 | } |
| 71567 | |
| 71568 | args = DUK_OP_TYPEOF; |
| 71569 | goto unary; |
| 71570 | } |
| 71571 | case DUK_TOK_INCREMENT: { |
| 71572 | args = (DUK_OP_PREINCP << 8) + DUK_OP_PREINCR; |
| 71573 | goto preincdec; |
| 71574 | } |
| 71575 | case DUK_TOK_DECREMENT: { |
| 71576 | args = (DUK_OP_PREDECP << 8) + DUK_OP_PREDECR; |
| 71577 | goto preincdec; |
| 71578 | } |
| 71579 | case DUK_TOK_ADD: { |
| 71580 | /* unary plus */ |
| 71581 | duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71582 | if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE && |
| 71583 | duk_is_number(thr, res->x1.valstack_idx)) { |
| 71584 | /* unary plus of a number is identity */ |
| 71585 | return; |
| 71586 | } |
| 71587 | args = DUK_OP_UNP; |
| 71588 | goto unary; |
| 71589 | } |
| 71590 | case DUK_TOK_SUB: { |
| 71591 | /* unary minus */ |
| 71592 | duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71593 | if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE && |
| 71594 | duk_is_number(thr, res->x1.valstack_idx)) { |
| 71595 | /* this optimization is important to handle negative literals |
| 71596 | * (which are not directly provided by the lexical grammar) |
| 71597 | */ |
| 71598 | duk_tval *tv_num; |
| 71599 | duk_double_union du; |
| 71600 | |
| 71601 | tv_num = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx); |
| 71602 | DUK_ASSERT(tv_num != NULL); |
| 71603 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num)); |
| 71604 | du.d = DUK_TVAL_GET_NUMBER(tv_num); |
| 71605 | du.d = -du.d; |
| 71606 | DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); |
| 71607 | DUK_TVAL_SET_NUMBER(tv_num, du.d); |
| 71608 | return; |
| 71609 | } |
| 71610 | args = DUK_OP_UNM; |
| 71611 | goto unary; |
| 71612 | } |
| 71613 | case DUK_TOK_BNOT: { |
| 71614 | duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71615 | args = DUK_OP_BNOT; |
| 71616 | goto unary; |
| 71617 | } |
| 71618 | case DUK_TOK_LNOT: { |
| 71619 | duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71620 | if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) { |
| 71621 | /* Very minimal inlining to handle common idioms '!0' and '!1', |
| 71622 | * and also boolean arguments like '!false' and '!true'. |
| 71623 | */ |
| 71624 | duk_tval *tv_val; |
| 71625 | |
| 71626 | tv_val = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx); |
| 71627 | DUK_ASSERT(tv_val != NULL); |
| 71628 | if (DUK_TVAL_IS_NUMBER(tv_val)) { |
| 71629 | duk_double_t d; |
| 71630 | d = DUK_TVAL_GET_NUMBER(tv_val); |
| 71631 | if (duk_double_equals(d, 0.0)) { |
| 71632 | /* Matches both +0 and -0 on purpose. */ |
| 71633 | DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true" )); |
| 71634 | DUK_TVAL_SET_BOOLEAN_TRUE(tv_val); |
| 71635 | return; |
| 71636 | } else if (duk_double_equals(d, 1.0)) { |
| 71637 | DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false" )); |
| 71638 | DUK_TVAL_SET_BOOLEAN_FALSE(tv_val); |
| 71639 | return; |
| 71640 | } |
| 71641 | } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) { |
| 71642 | duk_small_uint_t v; |
| 71643 | v = DUK_TVAL_GET_BOOLEAN(tv_val); |
| 71644 | DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld" , (long) v)); |
| 71645 | DUK_ASSERT(v == 0 || v == 1); |
| 71646 | DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01); |
| 71647 | return; |
| 71648 | } |
| 71649 | } |
| 71650 | args = DUK_OP_LNOT; |
| 71651 | goto unary; |
| 71652 | } |
| 71653 | |
| 71654 | } /* end switch */ |
| 71655 | |
| 71656 | DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); |
| 71657 | DUK_WO_NORETURN(return;); |
| 71658 | |
| 71659 | unary: |
| 71660 | { |
| 71661 | /* Unary opcodes use just the 'BC' register source because it |
| 71662 | * matches current shuffle limits, and maps cleanly to 16 high |
| 71663 | * bits of the opcode. |
| 71664 | */ |
| 71665 | |
| 71666 | duk_regconst_t reg_src, reg_res; |
| 71667 | |
| 71668 | reg_src = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*flags*/); |
| 71669 | if (DUK__ISREG_TEMP(comp_ctx, reg_src)) { |
| 71670 | reg_res = reg_src; |
| 71671 | } else { |
| 71672 | reg_res = DUK__ALLOCTEMP(comp_ctx); |
| 71673 | } |
| 71674 | duk__emit_a_bc(comp_ctx, |
| 71675 | args, |
| 71676 | reg_res, |
| 71677 | reg_src); |
| 71678 | duk__ivalue_regconst(res, reg_res); |
| 71679 | return; |
| 71680 | } |
| 71681 | |
| 71682 | preincdec: |
| 71683 | { |
| 71684 | /* preincrement and predecrement */ |
| 71685 | duk_regconst_t reg_res; |
| 71686 | duk_small_uint_t args_op1 = args & 0xff; /* DUK_OP_PREINCR/DUK_OP_PREDECR */ |
| 71687 | duk_small_uint_t args_op2 = args >> 8; /* DUK_OP_PREINCP_RR/DUK_OP_PREDECP_RR */ |
| 71688 | |
| 71689 | /* Specific assumptions for opcode numbering. */ |
| 71690 | DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV); |
| 71691 | DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV); |
| 71692 | |
| 71693 | reg_res = DUK__ALLOCTEMP(comp_ctx); |
| 71694 | |
| 71695 | duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ |
| 71696 | if (res->t == DUK_IVAL_VAR) { |
| 71697 | duk_hstring *h_varname; |
| 71698 | duk_regconst_t reg_varbind; |
| 71699 | duk_regconst_t rc_varname; |
| 71700 | |
| 71701 | h_varname = duk_known_hstring(thr, res->x1.valstack_idx); |
| 71702 | |
| 71703 | if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { |
| 71704 | goto syntax_error; |
| 71705 | } |
| 71706 | |
| 71707 | duk_dup(thr, res->x1.valstack_idx); |
| 71708 | if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { |
| 71709 | duk__emit_a_bc(comp_ctx, |
| 71710 | args_op1, /* e.g. DUK_OP_PREINCR */ |
| 71711 | reg_res, |
| 71712 | reg_varbind); |
| 71713 | } else { |
| 71714 | duk__emit_a_bc(comp_ctx, |
| 71715 | args_op1 + 4, /* e.g. DUK_OP_PREINCV */ |
| 71716 | reg_res, |
| 71717 | rc_varname); |
| 71718 | } |
| 71719 | |
| 71720 | DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld" , |
| 71721 | (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname)); |
| 71722 | } else if (res->t == DUK_IVAL_PROP) { |
| 71723 | duk_regconst_t reg_obj; /* allocate to reg only (not const) */ |
| 71724 | duk_regconst_t rc_key; |
| 71725 | reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ |
| 71726 | rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); |
| 71727 | duk__emit_a_b_c(comp_ctx, |
| 71728 | args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_PREINCP */ |
| 71729 | reg_res, |
| 71730 | reg_obj, |
| 71731 | rc_key); |
| 71732 | } else { |
| 71733 | /* Technically return value is not needed because INVLHS will |
| 71734 | * unconditially throw a ReferenceError. Coercion is necessary |
| 71735 | * for proper semantics (consider ToNumber() called for an object). |
| 71736 | * Use DUK_OP_UNP with a dummy register to get ToNumber(). |
| 71737 | */ |
| 71738 | |
| 71739 | duk__ivalue_toforcedreg(comp_ctx, res, reg_res); |
| 71740 | duk__emit_bc(comp_ctx, |
| 71741 | DUK_OP_UNP, |
| 71742 | reg_res); /* for side effects, result ignored */ |
| 71743 | duk__emit_op_only(comp_ctx, |
| 71744 | DUK_OP_INVLHS); |
| 71745 | } |
| 71746 | DUK__SETTEMP(comp_ctx, reg_res + 1); |
| 71747 | duk__ivalue_regconst(res, reg_res); |
| 71748 | return; |
| 71749 | } |
| 71750 | |
| 71751 | plain_value: |
| 71752 | { |
| 71753 | /* Stack top contains plain value */ |
| 71754 | duk__ivalue_plain_fromstack(comp_ctx, res); |
| 71755 | return; |
| 71756 | } |
| 71757 | |
| 71758 | #if defined(DUK_USE_ES6) |
| 71759 | syntax_error_newtarget: |
| 71760 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_NEWTARGET); |
| 71761 | DUK_WO_NORETURN(return;); |
| 71762 | #endif |
| 71763 | |
| 71764 | syntax_error: |
| 71765 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION); |
| 71766 | DUK_WO_NORETURN(return;); |
| 71767 | } |
| 71768 | |
| 71769 | /* XXX: add flag to indicate whether caller cares about return value; this |
| 71770 | * affects e.g. handling of assignment expressions. This change needs API |
| 71771 | * changes elsewhere too. |
| 71772 | */ |
| 71773 | DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) { |
| 71774 | duk_hthread *thr = comp_ctx->thr; |
| 71775 | duk_token *tk; |
| 71776 | duk_small_uint_t tok; |
| 71777 | duk_uint32_t args; /* temp variable to pass constants and flags to shared code */ |
| 71778 | |
| 71779 | /* |
| 71780 | * ctx->prev_token token to process with duk__expr_led() |
| 71781 | * ctx->curr_token updated by caller |
| 71782 | */ |
| 71783 | |
| 71784 | comp_ctx->curr_func.led_count++; |
| 71785 | |
| 71786 | /* The token in the switch has already been eaten here */ |
| 71787 | tk = &comp_ctx->prev_token; |
| 71788 | tok = tk->t; |
| 71789 | |
| 71790 | DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld" , |
| 71791 | (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level)); |
| 71792 | |
| 71793 | /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */ |
| 71794 | |
| 71795 | switch (tok) { |
| 71796 | |
| 71797 | /* PRIMARY EXPRESSIONS */ |
| 71798 | |
| 71799 | case DUK_TOK_PERIOD: { |
| 71800 | /* Property access expressions are critical for correct LHS ordering, |
| 71801 | * see comments in duk__expr()! |
| 71802 | * |
| 71803 | * A conservative approach would be to use duk__ivalue_totempconst() |
| 71804 | * for 'left'. However, allowing a reg-bound variable seems safe here |
| 71805 | * and is nice because "foo.bar" is a common expression. If the ivalue |
| 71806 | * is used in an expression a GETPROP will occur before any changes to |
| 71807 | * the base value can occur. If the ivalue is used as an assignment |
| 71808 | * LHS, the assignment code will ensure the base value is safe from |
| 71809 | * RHS mutation. |
| 71810 | */ |
| 71811 | |
| 71812 | /* XXX: This now coerces an identifier into a GETVAR to a temp, which |
| 71813 | * causes an extra LDREG in call setup. It's sufficient to coerce to a |
| 71814 | * unary ivalue? |
| 71815 | */ |
| 71816 | duk__ivalue_toplain(comp_ctx, left); |
| 71817 | |
| 71818 | /* NB: must accept reserved words as property name */ |
| 71819 | if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) { |
| 71820 | DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER); |
| 71821 | DUK_WO_NORETURN(return;); |
| 71822 | } |
| 71823 | |
| 71824 | res->t = DUK_IVAL_PROP; |
| 71825 | duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */ |
| 71826 | DUK_ASSERT(comp_ctx->curr_token.str1 != NULL); |
| 71827 | duk_push_hstring(thr, comp_ctx->curr_token.str1); |
| 71828 | duk_replace(thr, res->x2.valstack_idx); |
| 71829 | res->x2.t = DUK_ISPEC_VALUE; |
| 71830 | |
| 71831 | /* special RegExp literal handling after IdentifierName */ |
| 71832 | comp_ctx->curr_func.reject_regexp_in_adv = 1; |
| 71833 | |
| 71834 | duk__advance(comp_ctx); |
| 71835 | return; |
| 71836 | } |
| 71837 | case DUK_TOK_LBRACKET: { |
| 71838 | /* Property access expressions are critical for correct LHS ordering, |
| 71839 | * see comments in duk__expr()! |
| 71840 | */ |
| 71841 | |
| 71842 | /* XXX: optimize temp reg use */ |
| 71843 | /* XXX: similar coercion issue as in DUK_TOK_PERIOD */ |
| 71844 | /* XXX: coerce to regs? it might be better for enumeration use, where the |
| 71845 | * same PROP ivalue is used multiple times. Or perhaps coerce PROP further |
| 71846 | * there? |
| 71847 | */ |
| 71848 | /* XXX: for simple cases like x['y'] an unnecessary LDREG is |
| 71849 | * emitted for the base value; could avoid it if we knew that |
| 71850 | * the key expression is safe (e.g. just a single literal). |
| 71851 | */ |
| 71852 | |
| 71853 | /* The 'left' value must not be a register bound variable |
| 71854 | * because it may be mutated during the rest of the expression |
| 71855 | * and E5.1 Section 11.2.1 specifies the order of evaluation |
| 71856 | * so that the base value is evaluated first. |
| 71857 | * See: test-bug-nested-prop-mutate.js. |
| 71858 | */ |
| 71859 | duk__ivalue_totempconst(comp_ctx, left); |
| 71860 | duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */ |
| 71861 | duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET); |
| 71862 | |
| 71863 | res->t = DUK_IVAL_PROP; |
| 71864 | duk__copy_ispec(comp_ctx, &res->x1, &res->x2); /* res.x1 -> res.x2 */ |
| 71865 | duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */ |
| 71866 | return; |
| 71867 | } |
| 71868 | case DUK_TOK_LPAREN: { |
| 71869 | /* function call */ |
| 71870 | duk_regconst_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2); |
| 71871 | duk_int_t nargs; |
| 71872 | duk_small_uint_t call_op = DUK_OP_CALL0; |
| 71873 | |
| 71874 | /* XXX: attempt to get the call result to "next temp" whenever |
| 71875 | * possible to avoid unnecessary register shuffles. |
| 71876 | */ |
| 71877 | |
| 71878 | /* |
| 71879 | * Setup call: target and 'this' binding. Three cases: |
| 71880 | * |
| 71881 | * 1. Identifier base (e.g. "foo()") |
| 71882 | * 2. Property base (e.g. "foo.bar()") |
| 71883 | * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function) |
| 71884 | */ |
| 71885 | |
| 71886 | if (left->t == DUK_IVAL_VAR) { |
| 71887 | duk_hstring *h_varname; |
| 71888 | duk_regconst_t reg_varbind; |
| 71889 | duk_regconst_t rc_varname; |
| 71890 | |
| 71891 | DUK_DDD(DUK_DDDPRINT("function call with identifier base" )); |
| 71892 | |
| 71893 | h_varname = duk_known_hstring(thr, left->x1.valstack_idx); |
| 71894 | if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) { |
| 71895 | /* Potential direct eval call detected, flag the CALL |
| 71896 | * so that a run-time "direct eval" check is made and |
| 71897 | * special behavior may be triggered. Note that this |
| 71898 | * does not prevent 'eval' from being register bound. |
| 71899 | */ |
| 71900 | DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' " |
| 71901 | "-> using EVALCALL, marking function " |
| 71902 | "as may_direct_eval" )); |
| 71903 | call_op |= DUK_BC_CALL_FLAG_CALLED_AS_EVAL; |
| 71904 | comp_ctx->curr_func.may_direct_eval = 1; |
| 71905 | } |
| 71906 | |
| 71907 | duk_dup(thr, left->x1.valstack_idx); |
| 71908 | if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { |
| 71909 | duk__emit_a_bc(comp_ctx, |
| 71910 | DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 71911 | reg_varbind, |
| 71912 | reg_cs + 0); |
| 71913 | } else { |
| 71914 | /* XXX: expand target register or constant field to |
| 71915 | * reduce shuffling. |
| 71916 | */ |
| 71917 | DUK_ASSERT(DUK__ISCONST(rc_varname)); |
| 71918 | duk__emit_a_b(comp_ctx, |
| 71919 | DUK_OP_CSVAR | DUK__EMIT_FLAG_BC_REGCONST, |
| 71920 | reg_cs + 0, |
| 71921 | rc_varname); |
| 71922 | } |
| 71923 | } else if (left->t == DUK_IVAL_PROP) { |
| 71924 | /* Call through a property lookup, E5 Section 11.2.3, step 6.a.i, |
| 71925 | * E5 Section 10.4.3. There used to be a separate CSPROP opcode |
| 71926 | * but a typical call setup took 3 opcodes (e.g. LDREG, LDCONST, |
| 71927 | * CSPROP) and the same can be achieved with ordinary loads. |
| 71928 | */ |
| 71929 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 71930 | duk_regconst_t reg_key; |
| 71931 | #endif |
| 71932 | |
| 71933 | DUK_DDD(DUK_DDDPRINT("function call with property base" )); |
| 71934 | |
| 71935 | /* XXX: For Math.sin() this generates: LDCONST + LDREG + |
| 71936 | * GETPROPC + call. The LDREG is unnecessary because LDCONST |
| 71937 | * could be loaded directly into reg_cs + 1. This doesn't |
| 71938 | * happen now because a variable cannot be in left->x1 of a |
| 71939 | * DUK_IVAL_PROP. We could notice that left->x1 is a temp |
| 71940 | * and reuse, but it would still be in the wrong position |
| 71941 | * (reg_cs + 0 rather than reg_cs + 1). |
| 71942 | */ |
| 71943 | duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 1); /* base */ |
| 71944 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 71945 | reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); |
| 71946 | duk__emit_a_b_c(comp_ctx, |
| 71947 | DUK_OP_GETPROPC | DUK__EMIT_FLAG_BC_REGCONST, |
| 71948 | reg_cs + 0, |
| 71949 | reg_cs + 1, |
| 71950 | reg_key); |
| 71951 | #else |
| 71952 | duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); /* base[key] */ |
| 71953 | #endif |
| 71954 | } else { |
| 71955 | DUK_DDD(DUK_DDDPRINT("function call with register base" )); |
| 71956 | |
| 71957 | duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); |
| 71958 | #if 0 |
| 71959 | duk__emit_a_bc(comp_ctx, |
| 71960 | DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 71961 | reg_cs + 0, |
| 71962 | reg_cs + 0); /* in-place setup */ |
| 71963 | #endif |
| 71964 | /* Because of in-place setup, REGCS is equivalent to |
| 71965 | * just this LDUNDEF. |
| 71966 | */ |
| 71967 | duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, reg_cs + 1); |
| 71968 | } |
| 71969 | |
| 71970 | DUK__SETTEMP(comp_ctx, reg_cs + 2); |
| 71971 | nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */ |
| 71972 | |
| 71973 | /* Tailcalls are handled by back-patching the already emitted opcode |
| 71974 | * later in return statement parser. |
| 71975 | */ |
| 71976 | |
| 71977 | duk__emit_a_bc(comp_ctx, |
| 71978 | call_op, |
| 71979 | (duk_regconst_t) nargs /*numargs*/, |
| 71980 | reg_cs /*basereg*/); |
| 71981 | DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */ |
| 71982 | |
| 71983 | duk__ivalue_regconst(res, reg_cs); |
| 71984 | return; |
| 71985 | } |
| 71986 | |
| 71987 | /* POSTFIX EXPRESSION */ |
| 71988 | |
| 71989 | case DUK_TOK_INCREMENT: { |
| 71990 | args = (DUK_OP_POSTINCP_RR << 16) + (DUK_OP_POSTINCR << 8) + 0; |
| 71991 | goto postincdec; |
| 71992 | } |
| 71993 | case DUK_TOK_DECREMENT: { |
| 71994 | args = (DUK_OP_POSTDECP_RR << 16) + (DUK_OP_POSTDECR << 8) + 0; |
| 71995 | goto postincdec; |
| 71996 | } |
| 71997 | |
| 71998 | /* EXPONENTIATION EXPRESSION */ |
| 71999 | |
| 72000 | #if defined(DUK_USE_ES7_EXP_OPERATOR) |
| 72001 | case DUK_TOK_EXP: { |
| 72002 | args = (DUK_OP_EXP << 8) + DUK__BP_EXPONENTIATION - 1; /* UnaryExpression */ |
| 72003 | goto binary; |
| 72004 | } |
| 72005 | #endif |
| 72006 | |
| 72007 | /* MULTIPLICATIVE EXPRESSION */ |
| 72008 | |
| 72009 | case DUK_TOK_MUL: { |
| 72010 | args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */ |
| 72011 | goto binary; |
| 72012 | } |
| 72013 | case DUK_TOK_DIV: { |
| 72014 | args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */ |
| 72015 | goto binary; |
| 72016 | } |
| 72017 | case DUK_TOK_MOD: { |
| 72018 | args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */ |
| 72019 | goto binary; |
| 72020 | } |
| 72021 | |
| 72022 | /* ADDITIVE EXPRESSION */ |
| 72023 | |
| 72024 | case DUK_TOK_ADD: { |
| 72025 | args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */ |
| 72026 | goto binary; |
| 72027 | } |
| 72028 | case DUK_TOK_SUB: { |
| 72029 | args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */ |
| 72030 | goto binary; |
| 72031 | } |
| 72032 | |
| 72033 | /* SHIFT EXPRESSION */ |
| 72034 | |
| 72035 | case DUK_TOK_ALSHIFT: { |
| 72036 | /* << */ |
| 72037 | args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT; |
| 72038 | goto binary; |
| 72039 | } |
| 72040 | case DUK_TOK_ARSHIFT: { |
| 72041 | /* >> */ |
| 72042 | args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT; |
| 72043 | goto binary; |
| 72044 | } |
| 72045 | case DUK_TOK_RSHIFT: { |
| 72046 | /* >>> */ |
| 72047 | args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT; |
| 72048 | goto binary; |
| 72049 | } |
| 72050 | |
| 72051 | /* RELATIONAL EXPRESSION */ |
| 72052 | |
| 72053 | case DUK_TOK_LT: { |
| 72054 | /* < */ |
| 72055 | args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL; |
| 72056 | goto binary; |
| 72057 | } |
| 72058 | case DUK_TOK_GT: { |
| 72059 | args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL; |
| 72060 | goto binary; |
| 72061 | } |
| 72062 | case DUK_TOK_LE: { |
| 72063 | args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL; |
| 72064 | goto binary; |
| 72065 | } |
| 72066 | case DUK_TOK_GE: { |
| 72067 | args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL; |
| 72068 | goto binary; |
| 72069 | } |
| 72070 | case DUK_TOK_INSTANCEOF: { |
| 72071 | args = (DUK_OP_INSTOF << 8) + DUK__BP_RELATIONAL; |
| 72072 | goto binary; |
| 72073 | } |
| 72074 | case DUK_TOK_IN: { |
| 72075 | args = (DUK_OP_IN << 8) + DUK__BP_RELATIONAL; |
| 72076 | goto binary; |
| 72077 | } |
| 72078 | |
| 72079 | /* EQUALITY EXPRESSION */ |
| 72080 | |
| 72081 | case DUK_TOK_EQ: { |
| 72082 | args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY; |
| 72083 | goto binary; |
| 72084 | } |
| 72085 | case DUK_TOK_NEQ: { |
| 72086 | args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY; |
| 72087 | goto binary; |
| 72088 | } |
| 72089 | case DUK_TOK_SEQ: { |
| 72090 | args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY; |
| 72091 | goto binary; |
| 72092 | } |
| 72093 | case DUK_TOK_SNEQ: { |
| 72094 | args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY; |
| 72095 | goto binary; |
| 72096 | } |
| 72097 | |
| 72098 | /* BITWISE EXPRESSIONS */ |
| 72099 | |
| 72100 | case DUK_TOK_BAND: { |
| 72101 | args = (DUK_OP_BAND << 8) + DUK__BP_BAND; |
| 72102 | goto binary; |
| 72103 | } |
| 72104 | case DUK_TOK_BXOR: { |
| 72105 | args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR; |
| 72106 | goto binary; |
| 72107 | } |
| 72108 | case DUK_TOK_BOR: { |
| 72109 | args = (DUK_OP_BOR << 8) + DUK__BP_BOR; |
| 72110 | goto binary; |
| 72111 | } |
| 72112 | |
| 72113 | /* LOGICAL EXPRESSIONS */ |
| 72114 | |
| 72115 | case DUK_TOK_LAND: { |
| 72116 | /* syntactically left-associative but parsed as right-associative */ |
| 72117 | args = (1 << 8) + DUK__BP_LAND - 1; |
| 72118 | goto binary_logical; |
| 72119 | } |
| 72120 | case DUK_TOK_LOR: { |
| 72121 | /* syntactically left-associative but parsed as right-associative */ |
| 72122 | args = (0 << 8) + DUK__BP_LOR - 1; |
| 72123 | goto binary_logical; |
| 72124 | } |
| 72125 | |
| 72126 | /* CONDITIONAL EXPRESSION */ |
| 72127 | |
| 72128 | case DUK_TOK_QUESTION: { |
| 72129 | /* XXX: common reg allocation need is to reuse a sub-expression's temp reg, |
| 72130 | * but only if it really is a temp. Nothing fancy here now. |
| 72131 | */ |
| 72132 | duk_regconst_t reg_temp; |
| 72133 | duk_int_t pc_jump1; |
| 72134 | duk_int_t pc_jump2; |
| 72135 | |
| 72136 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 72137 | duk__ivalue_toforcedreg(comp_ctx, left, reg_temp); |
| 72138 | duk__emit_if_true_skip(comp_ctx, reg_temp); |
| 72139 | pc_jump1 = duk__emit_jump_empty(comp_ctx); /* jump to false */ |
| 72140 | duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */ |
| 72141 | duk__advance_expect(comp_ctx, DUK_TOK_COLON); |
| 72142 | pc_jump2 = duk__emit_jump_empty(comp_ctx); /* jump to end */ |
| 72143 | duk__patch_jump_here(comp_ctx, pc_jump1); |
| 72144 | duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */ |
| 72145 | duk__patch_jump_here(comp_ctx, pc_jump2); |
| 72146 | |
| 72147 | DUK__SETTEMP(comp_ctx, reg_temp + 1); |
| 72148 | duk__ivalue_regconst(res, reg_temp); |
| 72149 | return; |
| 72150 | } |
| 72151 | |
| 72152 | /* ASSIGNMENT EXPRESSION */ |
| 72153 | |
| 72154 | case DUK_TOK_EQUALSIGN: { |
| 72155 | /* |
| 72156 | * Assignments are right associative, allows e.g. |
| 72157 | * a = 5; |
| 72158 | * a += b = 9; // same as a += (b = 9) |
| 72159 | * -> expression value 14, a = 14, b = 9 |
| 72160 | * |
| 72161 | * Right associativiness is reflected in the BP for recursion, |
| 72162 | * "-1" ensures assignment operations are allowed. |
| 72163 | * |
| 72164 | * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)? |
| 72165 | */ |
| 72166 | args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */ |
| 72167 | goto assign; |
| 72168 | } |
| 72169 | case DUK_TOK_ADD_EQ: { |
| 72170 | /* right associative */ |
| 72171 | args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72172 | goto assign; |
| 72173 | } |
| 72174 | case DUK_TOK_SUB_EQ: { |
| 72175 | /* right associative */ |
| 72176 | args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72177 | goto assign; |
| 72178 | } |
| 72179 | case DUK_TOK_MUL_EQ: { |
| 72180 | /* right associative */ |
| 72181 | args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72182 | goto assign; |
| 72183 | } |
| 72184 | case DUK_TOK_DIV_EQ: { |
| 72185 | /* right associative */ |
| 72186 | args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72187 | goto assign; |
| 72188 | } |
| 72189 | case DUK_TOK_MOD_EQ: { |
| 72190 | /* right associative */ |
| 72191 | args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72192 | goto assign; |
| 72193 | } |
| 72194 | #if defined(DUK_USE_ES7_EXP_OPERATOR) |
| 72195 | case DUK_TOK_EXP_EQ: { |
| 72196 | /* right associative */ |
| 72197 | args = (DUK_OP_EXP << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72198 | goto assign; |
| 72199 | } |
| 72200 | #endif |
| 72201 | case DUK_TOK_ALSHIFT_EQ: { |
| 72202 | /* right associative */ |
| 72203 | args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72204 | goto assign; |
| 72205 | } |
| 72206 | case DUK_TOK_ARSHIFT_EQ: { |
| 72207 | /* right associative */ |
| 72208 | args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72209 | goto assign; |
| 72210 | } |
| 72211 | case DUK_TOK_RSHIFT_EQ: { |
| 72212 | /* right associative */ |
| 72213 | args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72214 | goto assign; |
| 72215 | } |
| 72216 | case DUK_TOK_BAND_EQ: { |
| 72217 | /* right associative */ |
| 72218 | args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72219 | goto assign; |
| 72220 | } |
| 72221 | case DUK_TOK_BOR_EQ: { |
| 72222 | /* right associative */ |
| 72223 | args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72224 | goto assign; |
| 72225 | } |
| 72226 | case DUK_TOK_BXOR_EQ: { |
| 72227 | /* right associative */ |
| 72228 | args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1; |
| 72229 | goto assign; |
| 72230 | } |
| 72231 | |
| 72232 | /* COMMA */ |
| 72233 | |
| 72234 | case DUK_TOK_COMMA: { |
| 72235 | /* right associative */ |
| 72236 | |
| 72237 | duk__ivalue_toplain_ignore(comp_ctx, left); /* need side effects, not value */ |
| 72238 | duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/); |
| 72239 | |
| 72240 | /* return 'res' (of right part) as our result */ |
| 72241 | return; |
| 72242 | } |
| 72243 | |
| 72244 | default: { |
| 72245 | break; |
| 72246 | } |
| 72247 | } |
| 72248 | |
| 72249 | DUK_D(DUK_DPRINT("parse error: unexpected token: %ld" , (long) tok)); |
| 72250 | DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR); |
| 72251 | DUK_WO_NORETURN(return;); |
| 72252 | |
| 72253 | #if 0 |
| 72254 | /* XXX: shared handling for 'duk__expr_lhs'? */ |
| 72255 | if (comp_ctx->curr_func.paren_level == 0 && XXX) { |
| 72256 | comp_ctx->curr_func.duk__expr_lhs = 0; |
| 72257 | } |
| 72258 | #endif |
| 72259 | |
| 72260 | binary: |
| 72261 | /* |
| 72262 | * Shared handling of binary operations |
| 72263 | * |
| 72264 | * args = (opcode << 8) + rbp |
| 72265 | */ |
| 72266 | { |
| 72267 | duk__ivalue_toplain(comp_ctx, left); |
| 72268 | duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/); |
| 72269 | |
| 72270 | /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */ |
| 72271 | DUK_ASSERT(left->t == DUK_IVAL_PLAIN); |
| 72272 | DUK_ASSERT(res->t == DUK_IVAL_PLAIN); |
| 72273 | |
| 72274 | res->t = DUK_IVAL_ARITH; |
| 72275 | res->op = (args >> 8) & 0xff; |
| 72276 | |
| 72277 | res->x2.t = res->x1.t; |
| 72278 | res->x2.regconst = res->x1.regconst; |
| 72279 | duk_copy(thr, res->x1.valstack_idx, res->x2.valstack_idx); |
| 72280 | |
| 72281 | res->x1.t = left->x1.t; |
| 72282 | res->x1.regconst = left->x1.regconst; |
| 72283 | duk_copy(thr, left->x1.valstack_idx, res->x1.valstack_idx); |
| 72284 | |
| 72285 | DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx" , |
| 72286 | (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst)); |
| 72287 | return; |
| 72288 | } |
| 72289 | |
| 72290 | binary_logical: |
| 72291 | /* |
| 72292 | * Shared handling for logical AND and logical OR. |
| 72293 | * |
| 72294 | * args = (truthval << 8) + rbp |
| 72295 | * |
| 72296 | * Truthval determines when to skip right-hand-side. |
| 72297 | * For logical AND truthval=1, for logical OR truthval=0. |
| 72298 | * |
| 72299 | * See doc/compiler.rst for discussion on compiling logical |
| 72300 | * AND and OR expressions. The approach here is very simplistic, |
| 72301 | * generating extra jumps and multiple evaluations of truth values, |
| 72302 | * but generates code on-the-fly with only local back-patching. |
| 72303 | * |
| 72304 | * Both logical AND and OR are syntactically left-associated. |
| 72305 | * However, logical ANDs are compiled as right associative |
| 72306 | * expressions, i.e. "A && B && C" as "A && (B && C)", to allow |
| 72307 | * skip jumps to skip over the entire tail. Similarly for logical OR. |
| 72308 | */ |
| 72309 | |
| 72310 | { |
| 72311 | duk_regconst_t reg_temp; |
| 72312 | duk_int_t pc_jump; |
| 72313 | duk_small_uint_t args_truthval = args >> 8; |
| 72314 | duk_small_uint_t args_rbp = args & 0xff; |
| 72315 | |
| 72316 | /* XXX: unoptimal use of temps, resetting */ |
| 72317 | |
| 72318 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 72319 | |
| 72320 | duk__ivalue_toforcedreg(comp_ctx, left, reg_temp); |
| 72321 | DUK_ASSERT(DUK__ISREG(reg_temp)); |
| 72322 | duk__emit_bc(comp_ctx, |
| 72323 | (args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R), |
| 72324 | reg_temp); /* skip jump conditionally */ |
| 72325 | pc_jump = duk__emit_jump_empty(comp_ctx); |
| 72326 | duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/); |
| 72327 | duk__patch_jump_here(comp_ctx, pc_jump); |
| 72328 | |
| 72329 | duk__ivalue_regconst(res, reg_temp); |
| 72330 | return; |
| 72331 | } |
| 72332 | |
| 72333 | assign: |
| 72334 | /* |
| 72335 | * Shared assignment expression handling |
| 72336 | * |
| 72337 | * args = (opcode << 8) + rbp |
| 72338 | * |
| 72339 | * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic. |
| 72340 | * Syntactically valid left-hand-side forms which are not accepted as |
| 72341 | * left-hand-side values (e.g. as in "f() = 1") must NOT cause a |
| 72342 | * SyntaxError, but rather a run-time ReferenceError. |
| 72343 | * |
| 72344 | * When evaluating X <op>= Y, the LHS (X) is conceptually evaluated |
| 72345 | * to a temporary first. The RHS is then evaluated. Finally, the |
| 72346 | * <op> is applied to the initial value of RHS (not the value after |
| 72347 | * RHS evaluation), and written to X. Doing so concretely generates |
| 72348 | * inefficient code so we'd like to avoid the temporary when possible. |
| 72349 | * See: https://github.com/svaarala/duktape/pull/992. |
| 72350 | * |
| 72351 | * The expression value (final LHS value, written to RHS) is |
| 72352 | * conceptually copied into a fresh temporary so that it won't |
| 72353 | * change even if the LHS/RHS values change in outer expressions. |
| 72354 | * For example, it'd be generally incorrect for the expression value |
| 72355 | * to be the RHS register binding, unless there's a guarantee that it |
| 72356 | * won't change during further expression evaluation. Using the |
| 72357 | * temporary concretely produces inefficient bytecode, so we try to |
| 72358 | * avoid the extra temporary for some known-to-be-safe cases. |
| 72359 | * Currently the only safe case we detect is a "top level assignment", |
| 72360 | * for example "x = y + z;", where the assignment expression value is |
| 72361 | * ignored. |
| 72362 | * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js. |
| 72363 | */ |
| 72364 | |
| 72365 | { |
| 72366 | duk_small_uint_t args_op = args >> 8; |
| 72367 | duk_small_uint_t args_rbp = args & 0xff; |
| 72368 | duk_bool_t toplevel_assign; |
| 72369 | |
| 72370 | /* XXX: here we need to know if 'left' is left-hand-side compatible. |
| 72371 | * That information is no longer available from current expr parsing |
| 72372 | * state; it would need to be carried into the 'left' ivalue or by |
| 72373 | * some other means. |
| 72374 | */ |
| 72375 | |
| 72376 | /* A top-level assignment is e.g. "x = y;". For these it's safe |
| 72377 | * to use the RHS as-is as the expression value, even if the RHS |
| 72378 | * is a reg-bound identifier. The RHS ('res') is right associative |
| 72379 | * so it has consumed all other assignment level operations; the |
| 72380 | * only relevant lower binding power construct is comma operator |
| 72381 | * which will ignore the expression value provided here. Usually |
| 72382 | * the top level assignment expression value is ignored, but it |
| 72383 | * is relevant for e.g. eval code. |
| 72384 | */ |
| 72385 | toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */ |
| 72386 | comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */ |
| 72387 | DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld" , |
| 72388 | (long) comp_ctx->curr_func.nud_count, |
| 72389 | (long) comp_ctx->curr_func.led_count, |
| 72390 | (long) toplevel_assign)); |
| 72391 | |
| 72392 | if (left->t == DUK_IVAL_VAR) { |
| 72393 | duk_hstring *h_varname; |
| 72394 | duk_regconst_t reg_varbind; |
| 72395 | duk_regconst_t rc_varname; |
| 72396 | |
| 72397 | DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */ |
| 72398 | |
| 72399 | h_varname = duk_known_hstring(thr, left->x1.valstack_idx); |
| 72400 | if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { |
| 72401 | /* E5 Section 11.13.1 (and others for other assignments), step 4. */ |
| 72402 | goto syntax_error_lvalue; |
| 72403 | } |
| 72404 | duk_dup(thr, left->x1.valstack_idx); |
| 72405 | (void) duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname); |
| 72406 | |
| 72407 | if (args_op == DUK_OP_NONE) { |
| 72408 | duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/); |
| 72409 | if (toplevel_assign) { |
| 72410 | /* Any 'res' will do. */ |
| 72411 | DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is" )); |
| 72412 | } else { |
| 72413 | /* 'res' must be a plain ivalue, and not register-bound variable. */ |
| 72414 | DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier" )); |
| 72415 | if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST && |
| 72416 | DUK__ISREG_NOTTEMP(comp_ctx, res->x1.regconst))) { |
| 72417 | duk__ivalue_totempconst(comp_ctx, res); |
| 72418 | } |
| 72419 | } |
| 72420 | } else { |
| 72421 | /* For X <op>= Y we need to evaluate the pre-op |
| 72422 | * value of X before evaluating the RHS: the RHS |
| 72423 | * can change X, but when we do <op> we must use |
| 72424 | * the pre-op value. |
| 72425 | */ |
| 72426 | duk_regconst_t reg_temp; |
| 72427 | |
| 72428 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 72429 | |
| 72430 | if (reg_varbind >= 0) { |
| 72431 | duk_regconst_t reg_res; |
| 72432 | duk_regconst_t reg_src; |
| 72433 | duk_int_t pc_temp_load; |
| 72434 | duk_int_t pc_before_rhs; |
| 72435 | duk_int_t pc_after_rhs; |
| 72436 | |
| 72437 | if (toplevel_assign) { |
| 72438 | /* 'reg_varbind' is the operation result and can also |
| 72439 | * become the expression value for top level assignments |
| 72440 | * such as: "var x; x += y;". |
| 72441 | */ |
| 72442 | DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind" )); |
| 72443 | reg_res = reg_varbind; |
| 72444 | } else { |
| 72445 | /* Not safe to use 'reg_varbind' as assignment expression |
| 72446 | * value, so go through a temp. |
| 72447 | */ |
| 72448 | DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp" )); |
| 72449 | reg_res = reg_temp; /* reg_res should be smallest possible */ |
| 72450 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 72451 | } |
| 72452 | |
| 72453 | /* Try to optimize X <op>= Y for reg-bound |
| 72454 | * variables. Detect side-effect free RHS |
| 72455 | * narrowly by seeing whether it emits code. |
| 72456 | * If not, rewind the code emitter and overwrite |
| 72457 | * the unnecessary temp reg load. |
| 72458 | */ |
| 72459 | |
| 72460 | pc_temp_load = duk__get_current_pc(comp_ctx); |
| 72461 | duk__emit_a_bc(comp_ctx, |
| 72462 | DUK_OP_LDREG, |
| 72463 | reg_temp, |
| 72464 | reg_varbind); |
| 72465 | |
| 72466 | pc_before_rhs = duk__get_current_pc(comp_ctx); |
| 72467 | duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); |
| 72468 | DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); |
| 72469 | pc_after_rhs = duk__get_current_pc(comp_ctx); |
| 72470 | |
| 72471 | DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld" , |
| 72472 | (long) pc_temp_load, (long) pc_before_rhs, |
| 72473 | (long) pc_after_rhs)); |
| 72474 | |
| 72475 | if (pc_after_rhs == pc_before_rhs) { |
| 72476 | /* Note: if the reg_temp load generated shuffling |
| 72477 | * instructions, we may need to rewind more than |
| 72478 | * one instruction, so use explicit PC computation. |
| 72479 | */ |
| 72480 | DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>=" )); |
| 72481 | DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * (duk_int_t) sizeof(duk_compiler_instr)); |
| 72482 | reg_src = reg_varbind; |
| 72483 | } else { |
| 72484 | DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS" )); |
| 72485 | reg_src = reg_temp; |
| 72486 | } |
| 72487 | |
| 72488 | duk__emit_a_b_c(comp_ctx, |
| 72489 | args_op | DUK__EMIT_FLAG_BC_REGCONST, |
| 72490 | reg_res, |
| 72491 | reg_src, |
| 72492 | res->x1.regconst); |
| 72493 | |
| 72494 | res->x1.regconst = reg_res; |
| 72495 | |
| 72496 | /* Ensure compact use of temps. */ |
| 72497 | if (DUK__ISREG_TEMP(comp_ctx, reg_res)) { |
| 72498 | DUK__SETTEMP(comp_ctx, reg_res + 1); |
| 72499 | } |
| 72500 | } else { |
| 72501 | /* When LHS is not register bound, always go through a |
| 72502 | * temporary. No optimization for top level assignment. |
| 72503 | */ |
| 72504 | |
| 72505 | duk__emit_a_bc(comp_ctx, |
| 72506 | DUK_OP_GETVAR, |
| 72507 | reg_temp, |
| 72508 | rc_varname); |
| 72509 | |
| 72510 | duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); |
| 72511 | DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); |
| 72512 | |
| 72513 | duk__emit_a_b_c(comp_ctx, |
| 72514 | args_op | DUK__EMIT_FLAG_BC_REGCONST, |
| 72515 | reg_temp, |
| 72516 | reg_temp, |
| 72517 | res->x1.regconst); |
| 72518 | res->x1.regconst = reg_temp; |
| 72519 | } |
| 72520 | |
| 72521 | DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); |
| 72522 | } |
| 72523 | |
| 72524 | /* At this point 'res' holds the potential expression value. |
| 72525 | * It can be basically any ivalue here, including a reg-bound |
| 72526 | * identifier (if code above deems it safe) or a unary/binary |
| 72527 | * operation. Operations must be resolved to a side effect free |
| 72528 | * plain value, and the side effects must happen exactly once. |
| 72529 | */ |
| 72530 | |
| 72531 | if (reg_varbind >= 0) { |
| 72532 | if (res->t != DUK_IVAL_PLAIN) { |
| 72533 | /* Resolve 'res' directly into the LHS binding, and use |
| 72534 | * that as the expression value if safe. If not safe, |
| 72535 | * resolve to a temp/const and copy to LHS. |
| 72536 | */ |
| 72537 | if (toplevel_assign) { |
| 72538 | duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind); |
| 72539 | } else { |
| 72540 | duk__ivalue_totempconst(comp_ctx, res); |
| 72541 | duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */ |
| 72542 | duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind); |
| 72543 | } |
| 72544 | } else { |
| 72545 | /* Use 'res' as the expression value (it's side effect |
| 72546 | * free and may be a plain value, a register, or a |
| 72547 | * constant) and write it to the LHS binding too. |
| 72548 | */ |
| 72549 | duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */ |
| 72550 | duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind); |
| 72551 | } |
| 72552 | } else { |
| 72553 | /* Only a reg fits into 'A' so coerce 'res' into a register |
| 72554 | * for PUTVAR. |
| 72555 | * |
| 72556 | * XXX: here the current A/B/C split is suboptimal: we could |
| 72557 | * just use 9 bits for reg_res (and support constants) and 17 |
| 72558 | * instead of 18 bits for the varname const index. |
| 72559 | */ |
| 72560 | |
| 72561 | duk__ivalue_toreg(comp_ctx, res); |
| 72562 | duk__emit_a_bc(comp_ctx, |
| 72563 | DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 72564 | res->x1.regconst, |
| 72565 | rc_varname); |
| 72566 | } |
| 72567 | |
| 72568 | /* 'res' contains expression value */ |
| 72569 | } else if (left->t == DUK_IVAL_PROP) { |
| 72570 | /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */ |
| 72571 | duk_regconst_t reg_obj; |
| 72572 | duk_regconst_t rc_key; |
| 72573 | duk_regconst_t rc_res; |
| 72574 | duk_regconst_t reg_temp; |
| 72575 | |
| 72576 | /* Property access expressions ('a[b]') are critical to correct |
| 72577 | * LHS evaluation ordering, see test-dev-assign-eval-order*.js. |
| 72578 | * We must make sure that the LHS target slot (base object and |
| 72579 | * key) don't change during RHS evaluation. The only concrete |
| 72580 | * problem is a register reference to a variable-bound register |
| 72581 | * (i.e., non-temp). Require temp regs for both key and base. |
| 72582 | * |
| 72583 | * Don't allow a constant for the object (even for a number |
| 72584 | * etc), as it goes into the 'A' field of the opcode. |
| 72585 | */ |
| 72586 | |
| 72587 | reg_obj = duk__ispec_toregconst_raw(comp_ctx, |
| 72588 | &left->x1, |
| 72589 | -1 /*forced_reg*/, |
| 72590 | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/); |
| 72591 | |
| 72592 | rc_key = duk__ispec_toregconst_raw(comp_ctx, |
| 72593 | &left->x2, |
| 72594 | -1 /*forced_reg*/, |
| 72595 | DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); |
| 72596 | |
| 72597 | /* Evaluate RHS only when LHS is safe. */ |
| 72598 | |
| 72599 | if (args_op == DUK_OP_NONE) { |
| 72600 | duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); |
| 72601 | DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); |
| 72602 | rc_res = res->x1.regconst; |
| 72603 | } else { |
| 72604 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 72605 | duk__emit_a_b_c(comp_ctx, |
| 72606 | DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST, |
| 72607 | reg_temp, |
| 72608 | reg_obj, |
| 72609 | rc_key); |
| 72610 | |
| 72611 | duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); |
| 72612 | DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST); |
| 72613 | |
| 72614 | duk__emit_a_b_c(comp_ctx, |
| 72615 | args_op | DUK__EMIT_FLAG_BC_REGCONST, |
| 72616 | reg_temp, |
| 72617 | reg_temp, |
| 72618 | res->x1.regconst); |
| 72619 | rc_res = reg_temp; |
| 72620 | } |
| 72621 | |
| 72622 | duk__emit_a_b_c(comp_ctx, |
| 72623 | DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST, |
| 72624 | reg_obj, |
| 72625 | rc_key, |
| 72626 | rc_res); |
| 72627 | |
| 72628 | duk__ivalue_regconst(res, rc_res); |
| 72629 | } else { |
| 72630 | /* No support for lvalues returned from new or function call expressions. |
| 72631 | * However, these must NOT cause compile-time SyntaxErrors, but run-time |
| 72632 | * ReferenceErrors. Both left and right sides of the assignment must be |
| 72633 | * evaluated before throwing a ReferenceError. For instance: |
| 72634 | * |
| 72635 | * f() = g(); |
| 72636 | * |
| 72637 | * must result in f() being evaluated, then g() being evaluated, and |
| 72638 | * finally, a ReferenceError being thrown. See E5 Section 11.13.1. |
| 72639 | */ |
| 72640 | |
| 72641 | duk_regconst_t rc_res; |
| 72642 | |
| 72643 | /* First evaluate LHS fully to ensure all side effects are out. */ |
| 72644 | duk__ivalue_toplain_ignore(comp_ctx, left); |
| 72645 | |
| 72646 | /* Then evaluate RHS fully (its value becomes the expression value too). |
| 72647 | * Technically we'd need the side effect safety check here too, but because |
| 72648 | * we always throw using INVLHS the result doesn't matter. |
| 72649 | */ |
| 72650 | rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/); |
| 72651 | |
| 72652 | duk__emit_op_only(comp_ctx, DUK_OP_INVLHS); |
| 72653 | |
| 72654 | duk__ivalue_regconst(res, rc_res); |
| 72655 | } |
| 72656 | |
| 72657 | return; |
| 72658 | } |
| 72659 | |
| 72660 | postincdec: |
| 72661 | { |
| 72662 | /* |
| 72663 | * Post-increment/decrement will return the original value as its |
| 72664 | * result value. However, even that value will be coerced using |
| 72665 | * ToNumber() which is quite awkward. Specific bytecode opcodes |
| 72666 | * are used to handle these semantics. |
| 72667 | * |
| 72668 | * Note that post increment/decrement has a "no LineTerminator here" |
| 72669 | * restriction. This is handled by duk__expr_lbp(), which forcibly terminates |
| 72670 | * the previous expression if a LineTerminator occurs before '++'/'--'. |
| 72671 | */ |
| 72672 | |
| 72673 | duk_regconst_t reg_res; |
| 72674 | duk_small_uint_t args_op1 = (args >> 8) & 0xff; /* DUK_OP_POSTINCR/DUK_OP_POSTDECR */ |
| 72675 | duk_small_uint_t args_op2 = args >> 16; /* DUK_OP_POSTINCP_RR/DUK_OP_POSTDECP_RR */ |
| 72676 | |
| 72677 | /* Specific assumptions for opcode numbering. */ |
| 72678 | DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV); |
| 72679 | DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV); |
| 72680 | |
| 72681 | reg_res = DUK__ALLOCTEMP(comp_ctx); |
| 72682 | |
| 72683 | if (left->t == DUK_IVAL_VAR) { |
| 72684 | duk_hstring *h_varname; |
| 72685 | duk_regconst_t reg_varbind; |
| 72686 | duk_regconst_t rc_varname; |
| 72687 | |
| 72688 | h_varname = duk_known_hstring(thr, left->x1.valstack_idx); |
| 72689 | |
| 72690 | if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { |
| 72691 | goto syntax_error; |
| 72692 | } |
| 72693 | |
| 72694 | duk_dup(thr, left->x1.valstack_idx); |
| 72695 | if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { |
| 72696 | duk__emit_a_bc(comp_ctx, |
| 72697 | args_op1, /* e.g. DUK_OP_POSTINCR */ |
| 72698 | reg_res, |
| 72699 | reg_varbind); |
| 72700 | } else { |
| 72701 | duk__emit_a_bc(comp_ctx, |
| 72702 | args_op1 + 4, /* e.g. DUK_OP_POSTINCV */ |
| 72703 | reg_res, |
| 72704 | rc_varname); |
| 72705 | } |
| 72706 | |
| 72707 | DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld" , |
| 72708 | (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname)); |
| 72709 | } else if (left->t == DUK_IVAL_PROP) { |
| 72710 | duk_regconst_t reg_obj; /* allocate to reg only (not const) */ |
| 72711 | duk_regconst_t rc_key; |
| 72712 | |
| 72713 | reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ |
| 72714 | rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); |
| 72715 | duk__emit_a_b_c(comp_ctx, |
| 72716 | args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_POSTINCP */ |
| 72717 | reg_res, |
| 72718 | reg_obj, |
| 72719 | rc_key); |
| 72720 | } else { |
| 72721 | /* Technically return value is not needed because INVLHS will |
| 72722 | * unconditially throw a ReferenceError. Coercion is necessary |
| 72723 | * for proper semantics (consider ToNumber() called for an object). |
| 72724 | * Use DUK_OP_UNP with a dummy register to get ToNumber(). |
| 72725 | */ |
| 72726 | duk__ivalue_toforcedreg(comp_ctx, left, reg_res); |
| 72727 | duk__emit_bc(comp_ctx, |
| 72728 | DUK_OP_UNP, |
| 72729 | reg_res); /* for side effects, result ignored */ |
| 72730 | duk__emit_op_only(comp_ctx, |
| 72731 | DUK_OP_INVLHS); |
| 72732 | } |
| 72733 | |
| 72734 | DUK__SETTEMP(comp_ctx, reg_res + 1); |
| 72735 | duk__ivalue_regconst(res, reg_res); |
| 72736 | return; |
| 72737 | } |
| 72738 | |
| 72739 | syntax_error: |
| 72740 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION); |
| 72741 | DUK_WO_NORETURN(return;); |
| 72742 | |
| 72743 | syntax_error_lvalue: |
| 72744 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE); |
| 72745 | DUK_WO_NORETURN(return;); |
| 72746 | } |
| 72747 | |
| 72748 | DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) { |
| 72749 | duk_small_uint_t tok = comp_ctx->curr_token.t; |
| 72750 | |
| 72751 | DUK_ASSERT_DISABLE(tok >= DUK_TOK_MINVAL); /* unsigned */ |
| 72752 | DUK_ASSERT(tok <= DUK_TOK_MAXVAL); |
| 72753 | DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1); |
| 72754 | |
| 72755 | /* XXX: integrate support for this into led() instead? |
| 72756 | * Similar issue as post-increment/post-decrement. |
| 72757 | */ |
| 72758 | |
| 72759 | /* prevent duk__expr_led() by using a binding power less than anything valid */ |
| 72760 | if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) { |
| 72761 | return 0; |
| 72762 | } |
| 72763 | |
| 72764 | if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) && |
| 72765 | (comp_ctx->curr_token.lineterm)) { |
| 72766 | /* '++' or '--' in a post-increment/decrement position, |
| 72767 | * and a LineTerminator occurs between the operator and |
| 72768 | * the preceding expression. Force the previous expr |
| 72769 | * to terminate, in effect treating e.g. "a,b\n++" as |
| 72770 | * "a,b;++" (= SyntaxError). |
| 72771 | */ |
| 72772 | return 0; |
| 72773 | } |
| 72774 | |
| 72775 | return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */ |
| 72776 | } |
| 72777 | |
| 72778 | /* |
| 72779 | * Expression parsing. |
| 72780 | * |
| 72781 | * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the |
| 72782 | * first token of the expression. Upon exit, 'curr_tok' will be the first |
| 72783 | * token not part of the expression (e.g. semicolon terminating an expression |
| 72784 | * statement). |
| 72785 | */ |
| 72786 | |
| 72787 | #define DUK__EXPR_RBP_MASK 0xff |
| 72788 | #define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */ |
| 72789 | #define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */ |
| 72790 | #define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */ |
| 72791 | |
| 72792 | /* main expression parser function */ |
| 72793 | DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72794 | duk_hthread *thr = comp_ctx->thr; |
| 72795 | duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */ |
| 72796 | duk_ivalue *tmp = &tmp_alloc; |
| 72797 | duk_small_uint_t rbp; |
| 72798 | |
| 72799 | DUK__RECURSION_INCREASE(comp_ctx, thr); |
| 72800 | |
| 72801 | duk_require_stack(thr, DUK__PARSE_EXPR_SLOTS); |
| 72802 | |
| 72803 | /* filter out flags from exprtop rbp_flags here to save space */ |
| 72804 | rbp = rbp_flags & DUK__EXPR_RBP_MASK; |
| 72805 | |
| 72806 | DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld" , |
| 72807 | (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in, |
| 72808 | (long) comp_ctx->curr_func.paren_level)); |
| 72809 | |
| 72810 | duk_memzero(&tmp_alloc, sizeof(tmp_alloc)); |
| 72811 | tmp->x1.valstack_idx = duk_get_top(thr); |
| 72812 | tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1; |
| 72813 | duk_push_undefined(thr); |
| 72814 | duk_push_undefined(thr); |
| 72815 | |
| 72816 | /* XXX: where to release temp regs in intermediate expressions? |
| 72817 | * e.g. 1+2+3 -> don't inflate temp register count when parsing this. |
| 72818 | * that particular expression temp regs can be forced here. |
| 72819 | */ |
| 72820 | |
| 72821 | /* XXX: increase ctx->expr_tokens here for every consumed token |
| 72822 | * (this would be a nice statistic)? |
| 72823 | */ |
| 72824 | |
| 72825 | if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) { |
| 72826 | /* XXX: possibly incorrect handling of empty expression */ |
| 72827 | DUK_DDD(DUK_DDDPRINT("empty expression" )); |
| 72828 | if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) { |
| 72829 | DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED); |
| 72830 | DUK_WO_NORETURN(return;); |
| 72831 | } |
| 72832 | duk_push_undefined(thr); |
| 72833 | duk__ivalue_plain_fromstack(comp_ctx, res); |
| 72834 | goto cleanup; |
| 72835 | } |
| 72836 | |
| 72837 | duk__advance(comp_ctx); |
| 72838 | duk__expr_nud(comp_ctx, res); /* reuse 'res' as 'left' */ |
| 72839 | while (rbp < duk__expr_lbp(comp_ctx)) { |
| 72840 | duk__advance(comp_ctx); |
| 72841 | duk__expr_led(comp_ctx, res, tmp); |
| 72842 | duk__copy_ivalue(comp_ctx, tmp, res); /* tmp -> res */ |
| 72843 | } |
| 72844 | |
| 72845 | cleanup: |
| 72846 | /* final result is already in 'res' */ |
| 72847 | |
| 72848 | duk_pop_2(thr); |
| 72849 | |
| 72850 | DUK__RECURSION_DECREASE(comp_ctx, thr); |
| 72851 | } |
| 72852 | |
| 72853 | DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72854 | duk_hthread *thr = comp_ctx->thr; |
| 72855 | |
| 72856 | /* Note: these variables must reside in 'curr_func' instead of the global |
| 72857 | * context: when parsing function expressions, expression parsing is nested. |
| 72858 | */ |
| 72859 | comp_ctx->curr_func.nud_count = 0; |
| 72860 | comp_ctx->curr_func.led_count = 0; |
| 72861 | comp_ctx->curr_func.paren_level = 0; |
| 72862 | comp_ctx->curr_func.expr_lhs = 1; |
| 72863 | comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1); |
| 72864 | |
| 72865 | duk__expr(comp_ctx, res, rbp_flags); |
| 72866 | |
| 72867 | if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) { |
| 72868 | DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED); |
| 72869 | DUK_WO_NORETURN(return;); |
| 72870 | } |
| 72871 | } |
| 72872 | |
| 72873 | /* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop() |
| 72874 | * and result conversions. |
| 72875 | * |
| 72876 | * Each helper needs at least 2-3 calls to make it worth while to wrap. |
| 72877 | */ |
| 72878 | |
| 72879 | #if 0 /* unused */ |
| 72880 | DUK_LOCAL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72881 | duk__expr(comp_ctx, res, rbp_flags); |
| 72882 | return duk__ivalue_toreg(comp_ctx, res); |
| 72883 | } |
| 72884 | #endif |
| 72885 | |
| 72886 | #if 0 /* unused */ |
| 72887 | DUK_LOCAL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72888 | duk__expr(comp_ctx, res, rbp_flags); |
| 72889 | return duk__ivalue_totemp(comp_ctx, res); |
| 72890 | } |
| 72891 | #endif |
| 72892 | |
| 72893 | DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) { |
| 72894 | DUK_ASSERT(forced_reg >= 0); |
| 72895 | duk__expr(comp_ctx, res, rbp_flags); |
| 72896 | duk__ivalue_toforcedreg(comp_ctx, res, forced_reg); |
| 72897 | } |
| 72898 | |
| 72899 | DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72900 | duk__expr(comp_ctx, res, rbp_flags); |
| 72901 | return duk__ivalue_toregconst(comp_ctx, res); |
| 72902 | } |
| 72903 | |
| 72904 | #if 0 /* unused */ |
| 72905 | DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72906 | duk__expr(comp_ctx, res, rbp_flags); |
| 72907 | return duk__ivalue_totempconst(comp_ctx, res); |
| 72908 | } |
| 72909 | #endif |
| 72910 | |
| 72911 | DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72912 | duk__expr(comp_ctx, res, rbp_flags); |
| 72913 | duk__ivalue_toplain(comp_ctx, res); |
| 72914 | } |
| 72915 | |
| 72916 | DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72917 | duk__expr(comp_ctx, res, rbp_flags); |
| 72918 | duk__ivalue_toplain_ignore(comp_ctx, res); |
| 72919 | } |
| 72920 | |
| 72921 | DUK_LOCAL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72922 | duk__exprtop(comp_ctx, res, rbp_flags); |
| 72923 | return duk__ivalue_toreg(comp_ctx, res); |
| 72924 | } |
| 72925 | |
| 72926 | #if 0 /* unused */ |
| 72927 | DUK_LOCAL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72928 | duk__exprtop(comp_ctx, res, rbp_flags); |
| 72929 | return duk__ivalue_totemp(comp_ctx, res); |
| 72930 | } |
| 72931 | #endif |
| 72932 | |
| 72933 | DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) { |
| 72934 | DUK_ASSERT(forced_reg >= 0); |
| 72935 | duk__exprtop(comp_ctx, res, rbp_flags); |
| 72936 | duk__ivalue_toforcedreg(comp_ctx, res, forced_reg); |
| 72937 | } |
| 72938 | |
| 72939 | DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) { |
| 72940 | duk__exprtop(comp_ctx, res, rbp_flags); |
| 72941 | return duk__ivalue_toregconst(comp_ctx, res); |
| 72942 | } |
| 72943 | |
| 72944 | #if 0 /* unused */ |
| 72945 | DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) { |
| 72946 | duk__exprtop(comp_ctx, res, rbp_flags); |
| 72947 | duk__ivalue_toplain_ignore(comp_ctx, res); |
| 72948 | } |
| 72949 | #endif |
| 72950 | |
| 72951 | /* |
| 72952 | * Parse an individual source element (top level statement) or a statement. |
| 72953 | * |
| 72954 | * Handles labeled statements automatically (peeling away labels before |
| 72955 | * parsing an expression that follows the label(s)). |
| 72956 | * |
| 72957 | * Upon entry, 'curr_tok' contains the first token of the statement (parsed |
| 72958 | * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first |
| 72959 | * token following the statement (if the statement has a terminator, this is |
| 72960 | * the token after the terminator). |
| 72961 | */ |
| 72962 | |
| 72963 | #define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */ |
| 72964 | #define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */ |
| 72965 | #define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */ |
| 72966 | #define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */ |
| 72967 | #define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */ |
| 72968 | |
| 72969 | /* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var' |
| 72970 | * has already been eaten. These is no return value in 'res', it is used only |
| 72971 | * as a temporary. |
| 72972 | * |
| 72973 | * When called from 'for-in' statement parser, the initializer expression must |
| 72974 | * not allow the 'in' token. The caller supply additional expression parsing |
| 72975 | * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'. |
| 72976 | * |
| 72977 | * Finally, out_rc_varname and out_reg_varbind are updated to reflect where |
| 72978 | * the identifier is bound: |
| 72979 | * |
| 72980 | * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore) |
| 72981 | * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0 |
| 72982 | * |
| 72983 | * These allow the caller to use the variable for further assignment, e.g. |
| 72984 | * as is done in 'for-in' parsing. |
| 72985 | */ |
| 72986 | |
| 72987 | DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) { |
| 72988 | duk_hthread *thr = comp_ctx->thr; |
| 72989 | duk_hstring *h_varname; |
| 72990 | duk_regconst_t reg_varbind; |
| 72991 | duk_regconst_t rc_varname; |
| 72992 | |
| 72993 | /* assume 'var' has been eaten */ |
| 72994 | |
| 72995 | /* Note: Identifier rejects reserved words */ |
| 72996 | if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) { |
| 72997 | goto syntax_error; |
| 72998 | } |
| 72999 | h_varname = comp_ctx->curr_token.str1; |
| 73000 | |
| 73001 | DUK_ASSERT(h_varname != NULL); |
| 73002 | |
| 73003 | /* strict mode restrictions (E5 Section 12.2.1) */ |
| 73004 | if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) { |
| 73005 | goto syntax_error; |
| 73006 | } |
| 73007 | |
| 73008 | /* register declarations in first pass */ |
| 73009 | if (comp_ctx->curr_func.in_scanning) { |
| 73010 | duk_uarridx_t n; |
| 73011 | DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1" , |
| 73012 | (duk_heaphdr *) h_varname)); |
| 73013 | n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx); |
| 73014 | duk_push_hstring(thr, h_varname); |
| 73015 | duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n); |
| 73016 | duk_push_int(thr, DUK_DECL_TYPE_VAR + (0 << 8)); |
| 73017 | duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1); |
| 73018 | } |
| 73019 | |
| 73020 | duk_push_hstring(thr, h_varname); /* push before advancing to keep reachable */ |
| 73021 | |
| 73022 | /* register binding lookup is based on varmap (even in first pass) */ |
| 73023 | duk_dup_top(thr); |
| 73024 | (void) duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname); |
| 73025 | |
| 73026 | duk__advance(comp_ctx); /* eat identifier */ |
| 73027 | |
| 73028 | if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) { |
| 73029 | duk__advance(comp_ctx); |
| 73030 | |
| 73031 | DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld" , |
| 73032 | (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname)); |
| 73033 | |
| 73034 | duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */ |
| 73035 | |
| 73036 | if (reg_varbind >= 0) { |
| 73037 | duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind); |
| 73038 | } else { |
| 73039 | duk_regconst_t reg_val; |
| 73040 | reg_val = duk__ivalue_toreg(comp_ctx, res); |
| 73041 | duk__emit_a_bc(comp_ctx, |
| 73042 | DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 73043 | reg_val, |
| 73044 | rc_varname); |
| 73045 | } |
| 73046 | } else { |
| 73047 | if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) { |
| 73048 | /* Used for minimal 'const': initializer required. */ |
| 73049 | goto syntax_error; |
| 73050 | } |
| 73051 | } |
| 73052 | |
| 73053 | duk_pop(thr); /* pop varname */ |
| 73054 | |
| 73055 | *out_rc_varname = rc_varname; |
| 73056 | *out_reg_varbind = reg_varbind; |
| 73057 | |
| 73058 | return; |
| 73059 | |
| 73060 | syntax_error: |
| 73061 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION); |
| 73062 | DUK_WO_NORETURN(return;); |
| 73063 | } |
| 73064 | |
| 73065 | DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) { |
| 73066 | duk_regconst_t reg_varbind; |
| 73067 | duk_regconst_t rc_varname; |
| 73068 | |
| 73069 | duk__advance(comp_ctx); /* eat 'var' */ |
| 73070 | |
| 73071 | for (;;) { |
| 73072 | /* rc_varname and reg_varbind are ignored here */ |
| 73073 | duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, ®_varbind, &rc_varname); |
| 73074 | |
| 73075 | if (comp_ctx->curr_token.t != DUK_TOK_COMMA) { |
| 73076 | break; |
| 73077 | } |
| 73078 | duk__advance(comp_ctx); |
| 73079 | } |
| 73080 | } |
| 73081 | |
| 73082 | DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { |
| 73083 | duk_hthread *thr = comp_ctx->thr; |
| 73084 | duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */ |
| 73085 | duk_regconst_t temp_reset; /* knock back "next temp" to this whenever possible */ |
| 73086 | duk_regconst_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */ |
| 73087 | |
| 73088 | DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement" )); |
| 73089 | |
| 73090 | /* Two temporaries are preallocated here for variants 3 and 4 which need |
| 73091 | * registers which are never clobbered by expressions in the loop |
| 73092 | * (concretely: for the enumerator object and the next enumerated value). |
| 73093 | * Variants 1 and 2 "release" these temps. |
| 73094 | */ |
| 73095 | |
| 73096 | reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2); |
| 73097 | |
| 73098 | temp_reset = DUK__GETTEMP(comp_ctx); |
| 73099 | |
| 73100 | /* |
| 73101 | * For/for-in main variants are: |
| 73102 | * |
| 73103 | * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement |
| 73104 | * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement |
| 73105 | * 3. for (LeftHandSideExpression in Expression) Statement |
| 73106 | * 4. for (var VariableDeclarationNoIn in Expression) Statement |
| 73107 | * |
| 73108 | * Parsing these without arbitrary lookahead or backtracking is relatively |
| 73109 | * tricky but we manage to do so for now. |
| 73110 | * |
| 73111 | * See doc/compiler.rst for a detailed discussion of control flow |
| 73112 | * issues, evaluation order issues, etc. |
| 73113 | */ |
| 73114 | |
| 73115 | duk__advance(comp_ctx); /* eat 'for' */ |
| 73116 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 73117 | |
| 73118 | DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld" , (long) duk__get_current_pc(comp_ctx))); |
| 73119 | |
| 73120 | /* a label site has been emitted by duk__parse_stmt() automatically |
| 73121 | * (it will also emit the ENDLABEL). |
| 73122 | */ |
| 73123 | |
| 73124 | if (comp_ctx->curr_token.t == DUK_TOK_VAR) { |
| 73125 | /* |
| 73126 | * Variant 2 or 4 |
| 73127 | */ |
| 73128 | |
| 73129 | duk_regconst_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */ |
| 73130 | duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */ |
| 73131 | |
| 73132 | duk__advance(comp_ctx); /* eat 'var' */ |
| 73133 | duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, ®_varbind, &rc_varname); |
| 73134 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73135 | |
| 73136 | if (comp_ctx->curr_token.t == DUK_TOK_IN) { |
| 73137 | /* |
| 73138 | * Variant 4 |
| 73139 | */ |
| 73140 | |
| 73141 | DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement" )); |
| 73142 | pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here */ |
| 73143 | if (reg_varbind >= 0) { |
| 73144 | duk__emit_a_bc(comp_ctx, |
| 73145 | DUK_OP_LDREG, |
| 73146 | reg_varbind, |
| 73147 | reg_temps + 0); |
| 73148 | } else { |
| 73149 | duk__emit_a_bc(comp_ctx, |
| 73150 | DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 73151 | reg_temps + 0, |
| 73152 | rc_varname); |
| 73153 | } |
| 73154 | goto parse_3_or_4; |
| 73155 | } else { |
| 73156 | /* |
| 73157 | * Variant 2 |
| 73158 | */ |
| 73159 | |
| 73160 | DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement" )); |
| 73161 | for (;;) { |
| 73162 | /* more initializers */ |
| 73163 | if (comp_ctx->curr_token.t != DUK_TOK_COMMA) { |
| 73164 | break; |
| 73165 | } |
| 73166 | DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer" )); |
| 73167 | |
| 73168 | duk__advance(comp_ctx); /* eat comma */ |
| 73169 | duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, ®_varbind, &rc_varname); |
| 73170 | } |
| 73171 | goto parse_1_or_2; |
| 73172 | } |
| 73173 | } else { |
| 73174 | /* |
| 73175 | * Variant 1 or 3 |
| 73176 | */ |
| 73177 | |
| 73178 | pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */ |
| 73179 | |
| 73180 | /* Note that duk__exprtop() here can clobber any reg above current temp_next, |
| 73181 | * so any loop variables (e.g. enumerator) must be "preallocated". |
| 73182 | */ |
| 73183 | |
| 73184 | /* don't coerce yet to a plain value (variant 3 needs special handling) */ |
| 73185 | duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression */ |
| 73186 | if (comp_ctx->curr_token.t == DUK_TOK_IN) { |
| 73187 | /* |
| 73188 | * Variant 3 |
| 73189 | */ |
| 73190 | |
| 73191 | /* XXX: need to determine LHS type, and check that it is LHS compatible */ |
| 73192 | DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement" )); |
| 73193 | if (duk__expr_is_empty(comp_ctx)) { |
| 73194 | goto syntax_error; /* LeftHandSideExpression does not allow empty expression */ |
| 73195 | } |
| 73196 | |
| 73197 | if (res->t == DUK_IVAL_VAR) { |
| 73198 | duk_regconst_t reg_varbind; |
| 73199 | duk_regconst_t rc_varname; |
| 73200 | |
| 73201 | duk_dup(thr, res->x1.valstack_idx); |
| 73202 | if (duk__lookup_lhs(comp_ctx, ®_varbind, &rc_varname)) { |
| 73203 | duk__emit_a_bc(comp_ctx, |
| 73204 | DUK_OP_LDREG, |
| 73205 | reg_varbind, |
| 73206 | reg_temps + 0); |
| 73207 | } else { |
| 73208 | duk__emit_a_bc(comp_ctx, |
| 73209 | DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 73210 | reg_temps + 0, |
| 73211 | rc_varname); |
| 73212 | } |
| 73213 | } else if (res->t == DUK_IVAL_PROP) { |
| 73214 | /* Don't allow a constant for the object (even for a number etc), as |
| 73215 | * it goes into the 'A' field of the opcode. |
| 73216 | */ |
| 73217 | duk_regconst_t reg_obj; |
| 73218 | duk_regconst_t rc_key; |
| 73219 | reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */ |
| 73220 | rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/); |
| 73221 | duk__emit_a_b_c(comp_ctx, |
| 73222 | DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST, |
| 73223 | reg_obj, |
| 73224 | rc_key, |
| 73225 | reg_temps + 0); |
| 73226 | } else { |
| 73227 | duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */ |
| 73228 | duk__emit_op_only(comp_ctx, |
| 73229 | DUK_OP_INVLHS); |
| 73230 | } |
| 73231 | goto parse_3_or_4; |
| 73232 | } else { |
| 73233 | /* |
| 73234 | * Variant 1 |
| 73235 | */ |
| 73236 | |
| 73237 | DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement" )); |
| 73238 | duk__ivalue_toplain_ignore(comp_ctx, res); |
| 73239 | goto parse_1_or_2; |
| 73240 | } |
| 73241 | } |
| 73242 | |
| 73243 | parse_1_or_2: |
| 73244 | /* |
| 73245 | * Parse variant 1 or 2. The first part expression (which differs |
| 73246 | * in the variants) has already been parsed and its code emitted. |
| 73247 | * |
| 73248 | * reg_temps + 0: unused |
| 73249 | * reg_temps + 1: unused |
| 73250 | */ |
| 73251 | { |
| 73252 | duk_regconst_t rc_cond; |
| 73253 | duk_int_t pc_l1, pc_l2, pc_l3, pc_l4; |
| 73254 | duk_int_t pc_jumpto_l3, pc_jumpto_l4; |
| 73255 | duk_bool_t expr_c_empty; |
| 73256 | |
| 73257 | DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2" )); |
| 73258 | |
| 73259 | /* "release" preallocated temps since we won't need them */ |
| 73260 | temp_reset = reg_temps + 0; |
| 73261 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73262 | |
| 73263 | duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON); |
| 73264 | |
| 73265 | pc_l1 = duk__get_current_pc(comp_ctx); |
| 73266 | duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */ |
| 73267 | if (duk__expr_is_empty(comp_ctx)) { |
| 73268 | /* no need to coerce */ |
| 73269 | pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */ |
| 73270 | pc_jumpto_l4 = -1; /* omitted */ |
| 73271 | } else { |
| 73272 | rc_cond = duk__ivalue_toregconst(comp_ctx, res); |
| 73273 | duk__emit_if_false_skip(comp_ctx, rc_cond); |
| 73274 | pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */ |
| 73275 | pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); /* to exit */ |
| 73276 | } |
| 73277 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73278 | |
| 73279 | duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON); |
| 73280 | |
| 73281 | pc_l2 = duk__get_current_pc(comp_ctx); |
| 73282 | duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */ |
| 73283 | if (duk__expr_is_empty(comp_ctx)) { |
| 73284 | /* no need to coerce */ |
| 73285 | expr_c_empty = 1; |
| 73286 | /* JUMP L1 omitted */ |
| 73287 | } else { |
| 73288 | duk__ivalue_toplain_ignore(comp_ctx, res); |
| 73289 | expr_c_empty = 0; |
| 73290 | duk__emit_jump(comp_ctx, pc_l1); |
| 73291 | } |
| 73292 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73293 | |
| 73294 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 73295 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ |
| 73296 | |
| 73297 | pc_l3 = duk__get_current_pc(comp_ctx); |
| 73298 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 73299 | if (expr_c_empty) { |
| 73300 | duk__emit_jump(comp_ctx, pc_l1); |
| 73301 | } else { |
| 73302 | duk__emit_jump(comp_ctx, pc_l2); |
| 73303 | } |
| 73304 | /* temp reset is not necessary after duk__parse_stmt(), which already does it */ |
| 73305 | |
| 73306 | pc_l4 = duk__get_current_pc(comp_ctx); |
| 73307 | |
| 73308 | DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, " |
| 73309 | "break: %ld->%ld, continue: %ld->%ld" , |
| 73310 | (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4, |
| 73311 | (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2)); |
| 73312 | |
| 73313 | duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3); |
| 73314 | duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4); |
| 73315 | duk__patch_jump(comp_ctx, |
| 73316 | pc_label_site + 1, |
| 73317 | pc_l4); /* break jump */ |
| 73318 | duk__patch_jump(comp_ctx, |
| 73319 | pc_label_site + 2, |
| 73320 | expr_c_empty ? pc_l1 : pc_l2); /* continue jump */ |
| 73321 | } |
| 73322 | goto finished; |
| 73323 | |
| 73324 | parse_3_or_4: |
| 73325 | /* |
| 73326 | * Parse variant 3 or 4. |
| 73327 | * |
| 73328 | * For variant 3 (e.g. "for (A in C) D;") the code for A (except the |
| 73329 | * final property/variable write) has already been emitted. The first |
| 73330 | * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted |
| 73331 | * there to satisfy control flow needs. |
| 73332 | * |
| 73333 | * For variant 4, if the variable declaration had an initializer |
| 73334 | * (e.g. "for (var A = B in C) D;") the code for the assignment |
| 73335 | * (B) has already been emitted. |
| 73336 | * |
| 73337 | * Variables set before entering here: |
| 73338 | * |
| 73339 | * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example). |
| 73340 | * reg_temps + 0: iteration target value (written to LHS) |
| 73341 | * reg_temps + 1: enumerator object |
| 73342 | */ |
| 73343 | { |
| 73344 | duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5; |
| 73345 | duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5; |
| 73346 | duk_regconst_t reg_target; |
| 73347 | |
| 73348 | DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld" , (long) pc_v34_lhs)); |
| 73349 | |
| 73350 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73351 | |
| 73352 | /* First we need to insert a jump in the middle of previously |
| 73353 | * emitted code to get the control flow right. No jumps can |
| 73354 | * cross the position where the jump is inserted. See doc/compiler.rst |
| 73355 | * for discussion on the intricacies of control flow and side effects |
| 73356 | * for variants 3 and 4. |
| 73357 | */ |
| 73358 | |
| 73359 | duk__insert_jump_entry(comp_ctx, pc_v34_lhs); |
| 73360 | pc_jumpto_l2 = pc_v34_lhs; /* inserted jump */ |
| 73361 | pc_l1 = pc_v34_lhs + 1; /* +1, right after inserted jump */ |
| 73362 | |
| 73363 | /* The code for writing reg_temps + 0 to the left hand side has already |
| 73364 | * been emitted. |
| 73365 | */ |
| 73366 | |
| 73367 | pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */ |
| 73368 | |
| 73369 | duk__advance(comp_ctx); /* eat 'in' */ |
| 73370 | |
| 73371 | /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined', |
| 73372 | * INITENUM will creates a 'null' enumerator which works like an empty enumerator |
| 73373 | * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a |
| 73374 | * register (constant not allowed). |
| 73375 | */ |
| 73376 | |
| 73377 | pc_l2 = duk__get_current_pc(comp_ctx); |
| 73378 | reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */ |
| 73379 | duk__emit_b_c(comp_ctx, |
| 73380 | DUK_OP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET, |
| 73381 | reg_temps + 1, |
| 73382 | reg_target); |
| 73383 | pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); |
| 73384 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73385 | |
| 73386 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 73387 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ |
| 73388 | |
| 73389 | pc_l3 = duk__get_current_pc(comp_ctx); |
| 73390 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 73391 | /* temp reset is not necessary after duk__parse_stmt(), which already does it */ |
| 73392 | |
| 73393 | /* NEXTENUM needs a jump slot right after the main opcode. |
| 73394 | * We need the code emitter to reserve the slot: if there's |
| 73395 | * target shuffling, the target shuffle opcodes must happen |
| 73396 | * after the jump slot (for NEXTENUM the shuffle opcodes are |
| 73397 | * not needed if the enum is finished). |
| 73398 | */ |
| 73399 | pc_l4 = duk__get_current_pc(comp_ctx); |
| 73400 | duk__emit_b_c(comp_ctx, |
| 73401 | DUK_OP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT, |
| 73402 | reg_temps + 0, |
| 73403 | reg_temps + 1); |
| 73404 | pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */ |
| 73405 | duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */ |
| 73406 | |
| 73407 | pc_l5 = duk__get_current_pc(comp_ctx); |
| 73408 | |
| 73409 | /* XXX: since the enumerator may be a memory expensive object, |
| 73410 | * perhaps clear it explicitly here? If so, break jump must |
| 73411 | * go through this clearing operation. |
| 73412 | */ |
| 73413 | |
| 73414 | DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, " |
| 73415 | "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, " |
| 73416 | "break: %ld->%ld, continue: %ld->%ld" , |
| 73417 | (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3, |
| 73418 | (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5, |
| 73419 | (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4)); |
| 73420 | |
| 73421 | duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2); |
| 73422 | duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3); |
| 73423 | duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4); |
| 73424 | duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5); |
| 73425 | duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5); /* break jump */ |
| 73426 | duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4); /* continue jump */ |
| 73427 | } |
| 73428 | goto finished; |
| 73429 | |
| 73430 | finished: |
| 73431 | DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement" )); |
| 73432 | return; |
| 73433 | |
| 73434 | syntax_error: |
| 73435 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR); |
| 73436 | DUK_WO_NORETURN(return;); |
| 73437 | } |
| 73438 | |
| 73439 | DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { |
| 73440 | duk_hthread *thr = comp_ctx->thr; |
| 73441 | duk_regconst_t temp_at_loop; |
| 73442 | duk_regconst_t rc_switch; /* reg/const for switch value */ |
| 73443 | duk_regconst_t rc_case; /* reg/const for case value */ |
| 73444 | duk_regconst_t reg_temp; /* general temp register */ |
| 73445 | duk_int_t pc_prevcase = -1; |
| 73446 | duk_int_t pc_prevstmt = -1; |
| 73447 | duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */ |
| 73448 | |
| 73449 | /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */ |
| 73450 | |
| 73451 | /* |
| 73452 | * Switch is pretty complicated because of several conflicting concerns: |
| 73453 | * |
| 73454 | * - Want to generate code without an intermediate representation, |
| 73455 | * i.e., in one go |
| 73456 | * |
| 73457 | * - Case selectors are expressions, not values, and may thus e.g. throw |
| 73458 | * exceptions (which causes evaluation order concerns) |
| 73459 | * |
| 73460 | * - Evaluation semantics of case selectors and default clause need to be |
| 73461 | * carefully implemented to provide correct behavior even with case value |
| 73462 | * side effects |
| 73463 | * |
| 73464 | * - Fall through case and default clauses; avoiding dead JUMPs if case |
| 73465 | * ends with an unconditional jump (a break or a continue) |
| 73466 | * |
| 73467 | * - The same case value may occur multiple times, but evaluation rules |
| 73468 | * only process the first match before switching to a "propagation" mode |
| 73469 | * where case values are no longer evaluated |
| 73470 | * |
| 73471 | * See E5 Section 12.11. Also see doc/compiler.rst for compilation |
| 73472 | * discussion. |
| 73473 | */ |
| 73474 | |
| 73475 | duk__advance(comp_ctx); |
| 73476 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 73477 | rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 73478 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* RegExp mode does not matter. */ |
| 73479 | duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); |
| 73480 | |
| 73481 | DUK_DDD(DUK_DDDPRINT("switch value in register %ld" , (long) rc_switch)); |
| 73482 | |
| 73483 | temp_at_loop = DUK__GETTEMP(comp_ctx); |
| 73484 | |
| 73485 | for (;;) { |
| 73486 | duk_int_t num_stmts; |
| 73487 | duk_small_uint_t tok; |
| 73488 | |
| 73489 | /* sufficient for keeping temp reg numbers in check */ |
| 73490 | DUK__SETTEMP(comp_ctx, temp_at_loop); |
| 73491 | |
| 73492 | if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { |
| 73493 | break; |
| 73494 | } |
| 73495 | |
| 73496 | /* |
| 73497 | * Parse a case or default clause. |
| 73498 | */ |
| 73499 | |
| 73500 | if (comp_ctx->curr_token.t == DUK_TOK_CASE) { |
| 73501 | /* |
| 73502 | * Case clause. |
| 73503 | * |
| 73504 | * Note: cannot use reg_case as a temp register (for SEQ target) |
| 73505 | * because it may be a constant. |
| 73506 | */ |
| 73507 | |
| 73508 | duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case |
| 73509 | * evaluation and checking |
| 73510 | */ |
| 73511 | |
| 73512 | duk__advance(comp_ctx); |
| 73513 | rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 73514 | duk__advance_expect(comp_ctx, DUK_TOK_COLON); |
| 73515 | |
| 73516 | reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 73517 | duk__emit_a_b_c(comp_ctx, |
| 73518 | DUK_OP_SEQ | DUK__EMIT_FLAG_BC_REGCONST, |
| 73519 | reg_temp, |
| 73520 | rc_switch, |
| 73521 | rc_case); |
| 73522 | duk__emit_if_true_skip(comp_ctx, reg_temp); |
| 73523 | |
| 73524 | /* jump to next case clause */ |
| 73525 | pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */ |
| 73526 | |
| 73527 | /* statements go here (if any) on next loop */ |
| 73528 | } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) { |
| 73529 | /* |
| 73530 | * Default clause. |
| 73531 | */ |
| 73532 | |
| 73533 | if (pc_default >= 0) { |
| 73534 | goto syntax_error; |
| 73535 | } |
| 73536 | duk__advance(comp_ctx); |
| 73537 | duk__advance_expect(comp_ctx, DUK_TOK_COLON); |
| 73538 | |
| 73539 | /* Fix for https://github.com/svaarala/duktape/issues/155: |
| 73540 | * If 'default' is first clause (detected by pc_prevcase < 0) |
| 73541 | * we need to ensure we stay in the matching chain. |
| 73542 | */ |
| 73543 | if (pc_prevcase < 0) { |
| 73544 | DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump" )); |
| 73545 | pc_prevcase = duk__emit_jump_empty(comp_ctx); |
| 73546 | } |
| 73547 | |
| 73548 | /* default clause matches next statement list (if any) */ |
| 73549 | pc_default = -2; |
| 73550 | } else { |
| 73551 | /* Code is not accepted before the first case/default clause */ |
| 73552 | goto syntax_error; |
| 73553 | } |
| 73554 | |
| 73555 | /* |
| 73556 | * Parse code after the clause. Possible terminators are |
| 73557 | * 'case', 'default', and '}'. |
| 73558 | * |
| 73559 | * Note that there may be no code at all, not even an empty statement, |
| 73560 | * between case clauses. This must be handled just like an empty statement |
| 73561 | * (omitting seemingly pointless JUMPs), to avoid situations like |
| 73562 | * test-bug-case-fallthrough.js. |
| 73563 | */ |
| 73564 | |
| 73565 | num_stmts = 0; |
| 73566 | if (pc_default == -2) { |
| 73567 | pc_default = duk__get_current_pc(comp_ctx); |
| 73568 | } |
| 73569 | |
| 73570 | /* Note: this is correct even for default clause statements: |
| 73571 | * they participate in 'fall-through' behavior even if the |
| 73572 | * default clause is in the middle. |
| 73573 | */ |
| 73574 | duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through' |
| 73575 | * after a case matches. |
| 73576 | */ |
| 73577 | |
| 73578 | for (;;) { |
| 73579 | tok = comp_ctx->curr_token.t; |
| 73580 | if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT || |
| 73581 | tok == DUK_TOK_RCURLY) { |
| 73582 | break; |
| 73583 | } |
| 73584 | num_stmts++; |
| 73585 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 73586 | } |
| 73587 | |
| 73588 | /* fall-through jump to next code of next case (backpatched) */ |
| 73589 | pc_prevstmt = duk__emit_jump_empty(comp_ctx); |
| 73590 | |
| 73591 | /* XXX: would be nice to omit this jump when the jump is not |
| 73592 | * reachable, at least in the obvious cases (such as the case |
| 73593 | * ending with a 'break'. |
| 73594 | * |
| 73595 | * Perhaps duk__parse_stmt() could provide some info on whether |
| 73596 | * the statement is a "dead end"? |
| 73597 | * |
| 73598 | * If implemented, just set pc_prevstmt to -1 when not needed. |
| 73599 | */ |
| 73600 | } |
| 73601 | |
| 73602 | DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY); |
| 73603 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 73604 | duk__advance(comp_ctx); /* Allow RegExp as part of next stmt. */ |
| 73605 | |
| 73606 | /* default case control flow patchup; note that if pc_prevcase < 0 |
| 73607 | * (i.e. no case clauses), control enters default case automatically. |
| 73608 | */ |
| 73609 | if (pc_default >= 0) { |
| 73610 | /* default case exists: go there if no case matches */ |
| 73611 | duk__patch_jump(comp_ctx, pc_prevcase, pc_default); |
| 73612 | } else { |
| 73613 | /* default case does not exist, or no statements present |
| 73614 | * after default case: finish case evaluation |
| 73615 | */ |
| 73616 | duk__patch_jump_here(comp_ctx, pc_prevcase); |
| 73617 | } |
| 73618 | |
| 73619 | /* fall-through control flow patchup; note that pc_prevstmt may be |
| 73620 | * < 0 (i.e. no case clauses), in which case this is a no-op. |
| 73621 | */ |
| 73622 | duk__patch_jump_here(comp_ctx, pc_prevstmt); |
| 73623 | |
| 73624 | /* continue jump not patched, an INVALID opcode remains there */ |
| 73625 | duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */ |
| 73626 | |
| 73627 | /* Note: 'fast' breaks will jump to pc_label_site + 1, which will |
| 73628 | * then jump here. The double jump will be eliminated by a |
| 73629 | * peephole pass, resulting in an optimal jump here. The label |
| 73630 | * site jumps will remain in bytecode and will waste code size. |
| 73631 | */ |
| 73632 | |
| 73633 | return; |
| 73634 | |
| 73635 | syntax_error: |
| 73636 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH); |
| 73637 | DUK_WO_NORETURN(return;); |
| 73638 | } |
| 73639 | |
| 73640 | DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 73641 | duk_regconst_t temp_reset; |
| 73642 | duk_regconst_t rc_cond; |
| 73643 | duk_int_t pc_jump_false; |
| 73644 | |
| 73645 | DUK_DDD(DUK_DDDPRINT("begin parsing if statement" )); |
| 73646 | |
| 73647 | temp_reset = DUK__GETTEMP(comp_ctx); |
| 73648 | |
| 73649 | duk__advance(comp_ctx); /* eat 'if' */ |
| 73650 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 73651 | |
| 73652 | rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 73653 | duk__emit_if_true_skip(comp_ctx, rc_cond); |
| 73654 | pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */ |
| 73655 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73656 | |
| 73657 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 73658 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ |
| 73659 | |
| 73660 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 73661 | |
| 73662 | /* The 'else' ambiguity is resolved by 'else' binding to the innermost |
| 73663 | * construct, so greedy matching is correct here. |
| 73664 | */ |
| 73665 | |
| 73666 | if (comp_ctx->curr_token.t == DUK_TOK_ELSE) { |
| 73667 | duk_int_t pc_jump_end; |
| 73668 | |
| 73669 | DUK_DDD(DUK_DDDPRINT("if has else part" )); |
| 73670 | |
| 73671 | duk__advance(comp_ctx); |
| 73672 | |
| 73673 | pc_jump_end = duk__emit_jump_empty(comp_ctx); /* jump from true part to end */ |
| 73674 | duk__patch_jump_here(comp_ctx, pc_jump_false); |
| 73675 | |
| 73676 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 73677 | |
| 73678 | duk__patch_jump_here(comp_ctx, pc_jump_end); |
| 73679 | } else { |
| 73680 | DUK_DDD(DUK_DDDPRINT("if does not have else part" )); |
| 73681 | |
| 73682 | duk__patch_jump_here(comp_ctx, pc_jump_false); |
| 73683 | } |
| 73684 | |
| 73685 | DUK_DDD(DUK_DDDPRINT("end parsing if statement" )); |
| 73686 | } |
| 73687 | |
| 73688 | DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { |
| 73689 | duk_regconst_t rc_cond; |
| 73690 | duk_int_t pc_start; |
| 73691 | |
| 73692 | DUK_DDD(DUK_DDDPRINT("begin parsing do statement" )); |
| 73693 | |
| 73694 | duk__advance(comp_ctx); /* Eat 'do'; allow RegExp as part of next stmt. */ |
| 73695 | |
| 73696 | pc_start = duk__get_current_pc(comp_ctx); |
| 73697 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 73698 | duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */ |
| 73699 | |
| 73700 | duk__advance_expect(comp_ctx, DUK_TOK_WHILE); |
| 73701 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 73702 | |
| 73703 | rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 73704 | duk__emit_if_false_skip(comp_ctx, rc_cond); |
| 73705 | duk__emit_jump(comp_ctx, pc_start); |
| 73706 | /* no need to reset temps, as we're finished emitting code */ |
| 73707 | |
| 73708 | comp_ctx->curr_func.allow_regexp_in_adv = 1; /* Allow RegExp as part of next stmt. */ |
| 73709 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); |
| 73710 | |
| 73711 | duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */ |
| 73712 | |
| 73713 | DUK_DDD(DUK_DDDPRINT("end parsing do statement" )); |
| 73714 | } |
| 73715 | |
| 73716 | DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) { |
| 73717 | duk_regconst_t temp_reset; |
| 73718 | duk_regconst_t rc_cond; |
| 73719 | duk_int_t pc_start; |
| 73720 | duk_int_t pc_jump_false; |
| 73721 | |
| 73722 | DUK_DDD(DUK_DDDPRINT("begin parsing while statement" )); |
| 73723 | |
| 73724 | temp_reset = DUK__GETTEMP(comp_ctx); |
| 73725 | |
| 73726 | duk__advance(comp_ctx); /* eat 'while' */ |
| 73727 | |
| 73728 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 73729 | |
| 73730 | pc_start = duk__get_current_pc(comp_ctx); |
| 73731 | duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */ |
| 73732 | |
| 73733 | rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 73734 | duk__emit_if_true_skip(comp_ctx, rc_cond); |
| 73735 | pc_jump_false = duk__emit_jump_empty(comp_ctx); |
| 73736 | DUK__SETTEMP(comp_ctx, temp_reset); |
| 73737 | |
| 73738 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 73739 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ |
| 73740 | |
| 73741 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 73742 | duk__emit_jump(comp_ctx, pc_start); |
| 73743 | |
| 73744 | duk__patch_jump_here(comp_ctx, pc_jump_false); |
| 73745 | duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */ |
| 73746 | |
| 73747 | DUK_DDD(DUK_DDDPRINT("end parsing while statement" )); |
| 73748 | } |
| 73749 | |
| 73750 | DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 73751 | duk_hthread *thr = comp_ctx->thr; |
| 73752 | duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK); |
| 73753 | duk_int_t label_id; |
| 73754 | duk_int_t label_catch_depth; |
| 73755 | duk_int_t label_pc; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */ |
| 73756 | duk_bool_t label_is_closest; |
| 73757 | |
| 73758 | DUK_UNREF(res); |
| 73759 | |
| 73760 | duk__advance(comp_ctx); /* eat 'break' or 'continue' */ |
| 73761 | |
| 73762 | if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */ |
| 73763 | comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */ |
| 73764 | comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */ |
| 73765 | /* break/continue without label */ |
| 73766 | |
| 73767 | duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest); |
| 73768 | } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) { |
| 73769 | /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */ |
| 73770 | DUK_ASSERT(comp_ctx->curr_token.str1 != NULL); |
| 73771 | duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest); |
| 73772 | duk__advance(comp_ctx); |
| 73773 | } else { |
| 73774 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL); |
| 73775 | DUK_WO_NORETURN(return;); |
| 73776 | } |
| 73777 | |
| 73778 | /* Use a fast break/continue when possible. A fast break/continue is |
| 73779 | * just a jump to the LABEL break/continue jump slot, which then jumps |
| 73780 | * to an appropriate place (for break, going through ENDLABEL correctly). |
| 73781 | * The peephole optimizer will optimize the jump to a direct one. |
| 73782 | */ |
| 73783 | |
| 73784 | if (label_catch_depth == comp_ctx->curr_func.catch_depth && |
| 73785 | label_is_closest) { |
| 73786 | DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, " |
| 73787 | "label_catch_depth=%ld, catch_depth=%ld " |
| 73788 | "-> use fast variant (direct jump)" , |
| 73789 | (long) is_break, (long) label_id, (long) label_is_closest, |
| 73790 | (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth)); |
| 73791 | |
| 73792 | duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2)); |
| 73793 | } else { |
| 73794 | DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, " |
| 73795 | "label_catch_depth=%ld, catch_depth=%ld " |
| 73796 | "-> use slow variant (longjmp)" , |
| 73797 | (long) is_break, (long) label_id, (long) label_is_closest, |
| 73798 | (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth)); |
| 73799 | |
| 73800 | duk__emit_bc(comp_ctx, |
| 73801 | is_break ? DUK_OP_BREAK : DUK_OP_CONTINUE, |
| 73802 | (duk_regconst_t) label_id); |
| 73803 | } |
| 73804 | } |
| 73805 | |
| 73806 | DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 73807 | duk_hthread *thr = comp_ctx->thr; |
| 73808 | duk_regconst_t rc_val; |
| 73809 | |
| 73810 | duk__advance(comp_ctx); /* eat 'return' */ |
| 73811 | |
| 73812 | /* A 'return' statement is only allowed inside an actual function body, |
| 73813 | * not as part of eval or global code. |
| 73814 | */ |
| 73815 | if (!comp_ctx->curr_func.is_function) { |
| 73816 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN); |
| 73817 | DUK_WO_NORETURN(return;); |
| 73818 | } |
| 73819 | |
| 73820 | if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */ |
| 73821 | comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */ |
| 73822 | comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */ |
| 73823 | DUK_DDD(DUK_DDDPRINT("empty return value -> undefined" )); |
| 73824 | duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF); |
| 73825 | } else { |
| 73826 | duk_int_t pc_before_expr; |
| 73827 | duk_int_t pc_after_expr; |
| 73828 | |
| 73829 | DUK_DDD(DUK_DDDPRINT("return with a value" )); |
| 73830 | |
| 73831 | DUK_UNREF(pc_before_expr); |
| 73832 | DUK_UNREF(pc_after_expr); |
| 73833 | |
| 73834 | pc_before_expr = duk__get_current_pc(comp_ctx); |
| 73835 | rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 73836 | pc_after_expr = duk__get_current_pc(comp_ctx); |
| 73837 | |
| 73838 | /* Tail call check: if last opcode emitted was CALL, and |
| 73839 | * the context allows it, add a tailcall flag to the CALL. |
| 73840 | * This doesn't guarantee that a tail call will be allowed at |
| 73841 | * runtime, so the RETURN must still be emitted. (Duktape |
| 73842 | * 0.10.0 avoided this and simulated a RETURN if a tail call |
| 73843 | * couldn't be used at runtime; but this didn't work |
| 73844 | * correctly with a thread yield/resume, see |
| 73845 | * test-bug-tailcall-thread-yield-resume.js for discussion.) |
| 73846 | * |
| 73847 | * In addition to the last opcode being CALL, we also need to |
| 73848 | * be sure that 'rc_val' is the result register of the CALL. |
| 73849 | * For instance, for the expression 'return 0, (function () |
| 73850 | * { return 1; }), 2' the last opcode emitted is CALL (no |
| 73851 | * bytecode is emitted for '2') but 'rc_val' indicates |
| 73852 | * constant '2'. Similarly if '2' is replaced by a register |
| 73853 | * bound variable, no opcodes are emitted but tail call would |
| 73854 | * be incorrect. |
| 73855 | * |
| 73856 | * This is tricky and easy to get wrong. It would be best to |
| 73857 | * track enough expression metadata to check that 'rc_val' came |
| 73858 | * from that last CALL instruction. We don't have that metadata |
| 73859 | * now, so we check that 'rc_val' is a temporary register result |
| 73860 | * (not a constant or a register bound variable). There should |
| 73861 | * be no way currently for 'rc_val' to be a temporary for an |
| 73862 | * expression following the CALL instruction without emitting |
| 73863 | * some opcodes following the CALL. This proxy check is used |
| 73864 | * below. |
| 73865 | * |
| 73866 | * See: test-bug-comma-expr-gh131.js. |
| 73867 | * |
| 73868 | * The non-standard 'caller' property disables tail calls |
| 73869 | * because they pose some special cases which haven't been |
| 73870 | * fixed yet. |
| 73871 | */ |
| 73872 | |
| 73873 | #if defined(DUK_USE_TAILCALL) |
| 73874 | if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */ |
| 73875 | pc_after_expr > pc_before_expr) { /* at least one opcode emitted */ |
| 73876 | duk_compiler_instr *instr; |
| 73877 | duk_instr_t ins; |
| 73878 | duk_small_uint_t op; |
| 73879 | |
| 73880 | instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1); |
| 73881 | DUK_ASSERT(instr != NULL); |
| 73882 | |
| 73883 | ins = instr->ins; |
| 73884 | op = (duk_small_uint_t) DUK_DEC_OP(ins); |
| 73885 | if ((op & ~0x0fU) == DUK_OP_CALL0 && |
| 73886 | DUK__ISREG_TEMP(comp_ctx, rc_val) /* see above */) { |
| 73887 | DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: " |
| 73888 | "catch depth is 0, duk__exprtop() emitted >= 1 instructions, " |
| 73889 | "and last instruction is a CALL " |
| 73890 | "-> change to TAILCALL" )); |
| 73891 | ins |= DUK_ENC_OP(DUK_BC_CALL_FLAG_TAILCALL); |
| 73892 | instr->ins = ins; |
| 73893 | } |
| 73894 | } |
| 73895 | #endif /* DUK_USE_TAILCALL */ |
| 73896 | |
| 73897 | if (DUK__ISREG(rc_val)) { |
| 73898 | duk__emit_bc(comp_ctx, DUK_OP_RETREG, rc_val); |
| 73899 | } else { |
| 73900 | rc_val = DUK__REMOVECONST(rc_val); |
| 73901 | if (duk__const_needs_refcount(comp_ctx, rc_val)) { |
| 73902 | duk__emit_bc(comp_ctx, DUK_OP_RETCONST, rc_val); |
| 73903 | } else { |
| 73904 | duk__emit_bc(comp_ctx, DUK_OP_RETCONSTN, rc_val); |
| 73905 | } |
| 73906 | } |
| 73907 | } |
| 73908 | } |
| 73909 | |
| 73910 | DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 73911 | duk_regconst_t reg_val; |
| 73912 | |
| 73913 | duk__advance(comp_ctx); /* eat 'throw' */ |
| 73914 | |
| 73915 | /* Unlike break/continue, throw statement does not allow an empty value. */ |
| 73916 | |
| 73917 | if (comp_ctx->curr_token.lineterm) { |
| 73918 | DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW); |
| 73919 | DUK_WO_NORETURN(return;); |
| 73920 | } |
| 73921 | |
| 73922 | reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 73923 | duk__emit_bc(comp_ctx, |
| 73924 | DUK_OP_THROW, |
| 73925 | reg_val); |
| 73926 | } |
| 73927 | |
| 73928 | DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 73929 | duk_hthread *thr = comp_ctx->thr; |
| 73930 | duk_regconst_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */ |
| 73931 | duk_regconst_t rc_varname = 0; |
| 73932 | duk_small_uint_t trycatch_flags = 0; |
| 73933 | duk_int_t pc_ldconst = -1; |
| 73934 | duk_int_t pc_trycatch = -1; |
| 73935 | duk_int_t pc_catch = -1; |
| 73936 | duk_int_t pc_finally = -1; |
| 73937 | |
| 73938 | DUK_UNREF(res); |
| 73939 | |
| 73940 | /* |
| 73941 | * See the following documentation for discussion: |
| 73942 | * |
| 73943 | * doc/execution.rst: control flow details |
| 73944 | * |
| 73945 | * Try, catch, and finally "parts" are Blocks, not Statements, so |
| 73946 | * they must always be delimited by curly braces. This is unlike e.g. |
| 73947 | * the if statement, which accepts any Statement. This eliminates any |
| 73948 | * questions of matching parts of nested try statements. The Block |
| 73949 | * parsing is implemented inline here (instead of calling out). |
| 73950 | * |
| 73951 | * Finally part has a 'let scoped' variable, which requires a few kinks |
| 73952 | * here. |
| 73953 | */ |
| 73954 | |
| 73955 | comp_ctx->curr_func.catch_depth++; |
| 73956 | |
| 73957 | duk__advance(comp_ctx); /* eat 'try' */ |
| 73958 | |
| 73959 | reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2); |
| 73960 | |
| 73961 | /* The target for this LDCONST may need output shuffling, but we assume |
| 73962 | * that 'pc_ldconst' will be the LDCONST that we can patch later. This |
| 73963 | * should be the case because there's no input shuffling. (If there's |
| 73964 | * no catch clause, this LDCONST will be replaced with a NOP.) |
| 73965 | */ |
| 73966 | pc_ldconst = duk__get_current_pc(comp_ctx); |
| 73967 | duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/); |
| 73968 | |
| 73969 | pc_trycatch = duk__get_current_pc(comp_ctx); |
| 73970 | duk__emit_invalid(comp_ctx); /* TRYCATCH, cannot emit now (not enough info) */ |
| 73971 | duk__emit_invalid(comp_ctx); /* jump for 'catch' case */ |
| 73972 | duk__emit_invalid(comp_ctx); /* jump for 'finally' case or end (if no finally) */ |
| 73973 | |
| 73974 | /* try part */ |
| 73975 | duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); |
| 73976 | duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); |
| 73977 | /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ |
| 73978 | duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY); |
| 73979 | |
| 73980 | if (comp_ctx->curr_token.t == DUK_TOK_CATCH) { |
| 73981 | /* |
| 73982 | * The catch variable must be updated to reflect the new allocated |
| 73983 | * register for the duration of the catch clause. We need to store |
| 73984 | * and restore the original value for the varmap entry (if any). |
| 73985 | */ |
| 73986 | |
| 73987 | /* |
| 73988 | * Note: currently register bindings must be fixed for the entire |
| 73989 | * function. So, even though the catch variable is in a register |
| 73990 | * we know, we must use an explicit environment record and slow path |
| 73991 | * accesses to read/write the catch binding to make closures created |
| 73992 | * within the catch clause work correctly. This restriction should |
| 73993 | * be fixable (at least in common cases) later. |
| 73994 | * |
| 73995 | * See: test-bug-catch-binding-2.js. |
| 73996 | * |
| 73997 | * XXX: improve to get fast path access to most catch clauses. |
| 73998 | */ |
| 73999 | |
| 74000 | duk_hstring *h_var; |
| 74001 | duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */ |
| 74002 | |
| 74003 | DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld" , (long) duk_get_top(thr))); |
| 74004 | |
| 74005 | trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH; |
| 74006 | |
| 74007 | pc_catch = duk__get_current_pc(comp_ctx); |
| 74008 | |
| 74009 | duk__advance(comp_ctx); |
| 74010 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 74011 | |
| 74012 | if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) { |
| 74013 | /* Identifier, i.e. don't allow reserved words */ |
| 74014 | goto syntax_error; |
| 74015 | } |
| 74016 | h_var = comp_ctx->curr_token.str1; |
| 74017 | DUK_ASSERT(h_var != NULL); |
| 74018 | |
| 74019 | duk_push_hstring(thr, h_var); /* keep in on valstack, use borrowed ref below */ |
| 74020 | |
| 74021 | if (comp_ctx->curr_func.is_strict && |
| 74022 | ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) || |
| 74023 | (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) { |
| 74024 | DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError" )); |
| 74025 | goto syntax_error; |
| 74026 | } |
| 74027 | |
| 74028 | duk_dup_top(thr); |
| 74029 | rc_varname = duk__getconst(comp_ctx); |
| 74030 | DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)" , |
| 74031 | (unsigned long) rc_varname, (long) rc_varname)); |
| 74032 | |
| 74033 | duk__advance(comp_ctx); |
| 74034 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); |
| 74035 | |
| 74036 | duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); |
| 74037 | |
| 74038 | DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT" , |
| 74039 | (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx))); |
| 74040 | |
| 74041 | duk_dup_top(thr); |
| 74042 | duk_get_prop(thr, comp_ctx->curr_func.varmap_idx); |
| 74043 | if (duk_is_undefined(thr, -1)) { |
| 74044 | varmap_value = -2; |
| 74045 | } else if (duk_is_null(thr, -1)) { |
| 74046 | varmap_value = -1; |
| 74047 | } else { |
| 74048 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 74049 | varmap_value = duk_get_int(thr, -1); |
| 74050 | DUK_ASSERT(varmap_value >= 0); |
| 74051 | } |
| 74052 | duk_pop(thr); |
| 74053 | |
| 74054 | #if 0 |
| 74055 | /* It'd be nice to do something like this - but it doesn't |
| 74056 | * work for closures created inside the catch clause. |
| 74057 | */ |
| 74058 | duk_dup_top(thr); |
| 74059 | duk_push_int(thr, (duk_int_t) (reg_catch + 0)); |
| 74060 | duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); |
| 74061 | #endif |
| 74062 | duk_dup_top(thr); |
| 74063 | duk_push_null(thr); |
| 74064 | duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); |
| 74065 | |
| 74066 | duk__emit_a_bc(comp_ctx, |
| 74067 | DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE, |
| 74068 | reg_catch + 0 /*value*/, |
| 74069 | rc_varname /*varname*/); |
| 74070 | |
| 74071 | DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT" , |
| 74072 | (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx))); |
| 74073 | |
| 74074 | duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); |
| 74075 | /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ |
| 74076 | |
| 74077 | if (varmap_value == -2) { |
| 74078 | /* not present */ |
| 74079 | duk_del_prop(thr, comp_ctx->curr_func.varmap_idx); |
| 74080 | } else { |
| 74081 | if (varmap_value == -1) { |
| 74082 | duk_push_null(thr); |
| 74083 | } else { |
| 74084 | DUK_ASSERT(varmap_value >= 0); |
| 74085 | duk_push_int(thr, varmap_value); |
| 74086 | } |
| 74087 | duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); |
| 74088 | } |
| 74089 | /* varname is popped by above code */ |
| 74090 | |
| 74091 | DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT" , |
| 74092 | (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx))); |
| 74093 | |
| 74094 | duk__emit_op_only(comp_ctx, |
| 74095 | DUK_OP_ENDCATCH); |
| 74096 | |
| 74097 | /* |
| 74098 | * XXX: for now, indicate that an expensive catch binding |
| 74099 | * declarative environment is always needed. If we don't |
| 74100 | * need it, we don't need the const_varname either. |
| 74101 | */ |
| 74102 | |
| 74103 | trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING; |
| 74104 | |
| 74105 | DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld" , (long) duk_get_top(thr))); |
| 74106 | } |
| 74107 | |
| 74108 | if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) { |
| 74109 | trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY; |
| 74110 | |
| 74111 | pc_finally = duk__get_current_pc(comp_ctx); |
| 74112 | |
| 74113 | duk__advance(comp_ctx); |
| 74114 | |
| 74115 | duk__advance_expect(comp_ctx, DUK_TOK_LCURLY); |
| 74116 | duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); |
| 74117 | /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ |
| 74118 | duk__emit_abc(comp_ctx, |
| 74119 | DUK_OP_ENDFIN, |
| 74120 | reg_catch); /* rethrow */ |
| 74121 | } |
| 74122 | |
| 74123 | if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) && |
| 74124 | !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) { |
| 74125 | /* must have catch and/or finally */ |
| 74126 | goto syntax_error; |
| 74127 | } |
| 74128 | |
| 74129 | /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch() |
| 74130 | * will replace the LDCONST with a NOP. For any actual constant (including |
| 74131 | * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname. |
| 74132 | */ |
| 74133 | |
| 74134 | duk__patch_trycatch(comp_ctx, |
| 74135 | pc_ldconst, |
| 74136 | pc_trycatch, |
| 74137 | reg_catch, |
| 74138 | rc_varname, |
| 74139 | trycatch_flags); |
| 74140 | |
| 74141 | if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { |
| 74142 | DUK_ASSERT(pc_catch >= 0); |
| 74143 | duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch); |
| 74144 | } |
| 74145 | |
| 74146 | if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) { |
| 74147 | DUK_ASSERT(pc_finally >= 0); |
| 74148 | duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally); |
| 74149 | } else { |
| 74150 | /* without finally, the second jump slot is used to jump to end of stmt */ |
| 74151 | duk__patch_jump_here(comp_ctx, pc_trycatch + 2); |
| 74152 | } |
| 74153 | |
| 74154 | comp_ctx->curr_func.catch_depth--; |
| 74155 | return; |
| 74156 | |
| 74157 | syntax_error: |
| 74158 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY); |
| 74159 | DUK_WO_NORETURN(return;); |
| 74160 | } |
| 74161 | |
| 74162 | DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { |
| 74163 | duk_int_t pc_trycatch; |
| 74164 | duk_int_t pc_finished; |
| 74165 | duk_regconst_t reg_catch; |
| 74166 | duk_small_uint_t trycatch_flags; |
| 74167 | |
| 74168 | if (comp_ctx->curr_func.is_strict) { |
| 74169 | DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE); |
| 74170 | DUK_WO_NORETURN(return;); |
| 74171 | } |
| 74172 | |
| 74173 | comp_ctx->curr_func.catch_depth++; |
| 74174 | |
| 74175 | duk__advance(comp_ctx); /* eat 'with' */ |
| 74176 | |
| 74177 | reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2); |
| 74178 | |
| 74179 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 74180 | duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch); |
| 74181 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 74182 | duk__advance_expect(comp_ctx, DUK_TOK_RPAREN); /* Allow RegExp as part of next stmt. */ |
| 74183 | |
| 74184 | pc_trycatch = duk__get_current_pc(comp_ctx); |
| 74185 | trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING; |
| 74186 | duk__emit_a_bc(comp_ctx, |
| 74187 | DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A, |
| 74188 | (duk_regconst_t) trycatch_flags /*a*/, |
| 74189 | reg_catch /*bc*/); |
| 74190 | duk__emit_invalid(comp_ctx); /* catch jump */ |
| 74191 | duk__emit_invalid(comp_ctx); /* finished jump */ |
| 74192 | |
| 74193 | duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/); |
| 74194 | duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY); |
| 74195 | |
| 74196 | pc_finished = duk__get_current_pc(comp_ctx); |
| 74197 | |
| 74198 | duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished); |
| 74199 | |
| 74200 | comp_ctx->curr_func.catch_depth--; |
| 74201 | } |
| 74202 | |
| 74203 | DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) { |
| 74204 | /* if a site already exists, nop: max one label site per statement */ |
| 74205 | if (label_id >= 0) { |
| 74206 | return label_id; |
| 74207 | } |
| 74208 | |
| 74209 | label_id = comp_ctx->curr_func.label_next++; |
| 74210 | DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld" , (long) label_id)); |
| 74211 | |
| 74212 | duk__emit_bc(comp_ctx, |
| 74213 | DUK_OP_LABEL, |
| 74214 | (duk_regconst_t) label_id); |
| 74215 | duk__emit_invalid(comp_ctx); |
| 74216 | duk__emit_invalid(comp_ctx); |
| 74217 | |
| 74218 | return label_id; |
| 74219 | } |
| 74220 | |
| 74221 | /* Parse a single statement. |
| 74222 | * |
| 74223 | * Creates a label site (with an empty label) automatically for iteration |
| 74224 | * statements. Also "peels off" any label statements for explicit labels. |
| 74225 | */ |
| 74226 | DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) { |
| 74227 | duk_hthread *thr = comp_ctx->thr; |
| 74228 | duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */ |
| 74229 | duk_regconst_t temp_at_entry; |
| 74230 | duk_size_t labels_len_at_entry; |
| 74231 | duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */ |
| 74232 | duk_int_t stmt_id; |
| 74233 | duk_small_uint_t stmt_flags = 0; |
| 74234 | duk_int_t label_id = -1; |
| 74235 | duk_small_uint_t tok; |
| 74236 | duk_bool_t test_func_decl; |
| 74237 | |
| 74238 | DUK__RECURSION_INCREASE(comp_ctx, thr); |
| 74239 | |
| 74240 | temp_at_entry = DUK__GETTEMP(comp_ctx); |
| 74241 | pc_at_entry = duk__get_current_pc(comp_ctx); |
| 74242 | labels_len_at_entry = duk_get_length(thr, comp_ctx->curr_func.labelnames_idx); |
| 74243 | stmt_id = comp_ctx->curr_func.stmt_next++; |
| 74244 | dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue; |
| 74245 | |
| 74246 | DUK_UNREF(stmt_id); |
| 74247 | |
| 74248 | DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, " |
| 74249 | "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld" , |
| 74250 | (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry, |
| 74251 | (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue, |
| 74252 | (long) comp_ctx->curr_func.catch_depth)); |
| 74253 | |
| 74254 | /* The directive prologue flag is cleared by default so that it is |
| 74255 | * unset for any recursive statement parsing. It is only "revived" |
| 74256 | * if a directive is detected. (We could also make directives only |
| 74257 | * allowed if 'allow_source_elem' was true.) |
| 74258 | */ |
| 74259 | comp_ctx->curr_func.in_directive_prologue = 0; |
| 74260 | |
| 74261 | retry_parse: |
| 74262 | |
| 74263 | DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld" , |
| 74264 | (long) stmt_id, (long) label_id, (long) allow_source_elem, |
| 74265 | (long) comp_ctx->curr_func.catch_depth)); |
| 74266 | |
| 74267 | /* |
| 74268 | * Detect iteration statements; if encountered, establish an |
| 74269 | * empty label. |
| 74270 | */ |
| 74271 | |
| 74272 | tok = comp_ctx->curr_token.t; |
| 74273 | if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE || |
| 74274 | tok == DUK_TOK_SWITCH) { |
| 74275 | DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label" )); |
| 74276 | |
| 74277 | label_id = duk__stmt_label_site(comp_ctx, label_id); |
| 74278 | duk__add_label(comp_ctx, |
| 74279 | DUK_HTHREAD_STRING_EMPTY_STRING(thr), |
| 74280 | pc_at_entry /*pc_label*/, |
| 74281 | label_id); |
| 74282 | } |
| 74283 | |
| 74284 | /* |
| 74285 | * Main switch for statement / source element type. |
| 74286 | */ |
| 74287 | |
| 74288 | switch (comp_ctx->curr_token.t) { |
| 74289 | case DUK_TOK_FUNCTION: { |
| 74290 | /* |
| 74291 | * Function declaration, function expression, or (non-standard) |
| 74292 | * function statement. |
| 74293 | * |
| 74294 | * The E5 specification only allows function declarations at |
| 74295 | * the top level (in "source elements"). An ExpressionStatement |
| 74296 | * is explicitly not allowed to begin with a "function" keyword |
| 74297 | * (E5 Section 12.4). Hence any non-error semantics for such |
| 74298 | * non-top-level statements are non-standard. Duktape semantics |
| 74299 | * for function statements are modelled after V8, see |
| 74300 | * test-dev-func-decl-outside-top.js. |
| 74301 | */ |
| 74302 | test_func_decl = allow_source_elem; |
| 74303 | #if defined(DUK_USE_NONSTD_FUNC_STMT) |
| 74304 | /* Lenient: allow function declarations outside top level in both |
| 74305 | * strict and non-strict modes. However, don't allow labelled |
| 74306 | * function declarations in strict mode. |
| 74307 | */ |
| 74308 | test_func_decl = test_func_decl || |
| 74309 | !comp_ctx->curr_func.is_strict || |
| 74310 | label_id < 0; |
| 74311 | #endif /* DUK_USE_NONSTD_FUNC_STMT */ |
| 74312 | /* Strict: never allow function declarations outside top level. */ |
| 74313 | if (test_func_decl) { |
| 74314 | /* FunctionDeclaration: not strictly a statement but handled as such. |
| 74315 | * |
| 74316 | * O(depth^2) parse count for inner functions is handled by recording a |
| 74317 | * lexer offset on the first compilation pass, so that the function can |
| 74318 | * be efficiently skipped on the second pass. This is encapsulated into |
| 74319 | * duk__parse_func_like_fnum(). |
| 74320 | */ |
| 74321 | |
| 74322 | duk_int_t fnum; |
| 74323 | #if defined(DUK_USE_ASSERTIONS) |
| 74324 | duk_idx_t top_before; |
| 74325 | #endif |
| 74326 | |
| 74327 | DUK_DDD(DUK_DDDPRINT("function declaration statement" )); |
| 74328 | |
| 74329 | #if defined(DUK_USE_ASSERTIONS) |
| 74330 | top_before = duk_get_top(thr); |
| 74331 | #endif |
| 74332 | |
| 74333 | duk__advance(comp_ctx); /* eat 'function' */ |
| 74334 | fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_DECL | DUK__FUNC_FLAG_PUSHNAME_PASS1); |
| 74335 | |
| 74336 | /* The value stack convention here is a bit odd: the function |
| 74337 | * name is only pushed on pass 1 (in_scanning), and is needed |
| 74338 | * to process function declarations. |
| 74339 | */ |
| 74340 | if (comp_ctx->curr_func.in_scanning) { |
| 74341 | duk_uarridx_t n; |
| 74342 | |
| 74343 | #if defined(DUK_USE_ASSERTIONS) |
| 74344 | DUK_ASSERT(duk_get_top(thr) == top_before + 1); |
| 74345 | #endif |
| 74346 | DUK_DDD(DUK_DDDPRINT("register function declaration %!T in pass 1, fnum %ld" , |
| 74347 | duk_get_tval(thr, -1), (long) fnum)); |
| 74348 | n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx); |
| 74349 | /* funcname is at index -1 */ |
| 74350 | duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n); |
| 74351 | duk_push_int(thr, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8))); |
| 74352 | duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1); |
| 74353 | } else { |
| 74354 | #if defined(DUK_USE_ASSERTIONS) |
| 74355 | DUK_ASSERT(duk_get_top(thr) == top_before); |
| 74356 | #endif |
| 74357 | } |
| 74358 | |
| 74359 | /* no statement value (unlike function expression) */ |
| 74360 | stmt_flags = 0; |
| 74361 | break; |
| 74362 | } else { |
| 74363 | DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED); |
| 74364 | DUK_WO_NORETURN(return;); |
| 74365 | } |
| 74366 | break; |
| 74367 | } |
| 74368 | case DUK_TOK_LCURLY: { |
| 74369 | DUK_DDD(DUK_DDDPRINT("block statement" )); |
| 74370 | duk__advance(comp_ctx); |
| 74371 | duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/); |
| 74372 | /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */ |
| 74373 | if (label_id >= 0) { |
| 74374 | duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */ |
| 74375 | } |
| 74376 | stmt_flags = 0; |
| 74377 | break; |
| 74378 | } |
| 74379 | case DUK_TOK_CONST: { |
| 74380 | DUK_DDD(DUK_DDDPRINT("constant declaration statement" )); |
| 74381 | duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/); |
| 74382 | stmt_flags = DUK__HAS_TERM; |
| 74383 | break; |
| 74384 | } |
| 74385 | case DUK_TOK_VAR: { |
| 74386 | DUK_DDD(DUK_DDDPRINT("variable declaration statement" )); |
| 74387 | duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/); |
| 74388 | stmt_flags = DUK__HAS_TERM; |
| 74389 | break; |
| 74390 | } |
| 74391 | case DUK_TOK_SEMICOLON: { |
| 74392 | /* empty statement with an explicit semicolon */ |
| 74393 | DUK_DDD(DUK_DDDPRINT("empty statement" )); |
| 74394 | stmt_flags = DUK__HAS_TERM; |
| 74395 | break; |
| 74396 | } |
| 74397 | case DUK_TOK_IF: { |
| 74398 | DUK_DDD(DUK_DDDPRINT("if statement" )); |
| 74399 | duk__parse_if_stmt(comp_ctx, res); |
| 74400 | if (label_id >= 0) { |
| 74401 | duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */ |
| 74402 | } |
| 74403 | stmt_flags = 0; |
| 74404 | break; |
| 74405 | } |
| 74406 | case DUK_TOK_DO: { |
| 74407 | /* |
| 74408 | * Do-while statement is mostly trivial, but there is special |
| 74409 | * handling for automatic semicolon handling (triggered by the |
| 74410 | * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at: |
| 74411 | * |
| 74412 | * https://bugs.ecmascript.org/show_bug.cgi?id=8 |
| 74413 | * |
| 74414 | * See doc/compiler.rst for details. |
| 74415 | */ |
| 74416 | DUK_DDD(DUK_DDDPRINT("do statement" )); |
| 74417 | DUK_ASSERT(label_id >= 0); |
| 74418 | duk__update_label_flags(comp_ctx, |
| 74419 | label_id, |
| 74420 | DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE); |
| 74421 | duk__parse_do_stmt(comp_ctx, res, pc_at_entry); |
| 74422 | stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */ |
| 74423 | break; |
| 74424 | } |
| 74425 | case DUK_TOK_WHILE: { |
| 74426 | DUK_DDD(DUK_DDDPRINT("while statement" )); |
| 74427 | DUK_ASSERT(label_id >= 0); |
| 74428 | duk__update_label_flags(comp_ctx, |
| 74429 | label_id, |
| 74430 | DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE); |
| 74431 | duk__parse_while_stmt(comp_ctx, res, pc_at_entry); |
| 74432 | stmt_flags = 0; |
| 74433 | break; |
| 74434 | } |
| 74435 | case DUK_TOK_FOR: { |
| 74436 | /* |
| 74437 | * For/for-in statement is complicated to parse because |
| 74438 | * determining the statement type (three-part for vs. a |
| 74439 | * for-in) requires potential backtracking. |
| 74440 | * |
| 74441 | * See the helper for the messy stuff. |
| 74442 | */ |
| 74443 | DUK_DDD(DUK_DDDPRINT("for/for-in statement" )); |
| 74444 | DUK_ASSERT(label_id >= 0); |
| 74445 | duk__update_label_flags(comp_ctx, |
| 74446 | label_id, |
| 74447 | DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE); |
| 74448 | duk__parse_for_stmt(comp_ctx, res, pc_at_entry); |
| 74449 | stmt_flags = 0; |
| 74450 | break; |
| 74451 | } |
| 74452 | case DUK_TOK_CONTINUE: |
| 74453 | case DUK_TOK_BREAK: { |
| 74454 | DUK_DDD(DUK_DDDPRINT("break/continue statement" )); |
| 74455 | duk__parse_break_or_continue_stmt(comp_ctx, res); |
| 74456 | stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL; |
| 74457 | break; |
| 74458 | } |
| 74459 | case DUK_TOK_RETURN: { |
| 74460 | DUK_DDD(DUK_DDDPRINT("return statement" )); |
| 74461 | duk__parse_return_stmt(comp_ctx, res); |
| 74462 | stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL; |
| 74463 | break; |
| 74464 | } |
| 74465 | case DUK_TOK_WITH: { |
| 74466 | DUK_DDD(DUK_DDDPRINT("with statement" )); |
| 74467 | comp_ctx->curr_func.with_depth++; |
| 74468 | duk__parse_with_stmt(comp_ctx, res); |
| 74469 | if (label_id >= 0) { |
| 74470 | duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */ |
| 74471 | } |
| 74472 | comp_ctx->curr_func.with_depth--; |
| 74473 | stmt_flags = 0; |
| 74474 | break; |
| 74475 | } |
| 74476 | case DUK_TOK_SWITCH: { |
| 74477 | /* |
| 74478 | * The switch statement is pretty messy to compile. |
| 74479 | * See the helper for details. |
| 74480 | */ |
| 74481 | DUK_DDD(DUK_DDDPRINT("switch statement" )); |
| 74482 | DUK_ASSERT(label_id >= 0); |
| 74483 | duk__update_label_flags(comp_ctx, |
| 74484 | label_id, |
| 74485 | DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */ |
| 74486 | duk__parse_switch_stmt(comp_ctx, res, pc_at_entry); |
| 74487 | stmt_flags = 0; |
| 74488 | break; |
| 74489 | } |
| 74490 | case DUK_TOK_THROW: { |
| 74491 | DUK_DDD(DUK_DDDPRINT("throw statement" )); |
| 74492 | duk__parse_throw_stmt(comp_ctx, res); |
| 74493 | stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL; |
| 74494 | break; |
| 74495 | } |
| 74496 | case DUK_TOK_TRY: { |
| 74497 | DUK_DDD(DUK_DDDPRINT("try statement" )); |
| 74498 | duk__parse_try_stmt(comp_ctx, res); |
| 74499 | stmt_flags = 0; |
| 74500 | break; |
| 74501 | } |
| 74502 | case DUK_TOK_DEBUGGER: { |
| 74503 | duk__advance(comp_ctx); |
| 74504 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 74505 | DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode" )); |
| 74506 | duk__emit_op_only(comp_ctx, DUK_OP_DEBUGGER); |
| 74507 | #else |
| 74508 | DUK_DDD(DUK_DDDPRINT("debugger statement: ignored" )); |
| 74509 | #endif |
| 74510 | stmt_flags = DUK__HAS_TERM; |
| 74511 | break; |
| 74512 | } |
| 74513 | default: { |
| 74514 | /* |
| 74515 | * Else, must be one of: |
| 74516 | * - ExpressionStatement, possibly a directive (String) |
| 74517 | * - LabelledStatement (Identifier followed by ':') |
| 74518 | * |
| 74519 | * Expressions beginning with 'function' keyword are covered by a case |
| 74520 | * above (such expressions are not allowed in standard E5 anyway). |
| 74521 | * Also expressions starting with '{' are interpreted as block |
| 74522 | * statements. See E5 Section 12.4. |
| 74523 | * |
| 74524 | * Directive detection is tricky; see E5 Section 14.1 on directive |
| 74525 | * prologue. A directive is an expression statement with a single |
| 74526 | * string literal and an explicit or automatic semicolon. Escape |
| 74527 | * characters are significant and no parens etc are allowed: |
| 74528 | * |
| 74529 | * 'use strict'; // valid 'use strict' directive |
| 74530 | * 'use\u0020strict'; // valid directive, not a 'use strict' directive |
| 74531 | * ('use strict'); // not a valid directive |
| 74532 | * |
| 74533 | * The expression is determined to consist of a single string literal |
| 74534 | * based on duk__expr_nud() and duk__expr_led() call counts. The string literal |
| 74535 | * of a 'use strict' directive is determined to lack any escapes based |
| 74536 | * num_escapes count from the lexer. Note that other directives may be |
| 74537 | * allowed to contain escapes, so a directive with escapes does not |
| 74538 | * terminate a directive prologue. |
| 74539 | * |
| 74540 | * We rely on the fact that the expression parser will not emit any |
| 74541 | * code for a single token expression. However, it will generate an |
| 74542 | * intermediate value which we will then successfully ignore. |
| 74543 | * |
| 74544 | * A similar approach is used for labels. |
| 74545 | */ |
| 74546 | |
| 74547 | duk_bool_t single_token; |
| 74548 | |
| 74549 | DUK_DDD(DUK_DDDPRINT("expression statement" )); |
| 74550 | duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); |
| 74551 | |
| 74552 | single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */ |
| 74553 | comp_ctx->curr_func.led_count == 0); /* no operators */ |
| 74554 | |
| 74555 | if (single_token && |
| 74556 | comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER && |
| 74557 | comp_ctx->curr_token.t == DUK_TOK_COLON) { |
| 74558 | /* |
| 74559 | * Detected label |
| 74560 | */ |
| 74561 | |
| 74562 | duk_hstring *h_lab; |
| 74563 | |
| 74564 | /* expected ival */ |
| 74565 | DUK_ASSERT(res->t == DUK_IVAL_VAR); |
| 74566 | DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE); |
| 74567 | DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx))); |
| 74568 | h_lab = comp_ctx->prev_token.str1; |
| 74569 | DUK_ASSERT(h_lab != NULL); |
| 74570 | |
| 74571 | DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'" , |
| 74572 | (duk_heaphdr *) h_lab)); |
| 74573 | |
| 74574 | duk__advance(comp_ctx); /* eat colon */ |
| 74575 | |
| 74576 | label_id = duk__stmt_label_site(comp_ctx, label_id); |
| 74577 | |
| 74578 | duk__add_label(comp_ctx, |
| 74579 | h_lab, |
| 74580 | pc_at_entry /*pc_label*/, |
| 74581 | label_id); |
| 74582 | |
| 74583 | /* a statement following a label cannot be a source element |
| 74584 | * (a function declaration). |
| 74585 | */ |
| 74586 | allow_source_elem = 0; |
| 74587 | |
| 74588 | DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing" )); |
| 74589 | goto retry_parse; |
| 74590 | } |
| 74591 | |
| 74592 | stmt_flags = 0; |
| 74593 | |
| 74594 | if (dir_prol_at_entry && /* still in prologue */ |
| 74595 | single_token && /* single string token */ |
| 74596 | comp_ctx->prev_token.t == DUK_TOK_STRING) { |
| 74597 | /* |
| 74598 | * Detected a directive |
| 74599 | */ |
| 74600 | duk_hstring *h_dir; |
| 74601 | |
| 74602 | /* expected ival */ |
| 74603 | DUK_ASSERT(res->t == DUK_IVAL_PLAIN); |
| 74604 | DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE); |
| 74605 | DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx))); |
| 74606 | h_dir = comp_ctx->prev_token.str1; |
| 74607 | DUK_ASSERT(h_dir != NULL); |
| 74608 | |
| 74609 | DUK_DDD(DUK_DDDPRINT("potential directive: %!O" , h_dir)); |
| 74610 | |
| 74611 | stmt_flags |= DUK__STILL_PROLOGUE; |
| 74612 | |
| 74613 | /* Note: escaped characters differentiate directives */ |
| 74614 | |
| 74615 | if (comp_ctx->prev_token.num_escapes > 0) { |
| 74616 | DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive " |
| 74617 | "but we ignore such directives" )); |
| 74618 | } else { |
| 74619 | /* |
| 74620 | * The length comparisons are present to handle |
| 74621 | * strings like "use strict\u0000foo" as required. |
| 74622 | */ |
| 74623 | |
| 74624 | if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 && |
| 74625 | DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict" ) == 0) { |
| 74626 | #if defined(DUK_USE_STRICT_DECL) |
| 74627 | DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld" , |
| 74628 | (long) comp_ctx->curr_func.is_strict, (long) 1)); |
| 74629 | comp_ctx->curr_func.is_strict = 1; |
| 74630 | #else |
| 74631 | DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring" )); |
| 74632 | #endif |
| 74633 | } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 && |
| 74634 | DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail" ) == 0) { |
| 74635 | DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld" , |
| 74636 | (long) comp_ctx->curr_func.is_notail, (long) 1)); |
| 74637 | comp_ctx->curr_func.is_notail = 1; |
| 74638 | } else { |
| 74639 | DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating " |
| 74640 | "directive prologue" , (duk_hobject *) h_dir)); |
| 74641 | } |
| 74642 | } |
| 74643 | } else { |
| 74644 | DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; " |
| 74645 | "prologue terminated if still active" )); |
| 74646 | } |
| 74647 | |
| 74648 | stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM; |
| 74649 | } |
| 74650 | } /* end switch (tok) */ |
| 74651 | |
| 74652 | /* |
| 74653 | * Statement value handling. |
| 74654 | * |
| 74655 | * Global code and eval code has an implicit return value |
| 74656 | * which comes from the last statement with a value |
| 74657 | * (technically a non-"empty" continuation, which is |
| 74658 | * different from an empty statement). |
| 74659 | * |
| 74660 | * Since we don't know whether a later statement will |
| 74661 | * override the value of the current statement, we need |
| 74662 | * to coerce the statement value to a register allocated |
| 74663 | * for implicit return values. In other cases we need |
| 74664 | * to coerce the statement value to a plain value to get |
| 74665 | * any side effects out (consider e.g. "foo.bar;"). |
| 74666 | */ |
| 74667 | |
| 74668 | /* XXX: what about statements which leave a half-cooked value in 'res' |
| 74669 | * but have no stmt value? Any such statements? |
| 74670 | */ |
| 74671 | |
| 74672 | if (stmt_flags & DUK__HAS_VAL) { |
| 74673 | duk_regconst_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value; |
| 74674 | if (reg_stmt_value >= 0) { |
| 74675 | duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value); |
| 74676 | } else { |
| 74677 | duk__ivalue_toplain_ignore(comp_ctx, res); |
| 74678 | } |
| 74679 | } else { |
| 74680 | ; |
| 74681 | } |
| 74682 | |
| 74683 | /* |
| 74684 | * Statement terminator check, including automatic semicolon |
| 74685 | * handling. After this step, 'curr_tok' should be the first |
| 74686 | * token after a possible statement terminator. |
| 74687 | */ |
| 74688 | |
| 74689 | if (stmt_flags & DUK__HAS_TERM) { |
| 74690 | if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) { |
| 74691 | DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement" )); |
| 74692 | duk__advance(comp_ctx); |
| 74693 | } else { |
| 74694 | if (comp_ctx->curr_token.allow_auto_semi) { |
| 74695 | DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement" )); |
| 74696 | } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) { |
| 74697 | /* XXX: make this lenience dependent on flags or strictness? */ |
| 74698 | DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility " |
| 74699 | "even though no lineterm present before next token)" )); |
| 74700 | } else { |
| 74701 | DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT); |
| 74702 | DUK_WO_NORETURN(return;); |
| 74703 | } |
| 74704 | } |
| 74705 | } else { |
| 74706 | DUK_DDD(DUK_DDDPRINT("statement has no terminator" )); |
| 74707 | } |
| 74708 | |
| 74709 | /* |
| 74710 | * Directive prologue tracking. |
| 74711 | */ |
| 74712 | |
| 74713 | if (stmt_flags & DUK__STILL_PROLOGUE) { |
| 74714 | DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue" )); |
| 74715 | comp_ctx->curr_func.in_directive_prologue = 1; |
| 74716 | } |
| 74717 | |
| 74718 | /* |
| 74719 | * Cleanups (all statement parsing flows through here). |
| 74720 | * |
| 74721 | * Pop label site and reset labels. Reset 'next temp' to value at |
| 74722 | * entry to reuse temps. |
| 74723 | */ |
| 74724 | |
| 74725 | if (label_id >= 0) { |
| 74726 | duk__emit_bc(comp_ctx, |
| 74727 | DUK_OP_ENDLABEL, |
| 74728 | (duk_regconst_t) label_id); |
| 74729 | } |
| 74730 | |
| 74731 | DUK__SETTEMP(comp_ctx, temp_at_entry); |
| 74732 | |
| 74733 | duk__reset_labels_to_length(comp_ctx, labels_len_at_entry); |
| 74734 | |
| 74735 | /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */ |
| 74736 | |
| 74737 | DUK__RECURSION_DECREASE(comp_ctx, thr); |
| 74738 | } |
| 74739 | |
| 74740 | /* |
| 74741 | * Parse a statement list. |
| 74742 | * |
| 74743 | * Handles automatic semicolon insertion and implicit return value. |
| 74744 | * |
| 74745 | * Upon entry, 'curr_tok' should contain the first token of the first |
| 74746 | * statement (parsed in the "allow regexp literal" mode). Upon exit, |
| 74747 | * 'curr_tok' contains the token following the statement list terminator |
| 74748 | * (EOF or closing brace). |
| 74749 | */ |
| 74750 | |
| 74751 | DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof, duk_bool_t regexp_after) { |
| 74752 | duk_hthread *thr = comp_ctx->thr; |
| 74753 | duk_ivalue res_alloc; |
| 74754 | duk_ivalue *res = &res_alloc; |
| 74755 | |
| 74756 | /* Setup state. Initial ivalue is 'undefined'. */ |
| 74757 | |
| 74758 | duk_require_stack(thr, DUK__PARSE_STATEMENTS_SLOTS); |
| 74759 | |
| 74760 | /* XXX: 'res' setup can be moved to function body level; in fact, two 'res' |
| 74761 | * intermediate values suffice for parsing of each function. Nesting is needed |
| 74762 | * for nested functions (which may occur inside expressions). |
| 74763 | */ |
| 74764 | |
| 74765 | duk_memzero(&res_alloc, sizeof(res_alloc)); |
| 74766 | res->t = DUK_IVAL_PLAIN; |
| 74767 | res->x1.t = DUK_ISPEC_VALUE; |
| 74768 | res->x1.valstack_idx = duk_get_top(thr); |
| 74769 | res->x2.valstack_idx = res->x1.valstack_idx + 1; |
| 74770 | duk_push_undefined(thr); |
| 74771 | duk_push_undefined(thr); |
| 74772 | |
| 74773 | /* Parse statements until a closing token (EOF or '}') is found. */ |
| 74774 | |
| 74775 | for (;;) { |
| 74776 | /* Check whether statement list ends. */ |
| 74777 | |
| 74778 | if (expect_eof) { |
| 74779 | if (comp_ctx->curr_token.t == DUK_TOK_EOF) { |
| 74780 | break; |
| 74781 | } |
| 74782 | } else { |
| 74783 | if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) { |
| 74784 | break; |
| 74785 | } |
| 74786 | } |
| 74787 | |
| 74788 | /* Check statement type based on the first token type. |
| 74789 | * |
| 74790 | * Note: expression parsing helpers expect 'curr_tok' to |
| 74791 | * contain the first token of the expression upon entry. |
| 74792 | */ |
| 74793 | |
| 74794 | DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)" , (long) comp_ctx->curr_token.t)); |
| 74795 | |
| 74796 | duk__parse_stmt(comp_ctx, res, allow_source_elem); |
| 74797 | } |
| 74798 | |
| 74799 | /* RegExp is allowed / not allowed depending on context. For function |
| 74800 | * declarations RegExp is allowed because it follows a function |
| 74801 | * declaration statement and may appear as part of the next statement. |
| 74802 | * For function expressions RegExp is not allowed, and it's possible |
| 74803 | * to do something like '(function () {} / 123)'. |
| 74804 | */ |
| 74805 | if (regexp_after) { |
| 74806 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 74807 | } |
| 74808 | duk__advance(comp_ctx); |
| 74809 | |
| 74810 | /* Tear down state. */ |
| 74811 | |
| 74812 | duk_pop_2(thr); |
| 74813 | } |
| 74814 | |
| 74815 | /* |
| 74816 | * Declaration binding instantiation conceptually happens when calling a |
| 74817 | * function; for us it essentially means that function prologue. The |
| 74818 | * conceptual process is described in E5 Section 10.5. |
| 74819 | * |
| 74820 | * We need to keep track of all encountered identifiers to (1) create an |
| 74821 | * identifier-to-register map ("varmap"); and (2) detect duplicate |
| 74822 | * declarations. Identifiers which are not bound to registers still need |
| 74823 | * to be tracked for detecting duplicates. Currently such identifiers |
| 74824 | * are put into the varmap with a 'null' value, which is later cleaned up. |
| 74825 | * |
| 74826 | * To support functions with a large number of variable and function |
| 74827 | * declarations, registers are not allocated beyond a certain limit; |
| 74828 | * after that limit, variables and functions need slow path access. |
| 74829 | * Arguments are currently always register bound, which imposes a hard |
| 74830 | * (and relatively small) argument count limit. |
| 74831 | * |
| 74832 | * Some bindings in E5 are not configurable (= deletable) and almost all |
| 74833 | * are mutable (writable). Exceptions are: |
| 74834 | * |
| 74835 | * - The 'arguments' binding, established only if no shadowing argument |
| 74836 | * or function declaration exists. We handle 'arguments' creation |
| 74837 | * and binding through an explicit slow path environment record. |
| 74838 | * |
| 74839 | * - The "name" binding for a named function expression. This is also |
| 74840 | * handled through an explicit slow path environment record. |
| 74841 | */ |
| 74842 | |
| 74843 | /* XXX: add support for variables to not be register bound always, to |
| 74844 | * handle cases with a very large number of variables? |
| 74845 | */ |
| 74846 | |
| 74847 | DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg) { |
| 74848 | duk_hthread *thr = comp_ctx->thr; |
| 74849 | duk_hstring *h_name; |
| 74850 | duk_bool_t configurable_bindings; |
| 74851 | duk_uarridx_t num_args; |
| 74852 | duk_uarridx_t num_decls; |
| 74853 | duk_regconst_t rc_name; |
| 74854 | duk_small_uint_t declvar_flags; |
| 74855 | duk_uarridx_t i; |
| 74856 | #if defined(DUK_USE_ASSERTIONS) |
| 74857 | duk_idx_t entry_top; |
| 74858 | #endif |
| 74859 | |
| 74860 | #if defined(DUK_USE_ASSERTIONS) |
| 74861 | entry_top = duk_get_top(thr); |
| 74862 | #endif |
| 74863 | |
| 74864 | /* |
| 74865 | * Preliminaries |
| 74866 | */ |
| 74867 | |
| 74868 | configurable_bindings = comp_ctx->curr_func.is_eval; |
| 74869 | DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld" , (long) configurable_bindings)); |
| 74870 | |
| 74871 | /* varmap is already in comp_ctx->curr_func.varmap_idx */ |
| 74872 | |
| 74873 | /* |
| 74874 | * Function formal arguments, always bound to registers |
| 74875 | * (there's no support for shuffling them now). |
| 74876 | */ |
| 74877 | |
| 74878 | num_args = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx); |
| 74879 | DUK_DDD(DUK_DDDPRINT("num_args=%ld" , (long) num_args)); |
| 74880 | /* XXX: check num_args */ |
| 74881 | |
| 74882 | for (i = 0; i < num_args; i++) { |
| 74883 | duk_get_prop_index(thr, comp_ctx->curr_func.argnames_idx, i); |
| 74884 | h_name = duk_known_hstring(thr, -1); |
| 74885 | |
| 74886 | if (comp_ctx->curr_func.is_strict) { |
| 74887 | if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) { |
| 74888 | DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError" )); |
| 74889 | goto error_argname; |
| 74890 | } |
| 74891 | duk_dup_top(thr); |
| 74892 | if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) { |
| 74893 | DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError" )); |
| 74894 | goto error_argname; |
| 74895 | } |
| 74896 | |
| 74897 | /* Ensure argument name is not a reserved word in current |
| 74898 | * (final) strictness. Formal argument parsing may not |
| 74899 | * catch reserved names if strictness changes during |
| 74900 | * parsing. |
| 74901 | * |
| 74902 | * We only need to do this in strict mode because non-strict |
| 74903 | * keyword are always detected in formal argument parsing. |
| 74904 | */ |
| 74905 | |
| 74906 | if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) { |
| 74907 | goto error_argname; |
| 74908 | } |
| 74909 | } |
| 74910 | |
| 74911 | /* overwrite any previous binding of the same name; the effect is |
| 74912 | * that last argument of a certain name wins. |
| 74913 | */ |
| 74914 | |
| 74915 | /* only functions can have arguments */ |
| 74916 | DUK_ASSERT(comp_ctx->curr_func.is_function); |
| 74917 | duk_push_uarridx(thr, i); /* -> [ ... name index ] */ |
| 74918 | duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */ |
| 74919 | |
| 74920 | /* no code needs to be emitted, the regs already have values */ |
| 74921 | } |
| 74922 | |
| 74923 | /* use temp_next for tracking register allocations */ |
| 74924 | DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_regconst_t) num_args); |
| 74925 | |
| 74926 | /* |
| 74927 | * After arguments, allocate special registers (like shuffling temps) |
| 74928 | */ |
| 74929 | |
| 74930 | if (out_stmt_value_reg) { |
| 74931 | *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx); |
| 74932 | } |
| 74933 | if (comp_ctx->curr_func.needs_shuffle) { |
| 74934 | duk_regconst_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3); |
| 74935 | comp_ctx->curr_func.shuffle1 = shuffle_base; |
| 74936 | comp_ctx->curr_func.shuffle2 = shuffle_base + 1; |
| 74937 | comp_ctx->curr_func.shuffle3 = shuffle_base + 2; |
| 74938 | DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld" , |
| 74939 | (long) comp_ctx->curr_func.shuffle1, |
| 74940 | (long) comp_ctx->curr_func.shuffle2, |
| 74941 | (long) comp_ctx->curr_func.shuffle3)); |
| 74942 | } |
| 74943 | if (comp_ctx->curr_func.temp_next > 0x100) { |
| 74944 | DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld" , (long) comp_ctx->curr_func.temp_next)); |
| 74945 | goto error_outofregs; |
| 74946 | } |
| 74947 | |
| 74948 | /* |
| 74949 | * Function declarations |
| 74950 | */ |
| 74951 | |
| 74952 | num_decls = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx); |
| 74953 | DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T" , |
| 74954 | (long) num_decls, |
| 74955 | (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.decls_idx))); |
| 74956 | for (i = 0; i < num_decls; i += 2) { |
| 74957 | duk_int_t decl_type; |
| 74958 | duk_int_t fnum; |
| 74959 | |
| 74960 | duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */ |
| 74961 | decl_type = duk_to_int(thr, -1); |
| 74962 | fnum = decl_type >> 8; /* XXX: macros */ |
| 74963 | decl_type = decl_type & 0xff; |
| 74964 | duk_pop(thr); |
| 74965 | |
| 74966 | if (decl_type != DUK_DECL_TYPE_FUNC) { |
| 74967 | continue; |
| 74968 | } |
| 74969 | |
| 74970 | duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */ |
| 74971 | |
| 74972 | /* XXX: spilling */ |
| 74973 | if (comp_ctx->curr_func.is_function) { |
| 74974 | duk_regconst_t reg_bind; |
| 74975 | duk_dup_top(thr); |
| 74976 | if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) { |
| 74977 | /* shadowed; update value */ |
| 74978 | duk_dup_top(thr); |
| 74979 | duk_get_prop(thr, comp_ctx->curr_func.varmap_idx); |
| 74980 | reg_bind = duk_to_int(thr, -1); /* [ ... name reg_bind ] */ |
| 74981 | duk__emit_a_bc(comp_ctx, |
| 74982 | DUK_OP_CLOSURE, |
| 74983 | reg_bind, |
| 74984 | (duk_regconst_t) fnum); |
| 74985 | } else { |
| 74986 | /* function: always register bound */ |
| 74987 | reg_bind = DUK__ALLOCTEMP(comp_ctx); |
| 74988 | duk__emit_a_bc(comp_ctx, |
| 74989 | DUK_OP_CLOSURE, |
| 74990 | reg_bind, |
| 74991 | (duk_regconst_t) fnum); |
| 74992 | duk_push_int(thr, (duk_int_t) reg_bind); |
| 74993 | } |
| 74994 | } else { |
| 74995 | /* Function declaration for global/eval code is emitted even |
| 74996 | * for duplicates, because of E5 Section 10.5, step 5.e of |
| 74997 | * E5.1 (special behavior for variable bound to global object). |
| 74998 | * |
| 74999 | * DECLVAR will not re-declare a variable as such, but will |
| 75000 | * update the binding value. |
| 75001 | */ |
| 75002 | |
| 75003 | duk_regconst_t reg_temp = DUK__ALLOCTEMP(comp_ctx); |
| 75004 | duk_dup_top(thr); |
| 75005 | rc_name = duk__getconst(comp_ctx); |
| 75006 | duk_push_null(thr); |
| 75007 | |
| 75008 | duk__emit_a_bc(comp_ctx, |
| 75009 | DUK_OP_CLOSURE, |
| 75010 | reg_temp, |
| 75011 | (duk_regconst_t) fnum); |
| 75012 | |
| 75013 | declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | |
| 75014 | DUK_PROPDESC_FLAG_ENUMERABLE | |
| 75015 | DUK_BC_DECLVAR_FLAG_FUNC_DECL; |
| 75016 | |
| 75017 | if (configurable_bindings) { |
| 75018 | declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 75019 | } |
| 75020 | |
| 75021 | duk__emit_a_b_c(comp_ctx, |
| 75022 | DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST, |
| 75023 | (duk_regconst_t) declvar_flags /*flags*/, |
| 75024 | rc_name /*name*/, |
| 75025 | reg_temp /*value*/); |
| 75026 | |
| 75027 | DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */ |
| 75028 | } |
| 75029 | |
| 75030 | DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T" , |
| 75031 | (duk_tval *) duk_get_tval(thr, -2), |
| 75032 | (duk_tval *) duk_get_tval(thr, -1))); |
| 75033 | |
| 75034 | #if defined(DUK_USE_FASTINT) |
| 75035 | DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(thr, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(thr, -1))); |
| 75036 | #endif |
| 75037 | duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ |
| 75038 | } |
| 75039 | |
| 75040 | /* |
| 75041 | * 'arguments' binding is special; if a shadowing argument or |
| 75042 | * function declaration exists, an arguments object will |
| 75043 | * definitely not be needed, regardless of whether the identifier |
| 75044 | * 'arguments' is referenced inside the function body. |
| 75045 | */ |
| 75046 | |
| 75047 | if (duk_has_prop_stridx(thr, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) { |
| 75048 | DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration " |
| 75049 | "-> arguments object creation can be skipped" )); |
| 75050 | comp_ctx->curr_func.is_arguments_shadowed = 1; |
| 75051 | } |
| 75052 | |
| 75053 | /* |
| 75054 | * Variable declarations. |
| 75055 | * |
| 75056 | * Unlike function declarations, variable declaration values don't get |
| 75057 | * assigned on entry. If a binding of the same name already exists, just |
| 75058 | * ignore it silently. |
| 75059 | */ |
| 75060 | |
| 75061 | for (i = 0; i < num_decls; i += 2) { |
| 75062 | duk_int_t decl_type; |
| 75063 | |
| 75064 | duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */ |
| 75065 | decl_type = duk_to_int(thr, -1); |
| 75066 | decl_type = decl_type & 0xff; |
| 75067 | duk_pop(thr); |
| 75068 | |
| 75069 | if (decl_type != DUK_DECL_TYPE_VAR) { |
| 75070 | continue; |
| 75071 | } |
| 75072 | |
| 75073 | duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */ |
| 75074 | |
| 75075 | if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) { |
| 75076 | /* shadowed, ignore */ |
| 75077 | } else { |
| 75078 | duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i); /* decl name */ |
| 75079 | h_name = duk_known_hstring(thr, -1); |
| 75080 | |
| 75081 | if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) && |
| 75082 | !comp_ctx->curr_func.is_arguments_shadowed) { |
| 75083 | /* E5 Section steps 7-8 */ |
| 75084 | DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, " |
| 75085 | "but appears as a variable declaration -> treat as " |
| 75086 | "a no-op for variable declaration purposes" )); |
| 75087 | duk_pop(thr); |
| 75088 | continue; |
| 75089 | } |
| 75090 | |
| 75091 | /* XXX: spilling */ |
| 75092 | if (comp_ctx->curr_func.is_function) { |
| 75093 | duk_regconst_t reg_bind = DUK__ALLOCTEMP(comp_ctx); |
| 75094 | /* no need to init reg, it will be undefined on entry */ |
| 75095 | duk_push_int(thr, (duk_int_t) reg_bind); |
| 75096 | } else { |
| 75097 | duk_dup_top(thr); |
| 75098 | rc_name = duk__getconst(comp_ctx); |
| 75099 | duk_push_null(thr); |
| 75100 | |
| 75101 | declvar_flags = DUK_PROPDESC_FLAG_WRITABLE | |
| 75102 | DUK_PROPDESC_FLAG_ENUMERABLE; |
| 75103 | if (configurable_bindings) { |
| 75104 | declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE; |
| 75105 | } |
| 75106 | |
| 75107 | duk__emit_a_b_c(comp_ctx, |
| 75108 | DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST, |
| 75109 | (duk_regconst_t) declvar_flags /*flags*/, |
| 75110 | rc_name /*name*/, |
| 75111 | 0 /*value*/); |
| 75112 | } |
| 75113 | |
| 75114 | duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */ |
| 75115 | } |
| 75116 | } |
| 75117 | |
| 75118 | /* |
| 75119 | * Wrap up |
| 75120 | */ |
| 75121 | |
| 75122 | DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld" , |
| 75123 | (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx), |
| 75124 | (long) comp_ctx->curr_func.is_arguments_shadowed)); |
| 75125 | |
| 75126 | DUK_ASSERT_TOP(thr, entry_top); |
| 75127 | return; |
| 75128 | |
| 75129 | error_outofregs: |
| 75130 | DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT); |
| 75131 | DUK_WO_NORETURN(return;); |
| 75132 | |
| 75133 | error_argname: |
| 75134 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME); |
| 75135 | DUK_WO_NORETURN(return;); |
| 75136 | } |
| 75137 | |
| 75138 | /* |
| 75139 | * Parse a function-body-like expression (FunctionBody or Program |
| 75140 | * in E5 grammar) using a two-pass parse. The productions appear |
| 75141 | * in the following contexts: |
| 75142 | * |
| 75143 | * - function expression |
| 75144 | * - function statement |
| 75145 | * - function declaration |
| 75146 | * - getter in object literal |
| 75147 | * - setter in object literal |
| 75148 | * - global code |
| 75149 | * - eval code |
| 75150 | * - Function constructor body |
| 75151 | * |
| 75152 | * This function only parses the statement list of the body; the argument |
| 75153 | * list and possible function name must be initialized by the caller. |
| 75154 | * For instance, for Function constructor, the argument names are originally |
| 75155 | * on the value stack. The parsing of statements ends either at an EOF or |
| 75156 | * a closing brace; this is controlled by an input flag. |
| 75157 | * |
| 75158 | * Note that there are many differences affecting parsing and even code |
| 75159 | * generation: |
| 75160 | * |
| 75161 | * - Global and eval code have an implicit return value generated |
| 75162 | * by the last statement; function code does not |
| 75163 | * |
| 75164 | * - Global code, eval code, and Function constructor body end in |
| 75165 | * an EOF, other bodies in a closing brace ('}') |
| 75166 | * |
| 75167 | * Upon entry, 'curr_tok' is ignored and the function will pull in the |
| 75168 | * first token on its own. Upon exit, 'curr_tok' is the terminating |
| 75169 | * token (EOF or closing brace). |
| 75170 | */ |
| 75171 | |
| 75172 | DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_bool_t regexp_after, duk_small_int_t expect_token) { |
| 75173 | duk_compiler_func *func; |
| 75174 | duk_hthread *thr; |
| 75175 | duk_regconst_t reg_stmt_value = -1; |
| 75176 | duk_lexer_point lex_pt; |
| 75177 | duk_regconst_t temp_first; |
| 75178 | duk_small_int_t compile_round = 1; |
| 75179 | |
| 75180 | DUK_ASSERT(comp_ctx != NULL); |
| 75181 | |
| 75182 | thr = comp_ctx->thr; |
| 75183 | DUK_ASSERT(thr != NULL); |
| 75184 | |
| 75185 | func = &comp_ctx->curr_func; |
| 75186 | DUK_ASSERT(func != NULL); |
| 75187 | |
| 75188 | DUK__RECURSION_INCREASE(comp_ctx, thr); |
| 75189 | |
| 75190 | duk_require_stack(thr, DUK__FUNCTION_BODY_REQUIRE_SLOTS); |
| 75191 | |
| 75192 | /* |
| 75193 | * Store lexer position for a later rewind |
| 75194 | */ |
| 75195 | |
| 75196 | DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt); |
| 75197 | |
| 75198 | /* |
| 75199 | * Program code (global and eval code) has an implicit return value |
| 75200 | * from the last statement value (e.g. eval("1; 2+3;") returns 3). |
| 75201 | * This is not the case with functions. If implicit statement return |
| 75202 | * value is requested, all statements are coerced to a register |
| 75203 | * allocated here, and used in the implicit return statement below. |
| 75204 | */ |
| 75205 | |
| 75206 | /* XXX: this is pointless here because pass 1 is throw-away */ |
| 75207 | if (implicit_return_value) { |
| 75208 | reg_stmt_value = DUK__ALLOCTEMP(comp_ctx); |
| 75209 | |
| 75210 | /* If an implicit return value is needed by caller, it must be |
| 75211 | * initialized to 'undefined' because we don't know whether any |
| 75212 | * non-empty (where "empty" is a continuation type, and different |
| 75213 | * from an empty statement) statements will be executed. |
| 75214 | * |
| 75215 | * However, since 1st pass is a throwaway one, no need to emit |
| 75216 | * it here. |
| 75217 | */ |
| 75218 | #if 0 |
| 75219 | duk__emit_bc(comp_ctx, |
| 75220 | DUK_OP_LDUNDEF, |
| 75221 | 0); |
| 75222 | #endif |
| 75223 | } |
| 75224 | |
| 75225 | /* |
| 75226 | * First pass. |
| 75227 | * |
| 75228 | * Gather variable/function declarations needed for second pass. |
| 75229 | * Code generated is dummy and discarded. |
| 75230 | */ |
| 75231 | |
| 75232 | func->in_directive_prologue = 1; |
| 75233 | func->in_scanning = 1; |
| 75234 | func->may_direct_eval = 0; |
| 75235 | func->id_access_arguments = 0; |
| 75236 | func->id_access_slow = 0; |
| 75237 | func->id_access_slow_own = 0; |
| 75238 | func->reg_stmt_value = reg_stmt_value; |
| 75239 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 75240 | func->min_line = DUK_INT_MAX; |
| 75241 | func->max_line = 0; |
| 75242 | #endif |
| 75243 | |
| 75244 | /* duk__parse_stmts() expects curr_tok to be set; parse in "allow |
| 75245 | * regexp literal" mode with current strictness. |
| 75246 | */ |
| 75247 | if (expect_token >= 0) { |
| 75248 | /* Eating a left curly; regexp mode is allowed by left curly |
| 75249 | * based on duk__token_lbp[] automatically. |
| 75250 | */ |
| 75251 | DUK_ASSERT(expect_token == DUK_TOK_LCURLY); |
| 75252 | duk__update_lineinfo_currtoken(comp_ctx); |
| 75253 | duk__advance_expect(comp_ctx, expect_token); |
| 75254 | } else { |
| 75255 | /* Need to set curr_token.t because lexing regexp mode depends on current |
| 75256 | * token type. Zero value causes "allow regexp" mode. |
| 75257 | */ |
| 75258 | comp_ctx->curr_token.t = 0; |
| 75259 | duk__advance(comp_ctx); |
| 75260 | } |
| 75261 | |
| 75262 | DUK_DDD(DUK_DDDPRINT("begin 1st pass" )); |
| 75263 | duk__parse_stmts(comp_ctx, |
| 75264 | 1, /* allow source elements */ |
| 75265 | expect_eof, /* expect EOF instead of } */ |
| 75266 | regexp_after); /* regexp after */ |
| 75267 | DUK_DDD(DUK_DDDPRINT("end 1st pass" )); |
| 75268 | |
| 75269 | /* |
| 75270 | * Second (and possibly third) pass. |
| 75271 | * |
| 75272 | * Generate actual code. In most cases the need for shuffle |
| 75273 | * registers is detected during pass 1, but in some corner cases |
| 75274 | * we'll only detect it during pass 2 and a third pass is then |
| 75275 | * needed (see GH-115). |
| 75276 | */ |
| 75277 | |
| 75278 | for (;;) { |
| 75279 | duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle; |
| 75280 | compile_round++; |
| 75281 | |
| 75282 | /* |
| 75283 | * Rewind lexer. |
| 75284 | * |
| 75285 | * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp |
| 75286 | * literal" mode with current strictness. |
| 75287 | * |
| 75288 | * curr_token line number info should be initialized for pass 2 before |
| 75289 | * generating prologue, to ensure prologue bytecode gets nice line numbers. |
| 75290 | */ |
| 75291 | |
| 75292 | DUK_DDD(DUK_DDDPRINT("rewind lexer" )); |
| 75293 | DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt); |
| 75294 | comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */ |
| 75295 | comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */ |
| 75296 | duk__advance(comp_ctx); |
| 75297 | |
| 75298 | /* |
| 75299 | * Reset function state and perform register allocation, which creates |
| 75300 | * 'varmap' for second pass. Function prologue for variable declarations, |
| 75301 | * binding value initializations etc is emitted as a by-product. |
| 75302 | * |
| 75303 | * Strict mode restrictions for duplicate and invalid argument |
| 75304 | * names are checked here now that we know whether the function |
| 75305 | * is actually strict. See: test-dev-strict-mode-boundary.js. |
| 75306 | * |
| 75307 | * Inner functions are compiled during pass 1 and are not reset. |
| 75308 | */ |
| 75309 | |
| 75310 | duk__reset_func_for_pass2(comp_ctx); |
| 75311 | func->in_directive_prologue = 1; |
| 75312 | func->in_scanning = 0; |
| 75313 | |
| 75314 | /* must be able to emit code, alloc consts, etc. */ |
| 75315 | |
| 75316 | duk__init_varmap_and_prologue_for_pass2(comp_ctx, |
| 75317 | (implicit_return_value ? ®_stmt_value : NULL)); |
| 75318 | func->reg_stmt_value = reg_stmt_value; |
| 75319 | |
| 75320 | temp_first = DUK__GETTEMP(comp_ctx); |
| 75321 | |
| 75322 | func->temp_first = temp_first; |
| 75323 | func->temp_next = temp_first; |
| 75324 | func->stmt_next = 0; |
| 75325 | func->label_next = 0; |
| 75326 | |
| 75327 | /* XXX: init or assert catch depth etc -- all values */ |
| 75328 | func->id_access_arguments = 0; |
| 75329 | func->id_access_slow = 0; |
| 75330 | func->id_access_slow_own = 0; |
| 75331 | |
| 75332 | /* |
| 75333 | * Check function name validity now that we know strictness. |
| 75334 | * This only applies to function declarations and expressions, |
| 75335 | * not setter/getter name. |
| 75336 | * |
| 75337 | * See: test-dev-strict-mode-boundary.js |
| 75338 | */ |
| 75339 | |
| 75340 | if (func->is_function && !func->is_setget && func->h_name != NULL) { |
| 75341 | if (func->is_strict) { |
| 75342 | if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) { |
| 75343 | DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode" )); |
| 75344 | goto error_funcname; |
| 75345 | } |
| 75346 | if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) { |
| 75347 | DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode" )); |
| 75348 | goto error_funcname; |
| 75349 | } |
| 75350 | } else { |
| 75351 | if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) && |
| 75352 | !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) { |
| 75353 | DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode" )); |
| 75354 | goto error_funcname; |
| 75355 | } |
| 75356 | } |
| 75357 | } |
| 75358 | |
| 75359 | /* |
| 75360 | * Second pass parsing. |
| 75361 | */ |
| 75362 | |
| 75363 | if (implicit_return_value) { |
| 75364 | /* Default implicit return value. */ |
| 75365 | duk__emit_bc(comp_ctx, |
| 75366 | DUK_OP_LDUNDEF, |
| 75367 | 0); |
| 75368 | } |
| 75369 | |
| 75370 | DUK_DDD(DUK_DDDPRINT("begin 2nd pass" )); |
| 75371 | duk__parse_stmts(comp_ctx, |
| 75372 | 1, /* allow source elements */ |
| 75373 | expect_eof, /* expect EOF instead of } */ |
| 75374 | regexp_after); /* regexp after */ |
| 75375 | DUK_DDD(DUK_DDDPRINT("end 2nd pass" )); |
| 75376 | |
| 75377 | duk__update_lineinfo_currtoken(comp_ctx); |
| 75378 | |
| 75379 | if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) { |
| 75380 | /* Shuffle decision not changed. */ |
| 75381 | break; |
| 75382 | } |
| 75383 | if (compile_round >= 3) { |
| 75384 | /* Should never happen but avoid infinite loop just in case. */ |
| 75385 | DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen" )); |
| 75386 | DUK_ERROR_INTERNAL(thr); |
| 75387 | DUK_WO_NORETURN(return;); |
| 75388 | } |
| 75389 | DUK_D(DUK_DPRINT("need additional round to compile function, round now %d" , (int) compile_round)); |
| 75390 | } |
| 75391 | |
| 75392 | /* |
| 75393 | * Emit a final RETURN. |
| 75394 | * |
| 75395 | * It would be nice to avoid emitting an unnecessary "return" opcode |
| 75396 | * if the current PC is not reachable. However, this cannot be reliably |
| 75397 | * detected; even if the previous instruction is an unconditional jump, |
| 75398 | * there may be a previous jump which jumps to current PC (which is the |
| 75399 | * case for iteration and conditional statements, for instance). |
| 75400 | */ |
| 75401 | |
| 75402 | /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts(); |
| 75403 | * we could avoid the last RETURN if we could ensure there is no way to get here |
| 75404 | * (directly or via a jump) |
| 75405 | */ |
| 75406 | |
| 75407 | DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0); |
| 75408 | if (reg_stmt_value >= 0) { |
| 75409 | DUK_ASSERT(DUK__ISREG(reg_stmt_value)); |
| 75410 | duk__emit_bc(comp_ctx, DUK_OP_RETREG, reg_stmt_value /*reg*/); |
| 75411 | } else { |
| 75412 | duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF); |
| 75413 | } |
| 75414 | |
| 75415 | /* |
| 75416 | * Peephole optimize JUMP chains. |
| 75417 | */ |
| 75418 | |
| 75419 | duk__peephole_optimize_bytecode(comp_ctx); |
| 75420 | |
| 75421 | /* |
| 75422 | * comp_ctx->curr_func is now ready to be converted into an actual |
| 75423 | * function template. |
| 75424 | */ |
| 75425 | |
| 75426 | DUK__RECURSION_DECREASE(comp_ctx, thr); |
| 75427 | return; |
| 75428 | |
| 75429 | error_funcname: |
| 75430 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME); |
| 75431 | DUK_WO_NORETURN(return;); |
| 75432 | } |
| 75433 | |
| 75434 | /* |
| 75435 | * Parse a function-like expression: |
| 75436 | * |
| 75437 | * - function expression |
| 75438 | * - function declaration |
| 75439 | * - function statement (non-standard) |
| 75440 | * - setter/getter |
| 75441 | * |
| 75442 | * Adds the function to comp_ctx->curr_func function table and returns the |
| 75443 | * function number. |
| 75444 | * |
| 75445 | * On entry, curr_token points to: |
| 75446 | * |
| 75447 | * - the token after 'function' for function expression/declaration/statement |
| 75448 | * - the token after 'set' or 'get' for setter/getter |
| 75449 | */ |
| 75450 | |
| 75451 | /* Parse formals. */ |
| 75452 | DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) { |
| 75453 | duk_hthread *thr = comp_ctx->thr; |
| 75454 | duk_bool_t first = 1; |
| 75455 | duk_uarridx_t n; |
| 75456 | |
| 75457 | for (;;) { |
| 75458 | if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) { |
| 75459 | break; |
| 75460 | } |
| 75461 | |
| 75462 | if (first) { |
| 75463 | /* no comma */ |
| 75464 | first = 0; |
| 75465 | } else { |
| 75466 | duk__advance_expect(comp_ctx, DUK_TOK_COMMA); |
| 75467 | } |
| 75468 | |
| 75469 | /* Note: when parsing a formal list in non-strict context, e.g. |
| 75470 | * "implements" is parsed as an identifier. When the function is |
| 75471 | * later detected to be strict, the argument list must be rechecked |
| 75472 | * against a larger set of reserved words (that of strict mode). |
| 75473 | * This is handled by duk__parse_func_body(). Here we recognize |
| 75474 | * whatever tokens are considered reserved in current strictness |
| 75475 | * (which is not always enough). |
| 75476 | */ |
| 75477 | |
| 75478 | if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) { |
| 75479 | DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER); |
| 75480 | DUK_WO_NORETURN(return;); |
| 75481 | } |
| 75482 | DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER); |
| 75483 | DUK_ASSERT(comp_ctx->curr_token.str1 != NULL); |
| 75484 | DUK_DDD(DUK_DDDPRINT("formal argument: %!O" , |
| 75485 | (duk_heaphdr *) comp_ctx->curr_token.str1)); |
| 75486 | |
| 75487 | /* XXX: append primitive */ |
| 75488 | duk_push_hstring(thr, comp_ctx->curr_token.str1); |
| 75489 | n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx); |
| 75490 | duk_put_prop_index(thr, comp_ctx->curr_func.argnames_idx, n); |
| 75491 | |
| 75492 | duk__advance(comp_ctx); /* eat identifier */ |
| 75493 | } |
| 75494 | } |
| 75495 | |
| 75496 | /* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is |
| 75497 | * correctly set up. Assumes that curr_token is just after 'function' (or |
| 75498 | * 'set'/'get' etc). |
| 75499 | */ |
| 75500 | DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) { |
| 75501 | duk_hthread *thr = comp_ctx->thr; |
| 75502 | duk_token *tok; |
| 75503 | duk_bool_t no_advance; |
| 75504 | |
| 75505 | DUK_ASSERT(comp_ctx->curr_func.num_formals == 0); |
| 75506 | DUK_ASSERT(comp_ctx->curr_func.is_function == 1); |
| 75507 | DUK_ASSERT(comp_ctx->curr_func.is_eval == 0); |
| 75508 | DUK_ASSERT(comp_ctx->curr_func.is_global == 0); |
| 75509 | DUK_ASSERT(comp_ctx->curr_func.is_setget == ((flags & DUK__FUNC_FLAG_GETSET) != 0)); |
| 75510 | |
| 75511 | duk__update_lineinfo_currtoken(comp_ctx); |
| 75512 | |
| 75513 | /* |
| 75514 | * Function name (if any) |
| 75515 | * |
| 75516 | * We don't check for prohibited names here, because we don't |
| 75517 | * yet know whether the function will be strict. Function body |
| 75518 | * parsing handles this retroactively. |
| 75519 | * |
| 75520 | * For function expressions and declarations function name must |
| 75521 | * be an Identifer (excludes reserved words). For setter/getter |
| 75522 | * it is a PropertyName which allows reserved words and also |
| 75523 | * strings and numbers (e.g. "{ get 1() { ... } }"). |
| 75524 | * |
| 75525 | * Function parsing may start either from prev_token or curr_token |
| 75526 | * (object literal method definition uses prev_token for example). |
| 75527 | * This is dealt with for the initial token. |
| 75528 | */ |
| 75529 | |
| 75530 | no_advance = (flags & DUK__FUNC_FLAG_USE_PREVTOKEN); |
| 75531 | if (no_advance) { |
| 75532 | tok = &comp_ctx->prev_token; |
| 75533 | } else { |
| 75534 | tok = &comp_ctx->curr_token; |
| 75535 | } |
| 75536 | |
| 75537 | if (flags & DUK__FUNC_FLAG_GETSET) { |
| 75538 | /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */ |
| 75539 | if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t == DUK_TOK_STRING) { |
| 75540 | duk_push_hstring(thr, tok->str1); /* keep in valstack */ |
| 75541 | } else if (tok->t == DUK_TOK_NUMBER) { |
| 75542 | duk_push_number(thr, tok->num); |
| 75543 | duk_to_string(thr, -1); |
| 75544 | } else { |
| 75545 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME); |
| 75546 | DUK_WO_NORETURN(return;); |
| 75547 | } |
| 75548 | comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */ |
| 75549 | } else { |
| 75550 | /* Function name is an Identifier (not IdentifierName), but we get |
| 75551 | * the raw name (not recognizing keywords) here and perform the name |
| 75552 | * checks only after pass 1. |
| 75553 | */ |
| 75554 | if (tok->t_nores == DUK_TOK_IDENTIFIER) { |
| 75555 | duk_push_hstring(thr, tok->str1); /* keep in valstack */ |
| 75556 | comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1); /* borrowed reference */ |
| 75557 | } else { |
| 75558 | /* valstack will be unbalanced, which is OK */ |
| 75559 | DUK_ASSERT((flags & DUK__FUNC_FLAG_GETSET) == 0); |
| 75560 | DUK_ASSERT(comp_ctx->curr_func.h_name == NULL); |
| 75561 | no_advance = 1; |
| 75562 | if (flags & DUK__FUNC_FLAG_DECL) { |
| 75563 | DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED); |
| 75564 | DUK_WO_NORETURN(return;); |
| 75565 | } |
| 75566 | } |
| 75567 | } |
| 75568 | |
| 75569 | DUK_DD(DUK_DDPRINT("function name: %!O" , |
| 75570 | (duk_heaphdr *) comp_ctx->curr_func.h_name)); |
| 75571 | |
| 75572 | if (!no_advance) { |
| 75573 | duk__advance(comp_ctx); |
| 75574 | } |
| 75575 | |
| 75576 | /* |
| 75577 | * Formal argument list |
| 75578 | * |
| 75579 | * We don't check for prohibited names or for duplicate argument |
| 75580 | * names here, becase we don't yet know whether the function will |
| 75581 | * be strict. Function body parsing handles this retroactively. |
| 75582 | */ |
| 75583 | |
| 75584 | duk__advance_expect(comp_ctx, DUK_TOK_LPAREN); |
| 75585 | |
| 75586 | duk__parse_func_formals(comp_ctx); |
| 75587 | |
| 75588 | DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN); |
| 75589 | duk__advance(comp_ctx); |
| 75590 | |
| 75591 | /* |
| 75592 | * Parse function body |
| 75593 | */ |
| 75594 | |
| 75595 | duk__parse_func_body(comp_ctx, |
| 75596 | 0, /* expect_eof */ |
| 75597 | 0, /* implicit_return_value */ |
| 75598 | flags & DUK__FUNC_FLAG_DECL, /* regexp_after */ |
| 75599 | DUK_TOK_LCURLY); /* expect_token */ |
| 75600 | |
| 75601 | /* |
| 75602 | * Convert duk_compiler_func to a function template and add it |
| 75603 | * to the parent function table. |
| 75604 | */ |
| 75605 | |
| 75606 | duk__convert_to_func_template(comp_ctx); /* -> [ ... func ] */ |
| 75607 | } |
| 75608 | |
| 75609 | /* Parse an inner function, adding the function template to the current function's |
| 75610 | * function table. Return a function number to be used by the outer function. |
| 75611 | * |
| 75612 | * Avoiding O(depth^2) inner function parsing is handled here. On the first pass, |
| 75613 | * compile and register the function normally into the 'funcs' array, also recording |
| 75614 | * a lexer point (offset/line) to the closing brace of the function. On the second |
| 75615 | * pass, skip the function and return the same 'fnum' as on the first pass by using |
| 75616 | * a running counter. |
| 75617 | * |
| 75618 | * An unfortunate side effect of this is that when parsing the inner function, almost |
| 75619 | * nothing is known of the outer function, i.e. the inner function's scope. We don't |
| 75620 | * need that information at the moment, but it would allow some optimizations if it |
| 75621 | * were used. |
| 75622 | */ |
| 75623 | DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) { |
| 75624 | duk_hthread *thr = comp_ctx->thr; |
| 75625 | duk_compiler_func old_func; |
| 75626 | duk_idx_t entry_top; |
| 75627 | duk_int_t fnum; |
| 75628 | |
| 75629 | /* |
| 75630 | * On second pass, skip the function. |
| 75631 | */ |
| 75632 | |
| 75633 | if (!comp_ctx->curr_func.in_scanning) { |
| 75634 | duk_lexer_point lex_pt; |
| 75635 | |
| 75636 | fnum = comp_ctx->curr_func.fnum_next++; |
| 75637 | duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1)); |
| 75638 | lex_pt.offset = (duk_size_t) duk_to_uint(thr, -1); |
| 75639 | duk_pop(thr); |
| 75640 | duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2)); |
| 75641 | lex_pt.line = duk_to_int(thr, -1); |
| 75642 | duk_pop(thr); |
| 75643 | |
| 75644 | DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld" , |
| 75645 | (long) lex_pt.offset, (long) lex_pt.line)); |
| 75646 | |
| 75647 | DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt); |
| 75648 | comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */ |
| 75649 | comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */ |
| 75650 | duk__advance(comp_ctx); |
| 75651 | |
| 75652 | /* RegExp is not allowed after a function expression, e.g. in |
| 75653 | * (function () {} / 123). A RegExp *is* allowed after a |
| 75654 | * function declaration! |
| 75655 | */ |
| 75656 | if (flags & DUK__FUNC_FLAG_DECL) { |
| 75657 | comp_ctx->curr_func.allow_regexp_in_adv = 1; |
| 75658 | } |
| 75659 | duk__advance_expect(comp_ctx, DUK_TOK_RCURLY); |
| 75660 | |
| 75661 | return fnum; |
| 75662 | } |
| 75663 | |
| 75664 | /* |
| 75665 | * On first pass, perform actual parsing. Remember valstack top on entry |
| 75666 | * to restore it later, and switch to using a new function in comp_ctx. |
| 75667 | */ |
| 75668 | |
| 75669 | entry_top = duk_get_top(thr); |
| 75670 | DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld" , |
| 75671 | (long) entry_top, (long) comp_ctx->curr_token.start_offset)); |
| 75672 | |
| 75673 | duk_memcpy(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func)); |
| 75674 | |
| 75675 | duk_memzero(&comp_ctx->curr_func, sizeof(duk_compiler_func)); |
| 75676 | duk__init_func_valstack_slots(comp_ctx); |
| 75677 | DUK_ASSERT(comp_ctx->curr_func.num_formals == 0); |
| 75678 | |
| 75679 | /* inherit initial strictness from parent */ |
| 75680 | comp_ctx->curr_func.is_strict = old_func.is_strict; |
| 75681 | |
| 75682 | /* XXX: It might be better to just store the flags into the curr_func |
| 75683 | * struct and use them as is without this flag interpretation step |
| 75684 | * here. |
| 75685 | */ |
| 75686 | DUK_ASSERT(comp_ctx->curr_func.is_notail == 0); |
| 75687 | comp_ctx->curr_func.is_function = 1; |
| 75688 | DUK_ASSERT(comp_ctx->curr_func.is_eval == 0); |
| 75689 | DUK_ASSERT(comp_ctx->curr_func.is_global == 0); |
| 75690 | comp_ctx->curr_func.is_setget = ((flags & DUK__FUNC_FLAG_GETSET) != 0); |
| 75691 | comp_ctx->curr_func.is_namebinding = !(flags & (DUK__FUNC_FLAG_GETSET | |
| 75692 | DUK__FUNC_FLAG_METDEF | |
| 75693 | DUK__FUNC_FLAG_DECL)); /* no name binding for: declarations, objlit getset, objlit method def */ |
| 75694 | comp_ctx->curr_func.is_constructable = !(flags & (DUK__FUNC_FLAG_GETSET | |
| 75695 | DUK__FUNC_FLAG_METDEF)); /* not constructable: objlit getset, objlit method def */ |
| 75696 | |
| 75697 | /* |
| 75698 | * Parse inner function |
| 75699 | */ |
| 75700 | |
| 75701 | duk__parse_func_like_raw(comp_ctx, flags); /* pushes function template */ |
| 75702 | |
| 75703 | /* prev_token.start_offset points to the closing brace here; when skipping |
| 75704 | * we're going to reparse the closing brace to ensure semicolon insertion |
| 75705 | * etc work as expected. |
| 75706 | */ |
| 75707 | DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld" , |
| 75708 | (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset)); |
| 75709 | DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY); |
| 75710 | |
| 75711 | /* XXX: append primitive */ |
| 75712 | DUK_ASSERT(duk_get_length(thr, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3)); |
| 75713 | fnum = old_func.fnum_next++; |
| 75714 | |
| 75715 | if (fnum > DUK__MAX_FUNCS) { |
| 75716 | DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT); |
| 75717 | DUK_WO_NORETURN(return 0;); |
| 75718 | } |
| 75719 | |
| 75720 | /* array writes autoincrement length */ |
| 75721 | (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3)); |
| 75722 | duk_push_size_t(thr, comp_ctx->prev_token.start_offset); |
| 75723 | (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1)); |
| 75724 | duk_push_int(thr, comp_ctx->prev_token.start_line); |
| 75725 | (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2)); |
| 75726 | |
| 75727 | /* |
| 75728 | * Cleanup: restore original function, restore valstack state. |
| 75729 | * |
| 75730 | * Function declaration handling needs the function name to be pushed |
| 75731 | * on the value stack. |
| 75732 | */ |
| 75733 | |
| 75734 | if (flags & DUK__FUNC_FLAG_PUSHNAME_PASS1) { |
| 75735 | DUK_ASSERT(comp_ctx->curr_func.h_name != NULL); |
| 75736 | duk_push_hstring(thr, comp_ctx->curr_func.h_name); |
| 75737 | duk_replace(thr, entry_top); |
| 75738 | duk_set_top(thr, entry_top + 1); |
| 75739 | } else { |
| 75740 | duk_set_top(thr, entry_top); |
| 75741 | } |
| 75742 | duk_memcpy((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func)); |
| 75743 | |
| 75744 | return fnum; |
| 75745 | } |
| 75746 | |
| 75747 | /* |
| 75748 | * Compile input string into an executable function template without |
| 75749 | * arguments. |
| 75750 | * |
| 75751 | * The string is parsed as the "Program" production of ECMAScript E5. |
| 75752 | * Compilation context can be either global code or eval code (see E5 |
| 75753 | * Sections 14 and 15.1.2.1). |
| 75754 | * |
| 75755 | * Input stack: [ ... filename ] |
| 75756 | * Output stack: [ ... func_template ] |
| 75757 | */ |
| 75758 | |
| 75759 | /* XXX: source code property */ |
| 75760 | |
| 75761 | DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_hthread *thr, void *udata) { |
| 75762 | duk_hstring *h_filename; |
| 75763 | duk__compiler_stkstate *comp_stk; |
| 75764 | duk_compiler_ctx *comp_ctx; |
| 75765 | duk_lexer_point *lex_pt; |
| 75766 | duk_compiler_func *func; |
| 75767 | duk_idx_t entry_top; |
| 75768 | duk_bool_t is_strict; |
| 75769 | duk_bool_t is_eval; |
| 75770 | duk_bool_t is_funcexpr; |
| 75771 | duk_small_uint_t flags; |
| 75772 | |
| 75773 | DUK_ASSERT(thr != NULL); |
| 75774 | DUK_ASSERT(udata != NULL); |
| 75775 | |
| 75776 | /* |
| 75777 | * Arguments check |
| 75778 | */ |
| 75779 | |
| 75780 | entry_top = duk_get_top(thr); |
| 75781 | DUK_ASSERT(entry_top >= 1); |
| 75782 | |
| 75783 | comp_stk = (duk__compiler_stkstate *) udata; |
| 75784 | comp_ctx = &comp_stk->comp_ctx_alloc; |
| 75785 | lex_pt = &comp_stk->lex_pt_alloc; |
| 75786 | DUK_ASSERT(comp_ctx != NULL); |
| 75787 | DUK_ASSERT(lex_pt != NULL); |
| 75788 | |
| 75789 | flags = comp_stk->flags; |
| 75790 | is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0); |
| 75791 | is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0); |
| 75792 | is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0); |
| 75793 | |
| 75794 | h_filename = duk_get_hstring(thr, -1); /* may be undefined */ |
| 75795 | |
| 75796 | /* |
| 75797 | * Init compiler and lexer contexts |
| 75798 | */ |
| 75799 | |
| 75800 | func = &comp_ctx->curr_func; |
| 75801 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 75802 | comp_ctx->thr = NULL; |
| 75803 | comp_ctx->h_filename = NULL; |
| 75804 | comp_ctx->prev_token.str1 = NULL; |
| 75805 | comp_ctx->prev_token.str2 = NULL; |
| 75806 | comp_ctx->curr_token.str1 = NULL; |
| 75807 | comp_ctx->curr_token.str2 = NULL; |
| 75808 | #endif |
| 75809 | |
| 75810 | duk_require_stack(thr, DUK__COMPILE_ENTRY_SLOTS); |
| 75811 | |
| 75812 | duk_push_dynamic_buffer(thr, 0); /* entry_top + 0 */ |
| 75813 | duk_push_undefined(thr); /* entry_top + 1 */ |
| 75814 | duk_push_undefined(thr); /* entry_top + 2 */ |
| 75815 | duk_push_undefined(thr); /* entry_top + 3 */ |
| 75816 | duk_push_undefined(thr); /* entry_top + 4 */ |
| 75817 | |
| 75818 | comp_ctx->thr = thr; |
| 75819 | comp_ctx->h_filename = h_filename; |
| 75820 | comp_ctx->tok11_idx = entry_top + 1; |
| 75821 | comp_ctx->tok12_idx = entry_top + 2; |
| 75822 | comp_ctx->tok21_idx = entry_top + 3; |
| 75823 | comp_ctx->tok22_idx = entry_top + 4; |
| 75824 | comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT; |
| 75825 | |
| 75826 | /* comp_ctx->lex has been pre-initialized by caller: it has been |
| 75827 | * zeroed and input/input_length has been set. |
| 75828 | */ |
| 75829 | comp_ctx->lex.thr = thr; |
| 75830 | /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */ |
| 75831 | comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx; |
| 75832 | comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx; |
| 75833 | comp_ctx->lex.buf_idx = entry_top + 0; |
| 75834 | comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 0); |
| 75835 | DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf)); |
| 75836 | comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT; |
| 75837 | |
| 75838 | lex_pt->offset = 0; |
| 75839 | lex_pt->line = 1; |
| 75840 | DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt); /* fills window */ |
| 75841 | comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */ |
| 75842 | |
| 75843 | /* |
| 75844 | * Initialize function state for a zero-argument function |
| 75845 | */ |
| 75846 | |
| 75847 | duk__init_func_valstack_slots(comp_ctx); |
| 75848 | DUK_ASSERT(func->num_formals == 0); |
| 75849 | |
| 75850 | if (is_funcexpr) { |
| 75851 | /* Name will be filled from function expression, not by caller. |
| 75852 | * This case is used by Function constructor and duk_compile() |
| 75853 | * API with the DUK_COMPILE_FUNCTION option. |
| 75854 | */ |
| 75855 | DUK_ASSERT(func->h_name == NULL); |
| 75856 | } else { |
| 75857 | duk_push_hstring_stridx(thr, (is_eval ? DUK_STRIDX_EVAL : |
| 75858 | DUK_STRIDX_GLOBAL)); |
| 75859 | func->h_name = duk_get_hstring(thr, -1); |
| 75860 | } |
| 75861 | |
| 75862 | /* |
| 75863 | * Parse a function body or a function-like expression, depending |
| 75864 | * on flags. |
| 75865 | */ |
| 75866 | |
| 75867 | DUK_ASSERT(func->is_setget == 0); |
| 75868 | func->is_strict = (duk_uint8_t) is_strict; |
| 75869 | DUK_ASSERT(func->is_notail == 0); |
| 75870 | |
| 75871 | if (is_funcexpr) { |
| 75872 | func->is_function = 1; |
| 75873 | DUK_ASSERT(func->is_eval == 0); |
| 75874 | DUK_ASSERT(func->is_global == 0); |
| 75875 | func->is_namebinding = 1; |
| 75876 | func->is_constructable = 1; |
| 75877 | |
| 75878 | duk__advance(comp_ctx); /* init 'curr_token' */ |
| 75879 | duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION); |
| 75880 | (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/); |
| 75881 | } else { |
| 75882 | DUK_ASSERT(func->is_function == 0); |
| 75883 | DUK_ASSERT(is_eval == 0 || is_eval == 1); |
| 75884 | func->is_eval = (duk_uint8_t) is_eval; |
| 75885 | func->is_global = (duk_uint8_t) !is_eval; |
| 75886 | DUK_ASSERT(func->is_namebinding == 0); |
| 75887 | DUK_ASSERT(func->is_constructable == 0); |
| 75888 | |
| 75889 | duk__parse_func_body(comp_ctx, |
| 75890 | 1, /* expect_eof */ |
| 75891 | 1, /* implicit_return_value */ |
| 75892 | 1, /* regexp_after (does not matter) */ |
| 75893 | -1); /* expect_token */ |
| 75894 | } |
| 75895 | |
| 75896 | /* |
| 75897 | * Convert duk_compiler_func to a function template |
| 75898 | */ |
| 75899 | |
| 75900 | duk__convert_to_func_template(comp_ctx); |
| 75901 | |
| 75902 | /* |
| 75903 | * Wrapping duk_safe_call() will mangle the stack, just return stack top |
| 75904 | */ |
| 75905 | |
| 75906 | /* [ ... filename (temps) func ] */ |
| 75907 | |
| 75908 | return 1; |
| 75909 | } |
| 75910 | |
| 75911 | DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) { |
| 75912 | duk__compiler_stkstate comp_stk; |
| 75913 | duk_compiler_ctx *prev_ctx; |
| 75914 | duk_ret_t safe_rc; |
| 75915 | |
| 75916 | DUK_ASSERT(thr != NULL); |
| 75917 | DUK_ASSERT(src_buffer != NULL); |
| 75918 | |
| 75919 | /* preinitialize lexer state partially */ |
| 75920 | duk_memzero(&comp_stk, sizeof(comp_stk)); |
| 75921 | comp_stk.flags = flags; |
| 75922 | DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex); |
| 75923 | comp_stk.comp_ctx_alloc.lex.input = src_buffer; |
| 75924 | comp_stk.comp_ctx_alloc.lex.input_length = src_length; |
| 75925 | comp_stk.comp_ctx_alloc.lex.flags = flags; /* Forward flags directly for now. */ |
| 75926 | |
| 75927 | /* [ ... filename ] */ |
| 75928 | |
| 75929 | prev_ctx = thr->compile_ctx; |
| 75930 | thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */ |
| 75931 | safe_rc = duk_safe_call(thr, duk__js_compile_raw, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nrets*/); |
| 75932 | thr->compile_ctx = prev_ctx; /* must restore reliably before returning */ |
| 75933 | |
| 75934 | if (safe_rc != DUK_EXEC_SUCCESS) { |
| 75935 | DUK_D(DUK_DPRINT("compilation failed: %!T" , duk_get_tval(thr, -1))); |
| 75936 | (void) duk_throw(thr); |
| 75937 | DUK_WO_NORETURN(return;); |
| 75938 | } |
| 75939 | |
| 75940 | /* [ ... template ] */ |
| 75941 | } |
| 75942 | |
| 75943 | /* automatic undefs */ |
| 75944 | #undef DUK__ALLOCTEMP |
| 75945 | #undef DUK__ALLOCTEMPS |
| 75946 | #undef DUK__ALLOW_AUTO_SEMI_ALWAYS |
| 75947 | #undef DUK__BC_INITIAL_INSTS |
| 75948 | #undef DUK__BP_ADDITIVE |
| 75949 | #undef DUK__BP_ASSIGNMENT |
| 75950 | #undef DUK__BP_BAND |
| 75951 | #undef DUK__BP_BOR |
| 75952 | #undef DUK__BP_BXOR |
| 75953 | #undef DUK__BP_CALL |
| 75954 | #undef DUK__BP_CLOSING |
| 75955 | #undef DUK__BP_COMMA |
| 75956 | #undef DUK__BP_CONDITIONAL |
| 75957 | #undef DUK__BP_EOF |
| 75958 | #undef DUK__BP_EQUALITY |
| 75959 | #undef DUK__BP_EXPONENTIATION |
| 75960 | #undef DUK__BP_FOR_EXPR |
| 75961 | #undef DUK__BP_INVALID |
| 75962 | #undef DUK__BP_LAND |
| 75963 | #undef DUK__BP_LOR |
| 75964 | #undef DUK__BP_MEMBER |
| 75965 | #undef DUK__BP_MULTIPLICATIVE |
| 75966 | #undef DUK__BP_POSTFIX |
| 75967 | #undef DUK__BP_RELATIONAL |
| 75968 | #undef DUK__BP_SHIFT |
| 75969 | #undef DUK__COMPILE_ENTRY_SLOTS |
| 75970 | #undef DUK__CONST_MARKER |
| 75971 | #undef DUK__DUMP_ISPEC |
| 75972 | #undef DUK__DUMP_IVALUE |
| 75973 | #undef DUK__EMIT_FLAG_A_IS_SOURCE |
| 75974 | #undef DUK__EMIT_FLAG_BC_REGCONST |
| 75975 | #undef DUK__EMIT_FLAG_B_IS_TARGET |
| 75976 | #undef DUK__EMIT_FLAG_C_IS_TARGET |
| 75977 | #undef DUK__EMIT_FLAG_NO_SHUFFLE_A |
| 75978 | #undef DUK__EMIT_FLAG_NO_SHUFFLE_B |
| 75979 | #undef DUK__EMIT_FLAG_NO_SHUFFLE_C |
| 75980 | #undef DUK__EMIT_FLAG_RESERVE_JUMPSLOT |
| 75981 | #undef DUK__EXPR_FLAG_ALLOW_EMPTY |
| 75982 | #undef DUK__EXPR_FLAG_REJECT_IN |
| 75983 | #undef DUK__EXPR_FLAG_REQUIRE_INIT |
| 75984 | #undef DUK__EXPR_RBP_MASK |
| 75985 | #undef DUK__FUNCTION_BODY_REQUIRE_SLOTS |
| 75986 | #undef DUK__FUNCTION_INIT_REQUIRE_SLOTS |
| 75987 | #undef DUK__FUNC_FLAG_DECL |
| 75988 | #undef DUK__FUNC_FLAG_GETSET |
| 75989 | #undef DUK__FUNC_FLAG_METDEF |
| 75990 | #undef DUK__FUNC_FLAG_PUSHNAME_PASS1 |
| 75991 | #undef DUK__FUNC_FLAG_USE_PREVTOKEN |
| 75992 | #undef DUK__GETCONST_MAX_CONSTS_CHECK |
| 75993 | #undef DUK__GETTEMP |
| 75994 | #undef DUK__HAS_TERM |
| 75995 | #undef DUK__HAS_VAL |
| 75996 | #undef DUK__ISCONST |
| 75997 | #undef DUK__ISREG |
| 75998 | #undef DUK__ISREG_NOTTEMP |
| 75999 | #undef DUK__ISREG_TEMP |
| 76000 | #undef DUK__IS_TERMINAL |
| 76001 | #undef DUK__IVAL_FLAG_ALLOW_CONST |
| 76002 | #undef DUK__IVAL_FLAG_REQUIRE_SHORT |
| 76003 | #undef DUK__IVAL_FLAG_REQUIRE_TEMP |
| 76004 | #undef DUK__MAX_ARRAY_INIT_VALUES |
| 76005 | #undef DUK__MAX_CONSTS |
| 76006 | #undef DUK__MAX_FUNCS |
| 76007 | #undef DUK__MAX_OBJECT_INIT_PAIRS |
| 76008 | #undef DUK__MAX_TEMPS |
| 76009 | #undef DUK__MK_LBP |
| 76010 | #undef DUK__MK_LBP_FLAGS |
| 76011 | #undef DUK__OBJ_LIT_KEY_GET |
| 76012 | #undef DUK__OBJ_LIT_KEY_PLAIN |
| 76013 | #undef DUK__OBJ_LIT_KEY_SET |
| 76014 | #undef DUK__PARSE_EXPR_SLOTS |
| 76015 | #undef DUK__PARSE_STATEMENTS_SLOTS |
| 76016 | #undef DUK__RECURSION_DECREASE |
| 76017 | #undef DUK__RECURSION_INCREASE |
| 76018 | #undef DUK__REMOVECONST |
| 76019 | #undef DUK__SETTEMP |
| 76020 | #undef DUK__SETTEMP_CHECKMAX |
| 76021 | #undef DUK__STILL_PROLOGUE |
| 76022 | #undef DUK__TOKEN_LBP_BP_MASK |
| 76023 | #undef DUK__TOKEN_LBP_FLAG_NO_REGEXP |
| 76024 | #undef DUK__TOKEN_LBP_FLAG_TERMINATES |
| 76025 | #undef DUK__TOKEN_LBP_FLAG_UNUSED |
| 76026 | #undef DUK__TOKEN_LBP_GET_BP |
| 76027 | #line 1 "duk_js_executor.c" |
| 76028 | /* |
| 76029 | * ECMAScript bytecode executor. |
| 76030 | */ |
| 76031 | |
| 76032 | /* #include duk_internal.h -> already included */ |
| 76033 | |
| 76034 | /* |
| 76035 | * Local declarations. |
| 76036 | */ |
| 76037 | |
| 76038 | DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act); |
| 76039 | |
| 76040 | /* |
| 76041 | * Misc helpers. |
| 76042 | */ |
| 76043 | |
| 76044 | /* Replace value stack top to value at 'tv_ptr'. Optimize for |
| 76045 | * performance by only applying the net refcount change. |
| 76046 | */ |
| 76047 | #define DUK__REPLACE_TO_TVPTR(thr,tv_ptr) do { \ |
| 76048 | duk_hthread *duk__thr; \ |
| 76049 | duk_tval *duk__tvsrc; \ |
| 76050 | duk_tval *duk__tvdst; \ |
| 76051 | duk_tval duk__tvtmp; \ |
| 76052 | duk__thr = (thr); \ |
| 76053 | duk__tvsrc = DUK_GET_TVAL_NEGIDX(duk__thr, -1); \ |
| 76054 | duk__tvdst = (tv_ptr); \ |
| 76055 | DUK_TVAL_SET_TVAL(&duk__tvtmp, duk__tvdst); \ |
| 76056 | DUK_TVAL_SET_TVAL(duk__tvdst, duk__tvsrc); \ |
| 76057 | DUK_TVAL_SET_UNDEFINED(duk__tvsrc); /* value stack init policy */ \ |
| 76058 | duk__thr->valstack_top = duk__tvsrc; \ |
| 76059 | DUK_TVAL_DECREF(duk__thr, &duk__tvtmp); \ |
| 76060 | } while (0) |
| 76061 | |
| 76062 | /* XXX: candidate of being an internal shared API call */ |
| 76063 | #if 0 /* unused */ |
| 76064 | DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, duk_small_uint_fast_t count) { |
| 76065 | duk_tval *tv_dst; |
| 76066 | duk_size_t copy_size; |
| 76067 | duk_size_t i; |
| 76068 | |
| 76069 | tv_dst = thr->valstack_top; |
| 76070 | copy_size = sizeof(duk_tval) * count; |
| 76071 | duk_memcpy((void *) tv_dst, (const void *) tv_src, copy_size); |
| 76072 | for (i = 0; i < count; i++) { |
| 76073 | DUK_TVAL_INCREF(thr, tv_dst); |
| 76074 | tv_dst++; |
| 76075 | } |
| 76076 | thr->valstack_top = tv_dst; |
| 76077 | } |
| 76078 | #endif |
| 76079 | |
| 76080 | /* |
| 76081 | * Arithmetic, binary, and logical helpers. |
| 76082 | * |
| 76083 | * Note: there is no opcode for logical AND or logical OR; this is on |
| 76084 | * purpose, because the evalution order semantics for them make such |
| 76085 | * opcodes pretty pointless: short circuiting means they are most |
| 76086 | * comfortably implemented as jumps. However, a logical NOT opcode |
| 76087 | * is useful. |
| 76088 | * |
| 76089 | * Note: careful with duk_tval pointers here: they are potentially |
| 76090 | * invalidated by any DECREF and almost any API call. It's still |
| 76091 | * preferable to work without making a copy but that's not always |
| 76092 | * possible. |
| 76093 | */ |
| 76094 | |
| 76095 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) { |
| 76096 | return (duk_double_t) duk_js_arith_mod((double) d1, (double) d2); |
| 76097 | } |
| 76098 | |
| 76099 | #if defined(DUK_USE_ES7_EXP_OPERATOR) |
| 76100 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF duk_double_t duk__compute_exp(duk_double_t d1, duk_double_t d2) { |
| 76101 | return (duk_double_t) duk_js_arith_pow((double) d1, (double) d2); |
| 76102 | } |
| 76103 | #endif |
| 76104 | |
| 76105 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) { |
| 76106 | /* |
| 76107 | * Addition operator is different from other arithmetic |
| 76108 | * operations in that it also provides string concatenation. |
| 76109 | * Hence it is implemented separately. |
| 76110 | * |
| 76111 | * There is a fast path for number addition. Other cases go |
| 76112 | * through potentially multiple coercions as described in the |
| 76113 | * E5 specification. It may be possible to reduce the number |
| 76114 | * of coercions, but this must be done carefully to preserve |
| 76115 | * the exact semantics. |
| 76116 | * |
| 76117 | * E5 Section 11.6.1. |
| 76118 | * |
| 76119 | * Custom types also have special behavior implemented here. |
| 76120 | */ |
| 76121 | |
| 76122 | duk_double_union du; |
| 76123 | |
| 76124 | DUK_ASSERT(thr != NULL); |
| 76125 | DUK_ASSERT(tv_x != NULL); /* may be reg or const */ |
| 76126 | DUK_ASSERT(tv_y != NULL); /* may be reg or const */ |
| 76127 | DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */ |
| 76128 | DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr)); |
| 76129 | |
| 76130 | /* |
| 76131 | * Fast paths |
| 76132 | */ |
| 76133 | |
| 76134 | #if defined(DUK_USE_FASTINT) |
| 76135 | if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { |
| 76136 | duk_int64_t v1, v2, v3; |
| 76137 | duk_int32_t v3_hi; |
| 76138 | duk_tval *tv_z; |
| 76139 | |
| 76140 | /* Input values are signed 48-bit so we can detect overflow |
| 76141 | * reliably from high bits or just a comparison. |
| 76142 | */ |
| 76143 | |
| 76144 | v1 = DUK_TVAL_GET_FASTINT(tv_x); |
| 76145 | v2 = DUK_TVAL_GET_FASTINT(tv_y); |
| 76146 | v3 = v1 + v2; |
| 76147 | v3_hi = (duk_int32_t) (v3 >> 32); |
| 76148 | if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) { |
| 76149 | tv_z = thr->valstack_bottom + idx_z; |
| 76150 | DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */ |
| 76151 | return; |
| 76152 | } else { |
| 76153 | /* overflow, fall through */ |
| 76154 | ; |
| 76155 | } |
| 76156 | } |
| 76157 | #endif /* DUK_USE_FASTINT */ |
| 76158 | |
| 76159 | if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { |
| 76160 | #if !defined(DUK_USE_EXEC_PREFER_SIZE) |
| 76161 | duk_tval *tv_z; |
| 76162 | #endif |
| 76163 | |
| 76164 | du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y); |
| 76165 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 76166 | duk_push_number(thr, du.d); /* will NaN normalize result */ |
| 76167 | duk_replace(thr, (duk_idx_t) idx_z); |
| 76168 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76169 | DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); |
| 76170 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 76171 | tv_z = thr->valstack_bottom + idx_z; |
| 76172 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */ |
| 76173 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76174 | return; |
| 76175 | } |
| 76176 | |
| 76177 | /* |
| 76178 | * Slow path: potentially requires function calls for coercion |
| 76179 | */ |
| 76180 | |
| 76181 | duk_push_tval(thr, tv_x); |
| 76182 | duk_push_tval(thr, tv_y); |
| 76183 | duk_to_primitive(thr, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */ |
| 76184 | duk_to_primitive(thr, -1, DUK_HINT_NONE); |
| 76185 | |
| 76186 | /* Since Duktape 2.x plain buffers are treated like ArrayBuffer. */ |
| 76187 | if (duk_is_string(thr, -2) || duk_is_string(thr, -1)) { |
| 76188 | /* Symbols shouldn't technically be handled here, but should |
| 76189 | * go into the default ToNumber() coercion path instead and |
| 76190 | * fail there with a TypeError. However, there's a ToString() |
| 76191 | * in duk_concat_2() which also fails with TypeError so no |
| 76192 | * explicit check is needed. |
| 76193 | */ |
| 76194 | duk_concat_2(thr); /* [... s1 s2] -> [... s1+s2] */ |
| 76195 | } else { |
| 76196 | duk_double_t d1, d2; |
| 76197 | |
| 76198 | d1 = duk_to_number_m2(thr); |
| 76199 | d2 = duk_to_number_m1(thr); |
| 76200 | DUK_ASSERT(duk_is_number(thr, -2)); |
| 76201 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 76202 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1); |
| 76203 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); |
| 76204 | |
| 76205 | du.d = d1 + d2; |
| 76206 | duk_pop_2_unsafe(thr); |
| 76207 | duk_push_number(thr, du.d); /* will NaN normalize result */ |
| 76208 | } |
| 76209 | duk_replace(thr, (duk_idx_t) idx_z); /* side effects */ |
| 76210 | } |
| 76211 | |
| 76212 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_uint_fast_t idx_z, duk_small_uint_fast_t opcode) { |
| 76213 | /* |
| 76214 | * Arithmetic operations other than '+' have number-only semantics |
| 76215 | * and are implemented here. The separate switch-case here means a |
| 76216 | * "double dispatch" of the arithmetic opcode, but saves code space. |
| 76217 | * |
| 76218 | * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3. |
| 76219 | */ |
| 76220 | |
| 76221 | duk_double_t d1, d2; |
| 76222 | duk_double_union du; |
| 76223 | duk_small_uint_fast_t opcode_shifted; |
| 76224 | #if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE) |
| 76225 | duk_tval *tv_z; |
| 76226 | #endif |
| 76227 | |
| 76228 | DUK_ASSERT(thr != NULL); |
| 76229 | DUK_ASSERT(tv_x != NULL); /* may be reg or const */ |
| 76230 | DUK_ASSERT(tv_y != NULL); /* may be reg or const */ |
| 76231 | DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */ |
| 76232 | DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr)); |
| 76233 | |
| 76234 | opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */ |
| 76235 | |
| 76236 | #if defined(DUK_USE_FASTINT) |
| 76237 | if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { |
| 76238 | duk_int64_t v1, v2, v3; |
| 76239 | duk_int32_t v3_hi; |
| 76240 | |
| 76241 | v1 = DUK_TVAL_GET_FASTINT(tv_x); |
| 76242 | v2 = DUK_TVAL_GET_FASTINT(tv_y); |
| 76243 | |
| 76244 | switch (opcode_shifted) { |
| 76245 | case DUK_OP_SUB >> 2: { |
| 76246 | v3 = v1 - v2; |
| 76247 | break; |
| 76248 | } |
| 76249 | case DUK_OP_MUL >> 2: { |
| 76250 | /* Must ensure result is 64-bit (no overflow); a |
| 76251 | * simple and sufficient fast path is to allow only |
| 76252 | * 32-bit inputs. Avoid zero inputs to avoid |
| 76253 | * negative zero issues (-1 * 0 = -0, for instance). |
| 76254 | */ |
| 76255 | if (v1 >= DUK_I64_CONSTANT(-0x80000000) && v1 <= DUK_I64_CONSTANT(0x7fffffff) && v1 != 0 && |
| 76256 | v2 >= DUK_I64_CONSTANT(-0x80000000) && v2 <= DUK_I64_CONSTANT(0x7fffffff) && v2 != 0) { |
| 76257 | v3 = v1 * v2; |
| 76258 | } else { |
| 76259 | goto skip_fastint; |
| 76260 | } |
| 76261 | break; |
| 76262 | } |
| 76263 | case DUK_OP_DIV >> 2: { |
| 76264 | /* Don't allow a zero divisor. Fast path check by |
| 76265 | * "verifying" with multiplication. Also avoid zero |
| 76266 | * dividend to avoid negative zero issues (0 / -1 = -0 |
| 76267 | * for instance). |
| 76268 | */ |
| 76269 | if (v1 == 0 || v2 == 0) { |
| 76270 | goto skip_fastint; |
| 76271 | } |
| 76272 | v3 = v1 / v2; |
| 76273 | if (v3 * v2 != v1) { |
| 76274 | goto skip_fastint; |
| 76275 | } |
| 76276 | break; |
| 76277 | } |
| 76278 | case DUK_OP_MOD >> 2: { |
| 76279 | /* Don't allow a zero divisor. Restrict both v1 and |
| 76280 | * v2 to positive values to avoid compiler specific |
| 76281 | * behavior. |
| 76282 | */ |
| 76283 | if (v1 < 1 || v2 < 1) { |
| 76284 | goto skip_fastint; |
| 76285 | } |
| 76286 | v3 = v1 % v2; |
| 76287 | DUK_ASSERT(v3 >= 0); |
| 76288 | DUK_ASSERT(v3 < v2); |
| 76289 | DUK_ASSERT(v1 - (v1 / v2) * v2 == v3); |
| 76290 | break; |
| 76291 | } |
| 76292 | default: { |
| 76293 | /* Possible with DUK_OP_EXP. */ |
| 76294 | goto skip_fastint; |
| 76295 | } |
| 76296 | } |
| 76297 | |
| 76298 | v3_hi = (duk_int32_t) (v3 >> 32); |
| 76299 | if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) { |
| 76300 | tv_z = thr->valstack_bottom + idx_z; |
| 76301 | DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */ |
| 76302 | return; |
| 76303 | } |
| 76304 | /* fall through if overflow etc */ |
| 76305 | } |
| 76306 | skip_fastint: |
| 76307 | #endif /* DUK_USE_FASTINT */ |
| 76308 | |
| 76309 | if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { |
| 76310 | /* fast path */ |
| 76311 | d1 = DUK_TVAL_GET_NUMBER(tv_x); |
| 76312 | d2 = DUK_TVAL_GET_NUMBER(tv_y); |
| 76313 | } else { |
| 76314 | duk_push_tval(thr, tv_x); |
| 76315 | duk_push_tval(thr, tv_y); |
| 76316 | d1 = duk_to_number_m2(thr); /* side effects */ |
| 76317 | d2 = duk_to_number_m1(thr); |
| 76318 | DUK_ASSERT(duk_is_number(thr, -2)); |
| 76319 | DUK_ASSERT(duk_is_number(thr, -1)); |
| 76320 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1); |
| 76321 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); |
| 76322 | duk_pop_2_unsafe(thr); |
| 76323 | } |
| 76324 | |
| 76325 | switch (opcode_shifted) { |
| 76326 | case DUK_OP_SUB >> 2: { |
| 76327 | du.d = d1 - d2; |
| 76328 | break; |
| 76329 | } |
| 76330 | case DUK_OP_MUL >> 2: { |
| 76331 | du.d = d1 * d2; |
| 76332 | break; |
| 76333 | } |
| 76334 | case DUK_OP_DIV >> 2: { |
| 76335 | /* Division-by-zero is undefined behavior, so |
| 76336 | * rely on a helper. |
| 76337 | */ |
| 76338 | du.d = duk_double_div(d1, d2); |
| 76339 | break; |
| 76340 | } |
| 76341 | case DUK_OP_MOD >> 2: { |
| 76342 | du.d = duk__compute_mod(d1, d2); |
| 76343 | break; |
| 76344 | } |
| 76345 | #if defined(DUK_USE_ES7_EXP_OPERATOR) |
| 76346 | case DUK_OP_EXP >> 2: { |
| 76347 | du.d = duk__compute_exp(d1, d2); |
| 76348 | break; |
| 76349 | } |
| 76350 | #endif |
| 76351 | default: { |
| 76352 | DUK_UNREACHABLE(); |
| 76353 | du.d = DUK_DOUBLE_NAN; /* should not happen */ |
| 76354 | break; |
| 76355 | } |
| 76356 | } |
| 76357 | |
| 76358 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 76359 | duk_push_number(thr, du.d); /* will NaN normalize result */ |
| 76360 | duk_replace(thr, (duk_idx_t) idx_z); |
| 76361 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76362 | /* important to use normalized NaN with 8-byte tagged types */ |
| 76363 | DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); |
| 76364 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 76365 | tv_z = thr->valstack_bottom + idx_z; |
| 76366 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */ |
| 76367 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76368 | } |
| 76369 | |
| 76370 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z, duk_small_uint_fast_t opcode) { |
| 76371 | /* |
| 76372 | * Binary bitwise operations use different coercions (ToInt32, ToUint32) |
| 76373 | * depending on the operation. We coerce the arguments first using |
| 76374 | * ToInt32(), and then cast to an 32-bit value if necessary. Note that |
| 76375 | * such casts must be correct even if there is no native 32-bit type |
| 76376 | * (e.g., duk_int32_t and duk_uint32_t are 64-bit). |
| 76377 | * |
| 76378 | * E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3 |
| 76379 | */ |
| 76380 | |
| 76381 | duk_int32_t i1, i2, i3; |
| 76382 | duk_uint32_t u1, u2, u3; |
| 76383 | #if defined(DUK_USE_FASTINT) |
| 76384 | duk_int64_t fi3; |
| 76385 | #else |
| 76386 | duk_double_t d3; |
| 76387 | #endif |
| 76388 | duk_small_uint_fast_t opcode_shifted; |
| 76389 | #if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE) |
| 76390 | duk_tval *tv_z; |
| 76391 | #endif |
| 76392 | |
| 76393 | DUK_ASSERT(thr != NULL); |
| 76394 | DUK_ASSERT(tv_x != NULL); /* may be reg or const */ |
| 76395 | DUK_ASSERT(tv_y != NULL); /* may be reg or const */ |
| 76396 | DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */ |
| 76397 | DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr)); |
| 76398 | |
| 76399 | opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */ |
| 76400 | |
| 76401 | #if defined(DUK_USE_FASTINT) |
| 76402 | if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { |
| 76403 | i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x); |
| 76404 | i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y); |
| 76405 | } |
| 76406 | else |
| 76407 | #endif /* DUK_USE_FASTINT */ |
| 76408 | { |
| 76409 | duk_push_tval(thr, tv_x); |
| 76410 | duk_push_tval(thr, tv_y); |
| 76411 | i1 = duk_to_int32(thr, -2); |
| 76412 | i2 = duk_to_int32(thr, -1); |
| 76413 | duk_pop_2_unsafe(thr); |
| 76414 | } |
| 76415 | |
| 76416 | switch (opcode_shifted) { |
| 76417 | case DUK_OP_BAND >> 2: { |
| 76418 | i3 = i1 & i2; |
| 76419 | break; |
| 76420 | } |
| 76421 | case DUK_OP_BOR >> 2: { |
| 76422 | i3 = i1 | i2; |
| 76423 | break; |
| 76424 | } |
| 76425 | case DUK_OP_BXOR >> 2: { |
| 76426 | i3 = i1 ^ i2; |
| 76427 | break; |
| 76428 | } |
| 76429 | case DUK_OP_BASL >> 2: { |
| 76430 | /* Signed shift, named "arithmetic" (asl) because the result |
| 76431 | * is signed, e.g. 4294967295 << 1 -> -2. Note that result |
| 76432 | * must be masked. |
| 76433 | */ |
| 76434 | |
| 76435 | u2 = ((duk_uint32_t) i2) & 0xffffffffUL; |
| 76436 | i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL)); /* E5 Section 11.7.1, steps 7 and 8 */ |
| 76437 | i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */ |
| 76438 | break; |
| 76439 | } |
| 76440 | case DUK_OP_BASR >> 2: { |
| 76441 | /* signed shift */ |
| 76442 | |
| 76443 | u2 = ((duk_uint32_t) i2) & 0xffffffffUL; |
| 76444 | i3 = i1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */ |
| 76445 | break; |
| 76446 | } |
| 76447 | case DUK_OP_BLSR >> 2: { |
| 76448 | /* unsigned shift */ |
| 76449 | |
| 76450 | u1 = ((duk_uint32_t) i1) & 0xffffffffUL; |
| 76451 | u2 = ((duk_uint32_t) i2) & 0xffffffffUL; |
| 76452 | |
| 76453 | /* special result value handling */ |
| 76454 | u3 = u1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */ |
| 76455 | #if defined(DUK_USE_FASTINT) |
| 76456 | fi3 = (duk_int64_t) u3; |
| 76457 | goto fastint_result_set; |
| 76458 | #else |
| 76459 | d3 = (duk_double_t) u3; |
| 76460 | goto result_set; |
| 76461 | #endif |
| 76462 | } |
| 76463 | default: { |
| 76464 | DUK_UNREACHABLE(); |
| 76465 | i3 = 0; /* should not happen */ |
| 76466 | break; |
| 76467 | } |
| 76468 | } |
| 76469 | |
| 76470 | #if defined(DUK_USE_FASTINT) |
| 76471 | /* Result is always fastint compatible. */ |
| 76472 | /* XXX: Set 32-bit result (but must then handle signed and |
| 76473 | * unsigned results separately). |
| 76474 | */ |
| 76475 | fi3 = (duk_int64_t) i3; |
| 76476 | |
| 76477 | fastint_result_set: |
| 76478 | tv_z = thr->valstack_bottom + idx_z; |
| 76479 | DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */ |
| 76480 | #else /* DUK_USE_FASTINT */ |
| 76481 | d3 = (duk_double_t) i3; |
| 76482 | |
| 76483 | result_set: |
| 76484 | DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */ |
| 76485 | DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */ |
| 76486 | |
| 76487 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 76488 | duk_push_number(thr, d3); /* would NaN normalize result, but unnecessary */ |
| 76489 | duk_replace(thr, (duk_idx_t) idx_z); |
| 76490 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76491 | tv_z = thr->valstack_bottom + idx_z; |
| 76492 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */ |
| 76493 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76494 | #endif /* DUK_USE_FASTINT */ |
| 76495 | } |
| 76496 | |
| 76497 | /* In-place unary operation. */ |
| 76498 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst, duk_small_uint_fast_t opcode) { |
| 76499 | /* |
| 76500 | * Arithmetic operations other than '+' have number-only semantics |
| 76501 | * and are implemented here. The separate switch-case here means a |
| 76502 | * "double dispatch" of the arithmetic opcode, but saves code space. |
| 76503 | * |
| 76504 | * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3. |
| 76505 | */ |
| 76506 | |
| 76507 | duk_tval *tv; |
| 76508 | duk_double_t d1; |
| 76509 | duk_double_union du; |
| 76510 | |
| 76511 | DUK_ASSERT(thr != NULL); |
| 76512 | DUK_ASSERT(opcode == DUK_OP_UNM || opcode == DUK_OP_UNP); |
| 76513 | DUK_ASSERT_DISABLE(idx_src >= 0); |
| 76514 | DUK_ASSERT_DISABLE(idx_dst >= 0); |
| 76515 | |
| 76516 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src); |
| 76517 | |
| 76518 | #if defined(DUK_USE_FASTINT) |
| 76519 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 76520 | duk_int64_t v1, v2; |
| 76521 | |
| 76522 | v1 = DUK_TVAL_GET_FASTINT(tv); |
| 76523 | if (opcode == DUK_OP_UNM) { |
| 76524 | /* The smallest fastint is no longer 48-bit when |
| 76525 | * negated. Positive zero becames negative zero |
| 76526 | * (cannot be represented) when negated. |
| 76527 | */ |
| 76528 | if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) { |
| 76529 | v2 = -v1; |
| 76530 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); |
| 76531 | DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2); |
| 76532 | return; |
| 76533 | } |
| 76534 | } else { |
| 76535 | /* ToNumber() for a fastint is a no-op. */ |
| 76536 | DUK_ASSERT(opcode == DUK_OP_UNP); |
| 76537 | v2 = v1; |
| 76538 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); |
| 76539 | DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2); |
| 76540 | return; |
| 76541 | } |
| 76542 | /* fall through if overflow etc */ |
| 76543 | } |
| 76544 | #endif /* DUK_USE_FASTINT */ |
| 76545 | |
| 76546 | if (DUK_TVAL_IS_NUMBER(tv)) { |
| 76547 | d1 = DUK_TVAL_GET_NUMBER(tv); |
| 76548 | } else { |
| 76549 | d1 = duk_to_number_tval(thr, tv); /* side effects */ |
| 76550 | } |
| 76551 | |
| 76552 | if (opcode == DUK_OP_UNP) { |
| 76553 | /* ToNumber() for a double is a no-op, but unary plus is |
| 76554 | * used to force a fastint check so do that here. |
| 76555 | */ |
| 76556 | du.d = d1; |
| 76557 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 76558 | #if defined(DUK_USE_FASTINT) |
| 76559 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); |
| 76560 | DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); /* always 'fast', i.e. inlined */ |
| 76561 | return; |
| 76562 | #endif |
| 76563 | } else { |
| 76564 | DUK_ASSERT(opcode == DUK_OP_UNM); |
| 76565 | du.d = -d1; |
| 76566 | DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */ |
| 76567 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 76568 | } |
| 76569 | |
| 76570 | /* XXX: size optimize: push+replace? */ |
| 76571 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); |
| 76572 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, du.d); |
| 76573 | } |
| 76574 | |
| 76575 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) { |
| 76576 | /* |
| 76577 | * E5 Section 11.4.8 |
| 76578 | */ |
| 76579 | |
| 76580 | duk_tval *tv; |
| 76581 | duk_int32_t i1, i2; |
| 76582 | |
| 76583 | DUK_ASSERT(thr != NULL); |
| 76584 | DUK_ASSERT_DISABLE(idx_src >= 0); |
| 76585 | DUK_ASSERT_DISABLE(idx_dst >= 0); |
| 76586 | DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr)); |
| 76587 | DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr)); |
| 76588 | |
| 76589 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src); |
| 76590 | |
| 76591 | #if defined(DUK_USE_FASTINT) |
| 76592 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 76593 | i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv); |
| 76594 | } |
| 76595 | else |
| 76596 | #endif /* DUK_USE_FASTINT */ |
| 76597 | { |
| 76598 | duk_push_tval(thr, tv); |
| 76599 | i1 = duk_to_int32(thr, -1); /* side effects */ |
| 76600 | duk_pop_unsafe(thr); |
| 76601 | } |
| 76602 | |
| 76603 | /* Result is always fastint compatible. */ |
| 76604 | i2 = ~i1; |
| 76605 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); |
| 76606 | DUK_TVAL_SET_I32_UPDREF(thr, tv, i2); /* side effects */ |
| 76607 | } |
| 76608 | |
| 76609 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) { |
| 76610 | /* |
| 76611 | * E5 Section 11.4.9 |
| 76612 | */ |
| 76613 | |
| 76614 | duk_tval *tv; |
| 76615 | duk_bool_t res; |
| 76616 | |
| 76617 | DUK_ASSERT(thr != NULL); |
| 76618 | DUK_ASSERT_DISABLE(idx_src >= 0); |
| 76619 | DUK_ASSERT_DISABLE(idx_dst >= 0); |
| 76620 | DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr)); |
| 76621 | DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr)); |
| 76622 | |
| 76623 | /* ToBoolean() does not require any operations with side effects so |
| 76624 | * we can do it efficiently. For footprint it would be better to use |
| 76625 | * duk_js_toboolean() and then push+replace to the result slot. |
| 76626 | */ |
| 76627 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src); |
| 76628 | res = duk_js_toboolean(tv); /* does not modify 'tv' */ |
| 76629 | DUK_ASSERT(res == 0 || res == 1); |
| 76630 | res ^= 1; |
| 76631 | tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst); |
| 76632 | /* XXX: size optimize: push+replace? */ |
| 76633 | DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, res); /* side effects */ |
| 76634 | } |
| 76635 | |
| 76636 | /* XXX: size optimized variant */ |
| 76637 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_small_uint_t op) { |
| 76638 | duk_double_t x, y, z; |
| 76639 | |
| 76640 | /* Two lowest bits of opcode are used to distinguish |
| 76641 | * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1). |
| 76642 | */ |
| 76643 | DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00); |
| 76644 | DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01); |
| 76645 | DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02); |
| 76646 | DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03); |
| 76647 | |
| 76648 | #if defined(DUK_USE_FASTINT) |
| 76649 | if (DUK_TVAL_IS_FASTINT(tv_src)) { |
| 76650 | duk_int64_t x_fi, y_fi, z_fi; |
| 76651 | x_fi = DUK_TVAL_GET_FASTINT(tv_src); |
| 76652 | if (op & 0x01) { |
| 76653 | if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MIN)) { |
| 76654 | goto skip_fastint; |
| 76655 | } |
| 76656 | y_fi = x_fi - 1; |
| 76657 | } else { |
| 76658 | if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MAX)) { |
| 76659 | goto skip_fastint; |
| 76660 | } |
| 76661 | y_fi = x_fi + 1; |
| 76662 | } |
| 76663 | |
| 76664 | DUK_TVAL_SET_FASTINT(tv_src, y_fi); /* no need for refcount update */ |
| 76665 | |
| 76666 | z_fi = (op & 0x02) ? x_fi : y_fi; |
| 76667 | DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_dst, z_fi); /* side effects */ |
| 76668 | return; |
| 76669 | } |
| 76670 | skip_fastint: |
| 76671 | #endif |
| 76672 | if (DUK_TVAL_IS_NUMBER(tv_src)) { |
| 76673 | /* Fast path for the case where the register |
| 76674 | * is a number (e.g. loop counter). |
| 76675 | */ |
| 76676 | |
| 76677 | x = DUK_TVAL_GET_NUMBER(tv_src); |
| 76678 | if (op & 0x01) { |
| 76679 | y = x - 1.0; |
| 76680 | } else { |
| 76681 | y = x + 1.0; |
| 76682 | } |
| 76683 | |
| 76684 | DUK_TVAL_SET_NUMBER(tv_src, y); /* no need for refcount update */ |
| 76685 | } else { |
| 76686 | /* Preserve duk_tval pointer(s) across a potential valstack |
| 76687 | * resize by converting them into offsets temporarily. |
| 76688 | */ |
| 76689 | duk_idx_t bc; |
| 76690 | duk_size_t off_dst; |
| 76691 | |
| 76692 | off_dst = (duk_size_t) ((duk_uint8_t *) tv_dst - (duk_uint8_t *) thr->valstack_bottom); |
| 76693 | bc = (duk_idx_t) (tv_src - thr->valstack_bottom); /* XXX: pass index explicitly? */ |
| 76694 | tv_src = NULL; /* no longer referenced */ |
| 76695 | |
| 76696 | x = duk_to_number(thr, bc); |
| 76697 | if (op & 0x01) { |
| 76698 | y = x - 1.0; |
| 76699 | } else { |
| 76700 | y = x + 1.0; |
| 76701 | } |
| 76702 | |
| 76703 | duk_push_number(thr, y); |
| 76704 | duk_replace(thr, bc); |
| 76705 | |
| 76706 | tv_dst = (duk_tval *) (void *) (((duk_uint8_t *) thr->valstack_bottom) + off_dst); |
| 76707 | } |
| 76708 | |
| 76709 | z = (op & 0x02) ? x : y; |
| 76710 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); /* side effects */ |
| 76711 | } |
| 76712 | |
| 76713 | DUK_LOCAL DUK_EXEC_ALWAYS_INLINE_PERF void duk__prepost_incdec_var_helper(duk_hthread *thr, duk_small_uint_t idx_dst, duk_tval *tv_id, duk_small_uint_t op, duk_small_uint_t is_strict) { |
| 76714 | duk_activation *act; |
| 76715 | duk_double_t x, y; |
| 76716 | duk_hstring *name; |
| 76717 | |
| 76718 | /* XXX: The pre/post inc/dec for an identifier lookup is |
| 76719 | * missing the important fast path where the identifier |
| 76720 | * has a storage location e.g. in a scope object so that |
| 76721 | * it can be updated in-place. In particular, the case |
| 76722 | * where the identifier has a storage location AND the |
| 76723 | * previous value is a number should be optimized because |
| 76724 | * it's side effect free. |
| 76725 | */ |
| 76726 | |
| 76727 | /* Two lowest bits of opcode are used to distinguish |
| 76728 | * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1). |
| 76729 | */ |
| 76730 | DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00); |
| 76731 | DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01); |
| 76732 | DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02); |
| 76733 | DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03); |
| 76734 | |
| 76735 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id)); |
| 76736 | name = DUK_TVAL_GET_STRING(tv_id); |
| 76737 | DUK_ASSERT(name != NULL); |
| 76738 | act = thr->callstack_curr; |
| 76739 | (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */ |
| 76740 | |
| 76741 | /* XXX: Fastint fast path would be useful here. Also fastints |
| 76742 | * now lose their fastint status in current handling which is |
| 76743 | * not intuitive. |
| 76744 | */ |
| 76745 | |
| 76746 | x = duk_to_number_m2(thr); |
| 76747 | if (op & 0x01) { |
| 76748 | y = x - 1.0; |
| 76749 | } else { |
| 76750 | y = x + 1.0; |
| 76751 | } |
| 76752 | |
| 76753 | /* [... x this] */ |
| 76754 | |
| 76755 | if (op & 0x02) { |
| 76756 | duk_push_number(thr, y); /* -> [ ... x this y ] */ |
| 76757 | DUK_ASSERT(act == thr->callstack_curr); |
| 76758 | duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict); |
| 76759 | duk_pop_2_unsafe(thr); /* -> [ ... x ] */ |
| 76760 | } else { |
| 76761 | duk_pop_2_unsafe(thr); /* -> [ ... ] */ |
| 76762 | duk_push_number(thr, y); /* -> [ ... y ] */ |
| 76763 | DUK_ASSERT(act == thr->callstack_curr); |
| 76764 | duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict); |
| 76765 | } |
| 76766 | |
| 76767 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 76768 | duk_replace(thr, (duk_idx_t) idx_dst); |
| 76769 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76770 | DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst)); |
| 76771 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 76772 | } |
| 76773 | |
| 76774 | /* |
| 76775 | * Longjmp and other control flow transfer for the bytecode executor. |
| 76776 | * |
| 76777 | * The longjmp handler can handle all longjmp types: error, yield, and |
| 76778 | * resume (pseudotypes are never actually thrown). |
| 76779 | * |
| 76780 | * Error policy for longjmp: should not ordinarily throw errors; if errors |
| 76781 | * occur (e.g. due to out-of-memory) they bubble outwards rather than being |
| 76782 | * handled recursively. |
| 76783 | */ |
| 76784 | |
| 76785 | #define DUK__LONGJMP_RESTART 0 /* state updated, restart bytecode execution */ |
| 76786 | #define DUK__LONGJMP_RETHROW 1 /* exit bytecode executor by rethrowing an error to caller */ |
| 76787 | |
| 76788 | #define DUK__RETHAND_RESTART 0 /* state updated, restart bytecode execution */ |
| 76789 | #define DUK__RETHAND_FINISHED 1 /* exit bytecode execution with return value */ |
| 76790 | |
| 76791 | /* XXX: optimize reconfig valstack operations so that resize, clamp, and setting |
| 76792 | * top are combined into one pass. |
| 76793 | */ |
| 76794 | |
| 76795 | /* Reconfigure value stack for return to an ECMAScript function at |
| 76796 | * callstack top (caller unwinds). |
| 76797 | */ |
| 76798 | DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) { |
| 76799 | duk_activation *act; |
| 76800 | duk_hcompfunc *h_func; |
| 76801 | duk_idx_t clamp_top; |
| 76802 | |
| 76803 | DUK_ASSERT(thr != NULL); |
| 76804 | act = thr->callstack_curr; |
| 76805 | DUK_ASSERT(act != NULL); |
| 76806 | DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); |
| 76807 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); |
| 76808 | |
| 76809 | /* Clamp so that values at 'clamp_top' and above are wiped and won't |
| 76810 | * retain reachable garbage. Then extend to 'nregs' because we're |
| 76811 | * returning to an ECMAScript function. |
| 76812 | */ |
| 76813 | |
| 76814 | h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); |
| 76815 | |
| 76816 | thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff); |
| 76817 | DUK_ASSERT(act->retval_byteoff >= act->bottom_byteoff); |
| 76818 | clamp_top = (duk_idx_t) ((act->retval_byteoff - act->bottom_byteoff + sizeof(duk_tval)) / sizeof(duk_tval)); /* +1 = one retval */ |
| 76819 | duk_set_top_and_wipe(thr, h_func->nregs, clamp_top); |
| 76820 | |
| 76821 | DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff); |
| 76822 | thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff); |
| 76823 | |
| 76824 | /* XXX: a best effort shrink check would be OK here */ |
| 76825 | } |
| 76826 | |
| 76827 | /* Reconfigure value stack for an ECMAScript catcher. Use topmost catcher |
| 76828 | * in 'act'. |
| 76829 | */ |
| 76830 | DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_activation *act) { |
| 76831 | duk_catcher *cat; |
| 76832 | duk_hcompfunc *h_func; |
| 76833 | duk_size_t idx_bottom; |
| 76834 | duk_idx_t clamp_top; |
| 76835 | |
| 76836 | DUK_ASSERT(thr != NULL); |
| 76837 | DUK_ASSERT(act != NULL); |
| 76838 | DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); |
| 76839 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act))); |
| 76840 | cat = act->cat; |
| 76841 | DUK_ASSERT(cat != NULL); |
| 76842 | |
| 76843 | h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); |
| 76844 | |
| 76845 | thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff); |
| 76846 | idx_bottom = (duk_size_t) (thr->valstack_bottom - thr->valstack); |
| 76847 | DUK_ASSERT(cat->idx_base >= idx_bottom); |
| 76848 | clamp_top = (duk_idx_t) (cat->idx_base - idx_bottom + 2); /* +2 = catcher value, catcher lj_type */ |
| 76849 | duk_set_top_and_wipe(thr, h_func->nregs, clamp_top); |
| 76850 | |
| 76851 | DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff); |
| 76852 | thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff); |
| 76853 | |
| 76854 | /* XXX: a best effort shrink check would be OK here */ |
| 76855 | } |
| 76856 | |
| 76857 | /* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. |
| 76858 | * No side effects. |
| 76859 | */ |
| 76860 | DUK_LOCAL void duk__set_catcher_regs_norz(duk_hthread *thr, duk_catcher *cat, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) { |
| 76861 | duk_tval *tv1; |
| 76862 | |
| 76863 | DUK_ASSERT(thr != NULL); |
| 76864 | DUK_ASSERT(tv_val_unstable != NULL); |
| 76865 | |
| 76866 | tv1 = thr->valstack + cat->idx_base; |
| 76867 | DUK_ASSERT(tv1 < thr->valstack_top); |
| 76868 | DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr, tv1, tv_val_unstable); |
| 76869 | |
| 76870 | tv1++; |
| 76871 | DUK_ASSERT(tv1 == thr->valstack + cat->idx_base + 1); |
| 76872 | DUK_ASSERT(tv1 < thr->valstack_top); |
| 76873 | DUK_TVAL_SET_U32_UPDREF_NORZ(thr, tv1, (duk_uint32_t) lj_type); |
| 76874 | } |
| 76875 | |
| 76876 | DUK_LOCAL void duk__handle_catch_part1(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type, volatile duk_bool_t *out_delayed_catch_setup) { |
| 76877 | duk_activation *act; |
| 76878 | duk_catcher *cat; |
| 76879 | |
| 76880 | DUK_ASSERT(thr != NULL); |
| 76881 | DUK_ASSERT(tv_val_unstable != NULL); |
| 76882 | |
| 76883 | act = thr->callstack_curr; |
| 76884 | DUK_ASSERT(act != NULL); |
| 76885 | DUK_DD(DUK_DDPRINT("handle catch, part 1; act=%!A, cat=%!C" , act, act->cat)); |
| 76886 | |
| 76887 | DUK_ASSERT(act->cat != NULL); |
| 76888 | DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF); |
| 76889 | |
| 76890 | /* The part1/part2 split could also be made here at the very top |
| 76891 | * of catch handling. Value stack would be reconfigured inside |
| 76892 | * part2's protection. Value stack reconfiguration should be free |
| 76893 | * of allocs, however. |
| 76894 | */ |
| 76895 | |
| 76896 | duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type); |
| 76897 | |
| 76898 | DUK_ASSERT(thr->callstack_top >= 1); |
| 76899 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 76900 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); |
| 76901 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); |
| 76902 | |
| 76903 | DUK_ASSERT(thr->callstack_top >= 1); |
| 76904 | DUK_ASSERT(act == thr->callstack_curr); |
| 76905 | DUK_ASSERT(act != NULL); |
| 76906 | duk__reconfig_valstack_ecma_catcher(thr, act); |
| 76907 | |
| 76908 | DUK_ASSERT(thr->callstack_top >= 1); |
| 76909 | DUK_ASSERT(act == thr->callstack_curr); |
| 76910 | DUK_ASSERT(act != NULL); |
| 76911 | cat = act->cat; |
| 76912 | DUK_ASSERT(cat != NULL); |
| 76913 | |
| 76914 | act->curr_pc = cat->pc_base + 0; /* +0 = catch */ |
| 76915 | |
| 76916 | /* |
| 76917 | * If the catch block has an automatic catch variable binding, |
| 76918 | * we need to create a lexical environment for it which requires |
| 76919 | * allocations. Move out of "error handling state" before the |
| 76920 | * allocations to avoid e.g. out-of-memory errors (leading to |
| 76921 | * GH-2022 or similar). |
| 76922 | */ |
| 76923 | |
| 76924 | if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)) { |
| 76925 | DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding, handle in part 2" )); |
| 76926 | *out_delayed_catch_setup = 1; |
| 76927 | } else { |
| 76928 | DUK_DDD(DUK_DDDPRINT("catcher has no catch binding" )); |
| 76929 | } |
| 76930 | |
| 76931 | DUK_CAT_CLEAR_CATCH_ENABLED(cat); |
| 76932 | } |
| 76933 | |
| 76934 | DUK_LOCAL void duk__handle_catch_part2(duk_hthread *thr) { |
| 76935 | duk_activation *act; |
| 76936 | duk_catcher *cat; |
| 76937 | duk_hdecenv *new_env; |
| 76938 | |
| 76939 | DUK_ASSERT(thr != NULL); |
| 76940 | |
| 76941 | act = thr->callstack_curr; |
| 76942 | DUK_ASSERT(act != NULL); |
| 76943 | DUK_DD(DUK_DDPRINT("handle catch, part 2; act=%!A, cat=%!C" , act, act->cat)); |
| 76944 | |
| 76945 | DUK_ASSERT(act->cat != NULL); |
| 76946 | cat = act->cat; |
| 76947 | DUK_ASSERT(cat != NULL); |
| 76948 | DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF); |
| 76949 | DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)); |
| 76950 | DUK_ASSERT(thr->valstack + cat->idx_base < thr->valstack_top); |
| 76951 | |
| 76952 | /* |
| 76953 | * Create lexical environment for the catch clause, containing |
| 76954 | * a binding for the caught value. |
| 76955 | * |
| 76956 | * The binding is mutable (= writable) but not deletable. |
| 76957 | * Step 4 for the catch production in E5 Section 12.14; |
| 76958 | * no value is given for CreateMutableBinding 'D' argument, |
| 76959 | * which implies the binding is not deletable. |
| 76960 | */ |
| 76961 | |
| 76962 | if (act->lex_env == NULL) { |
| 76963 | DUK_ASSERT(act->var_env == NULL); |
| 76964 | DUK_DDD(DUK_DDDPRINT("delayed environment initialization" )); |
| 76965 | |
| 76966 | duk_js_init_activation_environment_records_delayed(thr, act); |
| 76967 | DUK_ASSERT(act == thr->callstack_curr); |
| 76968 | DUK_ASSERT(act != NULL); |
| 76969 | } |
| 76970 | DUK_ASSERT(act->lex_env != NULL); |
| 76971 | DUK_ASSERT(act->var_env != NULL); |
| 76972 | DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); |
| 76973 | |
| 76974 | new_env = duk_hdecenv_alloc(thr, |
| 76975 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 76976 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); |
| 76977 | DUK_ASSERT(new_env != NULL); |
| 76978 | duk_push_hobject(thr, (duk_hobject *) new_env); |
| 76979 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); |
| 76980 | DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO" , (duk_heaphdr *) new_env)); |
| 76981 | |
| 76982 | /* Note: currently the catch binding is handled without a register |
| 76983 | * binding because we don't support dynamic register bindings (they |
| 76984 | * must be fixed for an entire function). So, there is no need to |
| 76985 | * record regbases etc. |
| 76986 | */ |
| 76987 | |
| 76988 | /* [ ...env ] */ |
| 76989 | |
| 76990 | DUK_ASSERT(cat->h_varname != NULL); |
| 76991 | duk_push_hstring(thr, cat->h_varname); |
| 76992 | DUK_ASSERT(thr->valstack + cat->idx_base < thr->valstack_top); |
| 76993 | duk_push_tval(thr, thr->valstack + cat->idx_base); |
| 76994 | duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */ |
| 76995 | |
| 76996 | /* [ ... env ] */ |
| 76997 | |
| 76998 | DUK_ASSERT(act == thr->callstack_curr); |
| 76999 | DUK_ASSERT(act != NULL); |
| 77000 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env); |
| 77001 | act->lex_env = (duk_hobject *) new_env; |
| 77002 | DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); /* reachable through activation */ |
| 77003 | /* Net refcount change to act->lex_env is 0: incref for new_env's |
| 77004 | * prototype, decref for act->lex_env overwrite. |
| 77005 | */ |
| 77006 | |
| 77007 | DUK_CAT_SET_LEXENV_ACTIVE(cat); |
| 77008 | |
| 77009 | duk_pop_unsafe(thr); |
| 77010 | |
| 77011 | DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO" , (duk_heaphdr *) new_env)); |
| 77012 | } |
| 77013 | |
| 77014 | DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) { |
| 77015 | duk_activation *act; |
| 77016 | duk_catcher *cat; |
| 77017 | |
| 77018 | DUK_ASSERT(thr != NULL); |
| 77019 | DUK_ASSERT(tv_val_unstable != NULL); |
| 77020 | |
| 77021 | act = thr->callstack_curr; |
| 77022 | DUK_ASSERT(act != NULL); |
| 77023 | DUK_ASSERT(act->cat != NULL); |
| 77024 | DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF); |
| 77025 | |
| 77026 | duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type); |
| 77027 | |
| 77028 | DUK_ASSERT(thr->callstack_top >= 1); |
| 77029 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 77030 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); |
| 77031 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); |
| 77032 | |
| 77033 | DUK_ASSERT(thr->callstack_top >= 1); |
| 77034 | DUK_ASSERT(act == thr->callstack_curr); |
| 77035 | DUK_ASSERT(act != NULL); |
| 77036 | duk__reconfig_valstack_ecma_catcher(thr, act); |
| 77037 | |
| 77038 | DUK_ASSERT(thr->callstack_top >= 1); |
| 77039 | DUK_ASSERT(act == thr->callstack_curr); |
| 77040 | DUK_ASSERT(act != NULL); |
| 77041 | cat = act->cat; |
| 77042 | DUK_ASSERT(cat != NULL); |
| 77043 | |
| 77044 | act->curr_pc = cat->pc_base + 1; /* +1 = finally */ |
| 77045 | |
| 77046 | DUK_CAT_CLEAR_FINALLY_ENABLED(cat); |
| 77047 | } |
| 77048 | |
| 77049 | DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_small_uint_t lj_type) { |
| 77050 | duk_activation *act; |
| 77051 | duk_catcher *cat; |
| 77052 | |
| 77053 | DUK_ASSERT(thr != NULL); |
| 77054 | |
| 77055 | DUK_ASSERT(thr->callstack_top >= 1); |
| 77056 | act = thr->callstack_curr; |
| 77057 | DUK_ASSERT(act != NULL); |
| 77058 | DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL); |
| 77059 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act))); |
| 77060 | |
| 77061 | /* +0 = break, +1 = continue */ |
| 77062 | cat = act->cat; |
| 77063 | DUK_ASSERT(cat != NULL); |
| 77064 | DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL); |
| 77065 | |
| 77066 | act->curr_pc = cat->pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0); |
| 77067 | |
| 77068 | /* valstack should not need changes */ |
| 77069 | #if defined(DUK_USE_ASSERTIONS) |
| 77070 | DUK_ASSERT(thr->callstack_top >= 1); |
| 77071 | DUK_ASSERT(act == thr->callstack_curr); |
| 77072 | DUK_ASSERT(act != NULL); |
| 77073 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) == |
| 77074 | (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs); |
| 77075 | #endif |
| 77076 | } |
| 77077 | |
| 77078 | /* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and |
| 77079 | * when a RETURN opcode terminates a thread and yields to the resumer. |
| 77080 | * Caller unwinds so that top of callstack is the activation we return to. |
| 77081 | */ |
| 77082 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 77083 | DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_tval *tv_val_unstable) { |
| 77084 | duk_activation *act_resumer; |
| 77085 | duk_tval *tv1; |
| 77086 | |
| 77087 | DUK_ASSERT(thr != NULL); |
| 77088 | DUK_ASSERT(resumer != NULL); |
| 77089 | DUK_ASSERT(tv_val_unstable != NULL); |
| 77090 | act_resumer = resumer->callstack_curr; |
| 77091 | DUK_ASSERT(act_resumer != NULL); |
| 77092 | DUK_ASSERT(DUK_ACT_GET_FUNC(act_resumer) != NULL); |
| 77093 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer))); /* resume caller must be an ECMAScript func */ |
| 77094 | |
| 77095 | tv1 = (duk_tval *) (void *) ((duk_uint8_t *) resumer->valstack + act_resumer->retval_byteoff); /* return value from Duktape.Thread.resume() */ |
| 77096 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */ /* XXX: avoid side effects */ |
| 77097 | |
| 77098 | duk__reconfig_valstack_ecma_return(resumer); |
| 77099 | |
| 77100 | /* caller must change active thread, and set thr->resumer to NULL */ |
| 77101 | } |
| 77102 | #endif /* DUK_USE_COROUTINE_SUPPORT */ |
| 77103 | |
| 77104 | DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation *entry_act, volatile duk_bool_t *out_delayed_catch_setup) { |
| 77105 | duk_small_uint_t retval = DUK__LONGJMP_RESTART; |
| 77106 | |
| 77107 | DUK_ASSERT(thr != NULL); |
| 77108 | DUK_ASSERT(entry_act != NULL); |
| 77109 | |
| 77110 | /* 'thr' is the current thread, as no-one resumes except us and we |
| 77111 | * switch 'thr' in that case. |
| 77112 | */ |
| 77113 | DUK_ASSERT(thr == thr->heap->curr_thread); |
| 77114 | |
| 77115 | /* |
| 77116 | * (Re)try handling the longjmp. |
| 77117 | * |
| 77118 | * A longjmp handler may convert the longjmp to a different type and |
| 77119 | * "virtually" rethrow by goto'ing to 'check_longjmp'. Before the goto, |
| 77120 | * the following must be updated: |
| 77121 | * - the heap 'lj' state |
| 77122 | * - 'thr' must reflect the "throwing" thread |
| 77123 | */ |
| 77124 | |
| 77125 | check_longjmp: |
| 77126 | |
| 77127 | DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld, top=%ld" , |
| 77128 | (long) thr->heap->lj.type, |
| 77129 | (duk_tval *) &thr->heap->lj.value1, |
| 77130 | (duk_tval *) &thr->heap->lj.value2, |
| 77131 | (long) thr->heap->lj.iserror, |
| 77132 | (long) duk_get_top(thr))); |
| 77133 | |
| 77134 | switch (thr->heap->lj.type) { |
| 77135 | |
| 77136 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 77137 | case DUK_LJ_TYPE_RESUME: { |
| 77138 | /* |
| 77139 | * Note: lj.value1 is 'value', lj.value2 is 'resumee'. |
| 77140 | * This differs from YIELD. |
| 77141 | */ |
| 77142 | |
| 77143 | duk_tval *tv; |
| 77144 | duk_tval *tv2; |
| 77145 | duk_hthread *resumee; |
| 77146 | |
| 77147 | /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */ |
| 77148 | |
| 77149 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */ |
| 77150 | DUK_ASSERT(thr->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ |
| 77151 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 77152 | DUK_ASSERT(thr->callstack_curr->parent != NULL); |
| 77153 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && |
| 77154 | DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && |
| 77155 | ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume); |
| 77156 | |
| 77157 | tv = &thr->heap->lj.value2; /* resumee */ |
| 77158 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv)); |
| 77159 | DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL); |
| 77160 | DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv))); |
| 77161 | resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv); |
| 77162 | |
| 77163 | DUK_ASSERT(resumee != NULL); |
| 77164 | DUK_ASSERT(resumee->resumer == NULL); |
| 77165 | DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE || |
| 77166 | resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */ |
| 77167 | DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || |
| 77168 | resumee->callstack_top >= 2); /* YIELDED: ECMAScript activation + Duktape.Thread.yield() activation */ |
| 77169 | DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED || |
| 77170 | (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL && |
| 77171 | DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) && |
| 77172 | ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield)); |
| 77173 | DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE || |
| 77174 | resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */ |
| 77175 | |
| 77176 | if (thr->heap->lj.iserror) { |
| 77177 | /* |
| 77178 | * Throw the error in the resumed thread's context; the |
| 77179 | * error value is pushed onto the resumee valstack. |
| 77180 | * |
| 77181 | * Note: the callstack of the target may empty in this case |
| 77182 | * too (i.e. the target thread has never been resumed). The |
| 77183 | * value stack will contain the initial function in that case, |
| 77184 | * which we simply ignore. |
| 77185 | */ |
| 77186 | |
| 77187 | DUK_ASSERT(resumee->resumer == NULL); |
| 77188 | resumee->resumer = thr; |
| 77189 | DUK_HTHREAD_INCREF(thr, thr); |
| 77190 | resumee->state = DUK_HTHREAD_STATE_RUNNING; |
| 77191 | thr->state = DUK_HTHREAD_STATE_RESUMED; |
| 77192 | DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); |
| 77193 | thr = resumee; |
| 77194 | |
| 77195 | thr->heap->lj.type = DUK_LJ_TYPE_THROW; |
| 77196 | |
| 77197 | /* thr->heap->lj.value1 is already the value to throw */ |
| 77198 | /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */ |
| 77199 | |
| 77200 | DUK_ASSERT(thr->heap->lj.iserror); /* already set */ |
| 77201 | |
| 77202 | DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate" )); |
| 77203 | goto check_longjmp; |
| 77204 | } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) { |
| 77205 | /* Unwind previous Duktape.Thread.yield() call. The |
| 77206 | * activation remaining must always be an ECMAScript |
| 77207 | * call now (yield() accepts calls from ECMAScript |
| 77208 | * only). |
| 77209 | */ |
| 77210 | duk_activation *act_resumee; |
| 77211 | |
| 77212 | DUK_ASSERT(resumee->callstack_top >= 2); |
| 77213 | act_resumee = resumee->callstack_curr; /* Duktape.Thread.yield() */ |
| 77214 | DUK_ASSERT(act_resumee != NULL); |
| 77215 | act_resumee = act_resumee->parent; /* ECMAScript call site for yield() */ |
| 77216 | DUK_ASSERT(act_resumee != NULL); |
| 77217 | |
| 77218 | tv = (duk_tval *) (void *) ((duk_uint8_t *) resumee->valstack + act_resumee->retval_byteoff); /* return value from Duktape.Thread.yield() */ |
| 77219 | DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top); |
| 77220 | tv2 = &thr->heap->lj.value1; |
| 77221 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */ /* XXX: avoid side effects */ |
| 77222 | |
| 77223 | duk_hthread_activation_unwind_norz(resumee); /* unwind to 'yield' caller */ |
| 77224 | /* no need to unwind catch stack */ |
| 77225 | |
| 77226 | duk__reconfig_valstack_ecma_return(resumee); |
| 77227 | |
| 77228 | DUK_ASSERT(resumee->resumer == NULL); |
| 77229 | resumee->resumer = thr; |
| 77230 | DUK_HTHREAD_INCREF(thr, thr); |
| 77231 | resumee->state = DUK_HTHREAD_STATE_RUNNING; |
| 77232 | thr->state = DUK_HTHREAD_STATE_RESUMED; |
| 77233 | DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); |
| 77234 | #if 0 |
| 77235 | thr = resumee; /* not needed, as we exit right away */ |
| 77236 | #endif |
| 77237 | DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee" )); |
| 77238 | retval = DUK__LONGJMP_RESTART; |
| 77239 | goto wipe_and_return; |
| 77240 | } else { |
| 77241 | /* Initial resume call. */ |
| 77242 | duk_small_uint_t call_flags; |
| 77243 | duk_int_t setup_rc; |
| 77244 | |
| 77245 | /* resumee: [... initial_func] (currently actually: [initial_func]) */ |
| 77246 | |
| 77247 | duk_push_undefined(resumee); |
| 77248 | tv = &thr->heap->lj.value1; |
| 77249 | duk_push_tval(resumee, tv); |
| 77250 | |
| 77251 | /* resumee: [... initial_func undefined(= this) resume_value ] */ |
| 77252 | |
| 77253 | call_flags = DUK_CALL_FLAG_ALLOW_ECMATOECMA; /* not tailcall, ecma-to-ecma (assumed to succeed) */ |
| 77254 | |
| 77255 | setup_rc = duk_handle_call_unprotected_nargs(resumee, 1 /*nargs*/, call_flags); |
| 77256 | if (setup_rc == 0) { |
| 77257 | /* This shouldn't happen; Duktape.Thread.resume() |
| 77258 | * should make sure of that. If it does happen |
| 77259 | * this internal error will propagate out of the |
| 77260 | * executor which can be quite misleading. |
| 77261 | */ |
| 77262 | DUK_ERROR_INTERNAL(thr); |
| 77263 | DUK_WO_NORETURN(return 0;); |
| 77264 | } |
| 77265 | |
| 77266 | DUK_ASSERT(resumee->resumer == NULL); |
| 77267 | resumee->resumer = thr; |
| 77268 | DUK_HTHREAD_INCREF(thr, thr); |
| 77269 | resumee->state = DUK_HTHREAD_STATE_RUNNING; |
| 77270 | thr->state = DUK_HTHREAD_STATE_RESUMED; |
| 77271 | DUK_HEAP_SWITCH_THREAD(thr->heap, resumee); |
| 77272 | #if 0 |
| 77273 | thr = resumee; /* not needed, as we exit right away */ |
| 77274 | #endif |
| 77275 | DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee" )); |
| 77276 | retval = DUK__LONGJMP_RESTART; |
| 77277 | goto wipe_and_return; |
| 77278 | } |
| 77279 | DUK_UNREACHABLE(); |
| 77280 | break; /* never here */ |
| 77281 | } |
| 77282 | |
| 77283 | case DUK_LJ_TYPE_YIELD: { |
| 77284 | /* |
| 77285 | * Currently only allowed only if yielding thread has only |
| 77286 | * ECMAScript activations (except for the Duktape.Thread.yield() |
| 77287 | * call at the callstack top) and none of them constructor |
| 77288 | * calls. |
| 77289 | * |
| 77290 | * This excludes the 'entry' thread which will always have |
| 77291 | * a preventcount > 0. |
| 77292 | */ |
| 77293 | |
| 77294 | duk_hthread *resumer; |
| 77295 | |
| 77296 | /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */ |
| 77297 | |
| 77298 | #if 0 /* entry_thread not available for assert */ |
| 77299 | DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */ |
| 77300 | #endif |
| 77301 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */ |
| 77302 | DUK_ASSERT(thr->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.yield() activation */ |
| 77303 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 77304 | DUK_ASSERT(thr->callstack_curr->parent != NULL); |
| 77305 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL && |
| 77306 | DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) && |
| 77307 | ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield); |
| 77308 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL && |
| 77309 | DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* an ECMAScript function */ |
| 77310 | |
| 77311 | resumer = thr->resumer; |
| 77312 | |
| 77313 | DUK_ASSERT(resumer != NULL); |
| 77314 | DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */ |
| 77315 | DUK_ASSERT(resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ |
| 77316 | DUK_ASSERT(resumer->callstack_curr != NULL); |
| 77317 | DUK_ASSERT(resumer->callstack_curr->parent != NULL); |
| 77318 | DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL && |
| 77319 | DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) && |
| 77320 | ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume); |
| 77321 | DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent) != NULL && |
| 77322 | DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent))); /* an ECMAScript function */ |
| 77323 | |
| 77324 | if (thr->heap->lj.iserror) { |
| 77325 | thr->state = DUK_HTHREAD_STATE_YIELDED; |
| 77326 | thr->resumer = NULL; |
| 77327 | DUK_HTHREAD_DECREF_NORZ(thr, resumer); |
| 77328 | resumer->state = DUK_HTHREAD_STATE_RUNNING; |
| 77329 | DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); |
| 77330 | thr = resumer; |
| 77331 | |
| 77332 | thr->heap->lj.type = DUK_LJ_TYPE_THROW; |
| 77333 | /* lj.value1 is already set */ |
| 77334 | DUK_ASSERT(thr->heap->lj.iserror); /* already set */ |
| 77335 | |
| 77336 | DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate" )); |
| 77337 | goto check_longjmp; |
| 77338 | } else { |
| 77339 | /* When handling the yield, the last reference to |
| 77340 | * 'thr' may disappear. |
| 77341 | */ |
| 77342 | |
| 77343 | DUK_GC_TORTURE(resumer->heap); |
| 77344 | duk_hthread_activation_unwind_norz(resumer); |
| 77345 | DUK_GC_TORTURE(resumer->heap); |
| 77346 | thr->state = DUK_HTHREAD_STATE_YIELDED; |
| 77347 | thr->resumer = NULL; |
| 77348 | DUK_HTHREAD_DECREF_NORZ(thr, resumer); |
| 77349 | resumer->state = DUK_HTHREAD_STATE_RUNNING; |
| 77350 | DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); |
| 77351 | duk__handle_yield(thr, resumer, &thr->heap->lj.value1); |
| 77352 | thr = resumer; |
| 77353 | DUK_GC_TORTURE(resumer->heap); |
| 77354 | |
| 77355 | DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer" )); |
| 77356 | retval = DUK__LONGJMP_RESTART; |
| 77357 | goto wipe_and_return; |
| 77358 | } |
| 77359 | DUK_UNREACHABLE(); |
| 77360 | break; /* never here */ |
| 77361 | } |
| 77362 | #endif /* DUK_USE_COROUTINE_SUPPORT */ |
| 77363 | |
| 77364 | case DUK_LJ_TYPE_THROW: { |
| 77365 | /* |
| 77366 | * Three possible outcomes: |
| 77367 | * * A try or finally catcher is found => resume there. |
| 77368 | * (or) |
| 77369 | * * The error propagates to the bytecode executor entry |
| 77370 | * level (and we're in the entry thread) => rethrow |
| 77371 | * with a new longjmp(), after restoring the previous |
| 77372 | * catchpoint. |
| 77373 | * * The error is not caught in the current thread, so |
| 77374 | * the thread finishes with an error. This works like |
| 77375 | * a yielded error, except that the thread is finished |
| 77376 | * and can no longer be resumed. (There is always a |
| 77377 | * resumer in this case.) |
| 77378 | * |
| 77379 | * Note: until we hit the entry level, there can only be |
| 77380 | * ECMAScript activations. |
| 77381 | */ |
| 77382 | |
| 77383 | duk_activation *act; |
| 77384 | duk_catcher *cat; |
| 77385 | duk_hthread *resumer; |
| 77386 | |
| 77387 | for (;;) { |
| 77388 | act = thr->callstack_curr; |
| 77389 | if (act == NULL) { |
| 77390 | break; |
| 77391 | } |
| 77392 | |
| 77393 | for (;;) { |
| 77394 | cat = act->cat; |
| 77395 | if (cat == NULL) { |
| 77396 | break; |
| 77397 | } |
| 77398 | |
| 77399 | if (DUK_CAT_HAS_CATCH_ENABLED(cat)) { |
| 77400 | DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF); |
| 77401 | |
| 77402 | DUK_DDD(DUK_DDDPRINT("before catch part 1: thr=%p, act=%p, cat=%p" , |
| 77403 | (void *) thr, (void *) act, (void *) act->cat)); |
| 77404 | duk__handle_catch_part1(thr, |
| 77405 | &thr->heap->lj.value1, |
| 77406 | DUK_LJ_TYPE_THROW, |
| 77407 | out_delayed_catch_setup); |
| 77408 | |
| 77409 | DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution" )); |
| 77410 | retval = DUK__LONGJMP_RESTART; |
| 77411 | goto wipe_and_return; |
| 77412 | } |
| 77413 | |
| 77414 | if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) { |
| 77415 | DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF); |
| 77416 | DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); |
| 77417 | |
| 77418 | duk__handle_finally(thr, |
| 77419 | &thr->heap->lj.value1, |
| 77420 | DUK_LJ_TYPE_THROW); |
| 77421 | |
| 77422 | DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution" )); |
| 77423 | retval = DUK__LONGJMP_RESTART; |
| 77424 | goto wipe_and_return; |
| 77425 | } |
| 77426 | |
| 77427 | duk_hthread_catcher_unwind_norz(thr, act); |
| 77428 | } |
| 77429 | |
| 77430 | if (act == entry_act) { |
| 77431 | /* Not caught by anything before entry level; rethrow and let the |
| 77432 | * final catcher finish unwinding (esp. value stack). |
| 77433 | */ |
| 77434 | DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor" )); |
| 77435 | retval = DUK__LONGJMP_RETHROW; |
| 77436 | goto just_return; |
| 77437 | } |
| 77438 | |
| 77439 | duk_hthread_activation_unwind_norz(thr); |
| 77440 | } |
| 77441 | |
| 77442 | DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp" )); |
| 77443 | |
| 77444 | /* Not caught by current thread, thread terminates (yield error to resumer); |
| 77445 | * note that this may cause a cascade if the resumer terminates with an uncaught |
| 77446 | * exception etc (this is OK, but needs careful testing). |
| 77447 | */ |
| 77448 | |
| 77449 | DUK_ASSERT(thr->resumer != NULL); |
| 77450 | DUK_ASSERT(thr->resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ |
| 77451 | DUK_ASSERT(thr->resumer->callstack_curr != NULL); |
| 77452 | DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL); |
| 77453 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL && |
| 77454 | DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an ECMAScript function */ |
| 77455 | |
| 77456 | resumer = thr->resumer; |
| 77457 | |
| 77458 | /* reset longjmp */ |
| 77459 | |
| 77460 | DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); /* already set */ |
| 77461 | /* lj.value1 already set */ |
| 77462 | |
| 77463 | duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */ |
| 77464 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); |
| 77465 | |
| 77466 | thr->resumer = NULL; |
| 77467 | DUK_HTHREAD_DECREF_NORZ(thr, resumer); |
| 77468 | resumer->state = DUK_HTHREAD_STATE_RUNNING; |
| 77469 | DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); |
| 77470 | thr = resumer; |
| 77471 | goto check_longjmp; |
| 77472 | } |
| 77473 | |
| 77474 | case DUK_LJ_TYPE_BREAK: /* pseudotypes, not used in actual longjmps */ |
| 77475 | case DUK_LJ_TYPE_CONTINUE: |
| 77476 | case DUK_LJ_TYPE_RETURN: |
| 77477 | case DUK_LJ_TYPE_NORMAL: |
| 77478 | default: { |
| 77479 | /* should never happen, but be robust */ |
| 77480 | DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error" , (long) thr->heap->lj.type)); |
| 77481 | goto convert_to_internal_error; |
| 77482 | } |
| 77483 | |
| 77484 | } /* end switch */ |
| 77485 | |
| 77486 | DUK_UNREACHABLE(); |
| 77487 | |
| 77488 | wipe_and_return: |
| 77489 | DUK_DD(DUK_DDPRINT("handling longjmp done, wipe-and-return, top=%ld" , |
| 77490 | (long) duk_get_top(thr))); |
| 77491 | thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN; |
| 77492 | thr->heap->lj.iserror = 0; |
| 77493 | |
| 77494 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */ |
| 77495 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */ |
| 77496 | |
| 77497 | DUK_GC_TORTURE(thr->heap); |
| 77498 | |
| 77499 | just_return: |
| 77500 | return retval; |
| 77501 | |
| 77502 | convert_to_internal_error: |
| 77503 | /* This could also be thrown internally (set the error, goto check_longjmp), |
| 77504 | * but it's better for internal errors to bubble outwards so that we won't |
| 77505 | * infinite loop in this catchpoint. |
| 77506 | */ |
| 77507 | DUK_ERROR_INTERNAL(thr); |
| 77508 | DUK_WO_NORETURN(return 0;); |
| 77509 | } |
| 77510 | |
| 77511 | /* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE |
| 77512 | * handling because it has a measurable performance impact in ordinary |
| 77513 | * environments and an extreme impact in Emscripten (GH-342). |
| 77514 | */ |
| 77515 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_break_or_continue(duk_hthread *thr, |
| 77516 | duk_uint_t label_id, |
| 77517 | duk_small_uint_t lj_type) { |
| 77518 | duk_activation *act; |
| 77519 | duk_catcher *cat; |
| 77520 | |
| 77521 | DUK_ASSERT(thr != NULL); |
| 77522 | |
| 77523 | /* Find a matching label catcher or 'finally' catcher in |
| 77524 | * the same function, unwinding catchers as we go. |
| 77525 | * |
| 77526 | * A label catcher must always exist and will match unless |
| 77527 | * a 'finally' captures the break/continue first. It is the |
| 77528 | * compiler's responsibility to ensure that labels are used |
| 77529 | * correctly. |
| 77530 | */ |
| 77531 | |
| 77532 | act = thr->callstack_curr; |
| 77533 | DUK_ASSERT(act != NULL); |
| 77534 | |
| 77535 | for (;;) { |
| 77536 | cat = act->cat; |
| 77537 | if (cat == NULL) { |
| 77538 | break; |
| 77539 | } |
| 77540 | |
| 77541 | DUK_DDD(DUK_DDDPRINT("considering catcher %p: type=%ld label=%ld" , |
| 77542 | (void *) cat, |
| 77543 | (long) DUK_CAT_GET_TYPE(cat), |
| 77544 | (long) DUK_CAT_GET_LABEL(cat))); |
| 77545 | |
| 77546 | /* XXX: bit mask test; FINALLY <-> TCF, single bit mask would suffice? */ |
| 77547 | |
| 77548 | if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF && |
| 77549 | DUK_CAT_HAS_FINALLY_ENABLED(cat)) { |
| 77550 | duk_tval tv_tmp; |
| 77551 | |
| 77552 | DUK_TVAL_SET_U32(&tv_tmp, (duk_uint32_t) label_id); |
| 77553 | duk__handle_finally(thr, &tv_tmp, lj_type); |
| 77554 | |
| 77555 | DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution" )); |
| 77556 | return; |
| 77557 | } |
| 77558 | if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL && |
| 77559 | (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) { |
| 77560 | duk__handle_label(thr, lj_type); |
| 77561 | |
| 77562 | DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution" )); |
| 77563 | return; |
| 77564 | } |
| 77565 | |
| 77566 | duk_hthread_catcher_unwind_norz(thr, act); |
| 77567 | } |
| 77568 | |
| 77569 | /* Should never happen, but be robust. */ |
| 77570 | DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error" )); |
| 77571 | DUK_ERROR_INTERNAL(thr); |
| 77572 | DUK_WO_NORETURN(return;); |
| 77573 | } |
| 77574 | |
| 77575 | /* Handle a RETURN opcode. Avoid using longjmp() for return handling because |
| 77576 | * it has a measurable performance impact in ordinary environments and an extreme |
| 77577 | * impact in Emscripten (GH-342). Return value is on value stack top. |
| 77578 | */ |
| 77579 | DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation *entry_act) { |
| 77580 | duk_tval *tv1; |
| 77581 | duk_tval *tv2; |
| 77582 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 77583 | duk_hthread *resumer; |
| 77584 | #endif |
| 77585 | duk_activation *act; |
| 77586 | duk_catcher *cat; |
| 77587 | |
| 77588 | /* We can directly access value stack here. */ |
| 77589 | |
| 77590 | DUK_ASSERT(thr != NULL); |
| 77591 | DUK_ASSERT(entry_act != NULL); |
| 77592 | DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); |
| 77593 | tv1 = thr->valstack_top - 1; |
| 77594 | DUK_TVAL_CHKFAST_INPLACE_FAST(tv1); /* fastint downgrade check for return values */ |
| 77595 | |
| 77596 | /* |
| 77597 | * Four possible outcomes: |
| 77598 | * |
| 77599 | * 1. A 'finally' in the same function catches the 'return'. |
| 77600 | * It may continue to propagate when 'finally' is finished, |
| 77601 | * or it may be neutralized by 'finally' (both handled by |
| 77602 | * ENDFIN). |
| 77603 | * |
| 77604 | * 2. The return happens at the entry level of the bytecode |
| 77605 | * executor, so return from the executor (in C stack). |
| 77606 | * |
| 77607 | * 3. There is a calling (ECMAScript) activation in the call |
| 77608 | * stack => return to it, in the same executor instance. |
| 77609 | * |
| 77610 | * 4. There is no calling activation, and the thread is |
| 77611 | * terminated. There is always a resumer in this case, |
| 77612 | * which gets the return value similarly to a 'yield' |
| 77613 | * (except that the current thread can no longer be |
| 77614 | * resumed). |
| 77615 | */ |
| 77616 | |
| 77617 | DUK_ASSERT(thr != NULL); |
| 77618 | DUK_ASSERT(thr->callstack_top >= 1); |
| 77619 | |
| 77620 | act = thr->callstack_curr; |
| 77621 | DUK_ASSERT(act != NULL); |
| 77622 | |
| 77623 | for (;;) { |
| 77624 | cat = act->cat; |
| 77625 | if (cat == NULL) { |
| 77626 | break; |
| 77627 | } |
| 77628 | |
| 77629 | if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF && |
| 77630 | DUK_CAT_HAS_FINALLY_ENABLED(cat)) { |
| 77631 | DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); |
| 77632 | duk__handle_finally(thr, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN); |
| 77633 | |
| 77634 | DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution" )); |
| 77635 | return DUK__RETHAND_RESTART; |
| 77636 | } |
| 77637 | |
| 77638 | duk_hthread_catcher_unwind_norz(thr, act); |
| 77639 | } |
| 77640 | |
| 77641 | if (act == entry_act) { |
| 77642 | /* Return to the bytecode executor caller who will unwind stacks |
| 77643 | * and handle constructor post-processing. |
| 77644 | * Return value is already on the stack top: [ ... retval ]. |
| 77645 | */ |
| 77646 | |
| 77647 | DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor" )); |
| 77648 | return DUK__RETHAND_FINISHED; |
| 77649 | } |
| 77650 | |
| 77651 | if (thr->callstack_top >= 2) { |
| 77652 | /* There is a caller; it MUST be an ECMAScript caller (otherwise it would |
| 77653 | * match entry_act check). |
| 77654 | */ |
| 77655 | DUK_DDD(DUK_DDDPRINT("return to ECMAScript caller, retval_byteoff=%ld, lj_value1=%!T" , |
| 77656 | (long) (thr->callstack_curr->parent->retval_byteoff), |
| 77657 | (duk_tval *) &thr->heap->lj.value1)); |
| 77658 | |
| 77659 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 77660 | DUK_ASSERT(thr->callstack_curr->parent != NULL); |
| 77661 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent))); /* must be ECMAScript */ |
| 77662 | |
| 77663 | #if defined(DUK_USE_ES6_PROXY) |
| 77664 | if (thr->callstack_curr->flags & (DUK_ACT_FLAG_CONSTRUCT | DUK_ACT_FLAG_CONSTRUCT_PROXY)) { |
| 77665 | duk_call_construct_postprocess(thr, thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY); /* side effects */ |
| 77666 | } |
| 77667 | #else |
| 77668 | if (thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT) { |
| 77669 | duk_call_construct_postprocess(thr, 0); /* side effects */ |
| 77670 | } |
| 77671 | #endif |
| 77672 | |
| 77673 | tv1 = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + thr->callstack_curr->parent->retval_byteoff); |
| 77674 | DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); |
| 77675 | tv2 = thr->valstack_top - 1; |
| 77676 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */ |
| 77677 | |
| 77678 | /* Catch stack unwind happens inline in callstack unwind. */ |
| 77679 | duk_hthread_activation_unwind_norz(thr); |
| 77680 | |
| 77681 | duk__reconfig_valstack_ecma_return(thr); |
| 77682 | |
| 77683 | DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller" )); |
| 77684 | return DUK__RETHAND_RESTART; |
| 77685 | } |
| 77686 | |
| 77687 | #if defined(DUK_USE_COROUTINE_SUPPORT) |
| 77688 | DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)" )); |
| 77689 | |
| 77690 | DUK_ASSERT(thr->resumer != NULL); |
| 77691 | DUK_ASSERT(thr->resumer->callstack_top >= 2); /* ECMAScript activation + Duktape.Thread.resume() activation */ |
| 77692 | DUK_ASSERT(thr->resumer->callstack_curr != NULL); |
| 77693 | DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL); |
| 77694 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL && |
| 77695 | DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) && |
| 77696 | ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */ |
| 77697 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL && |
| 77698 | DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent))); /* an ECMAScript function */ |
| 77699 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); |
| 77700 | DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED); |
| 77701 | |
| 77702 | resumer = thr->resumer; |
| 77703 | |
| 77704 | /* Share yield longjmp handler. |
| 77705 | * |
| 77706 | * This sequence of steps is a bit fragile (see GH-1845): |
| 77707 | * - We need the return value from 'thr' (resumed thread) value stack. |
| 77708 | * The termination unwinds its value stack, losing the value. |
| 77709 | * - We need a refcounted reference for 'thr', which may only exist |
| 77710 | * in the caller value stack. We can't unwind or reconfigure the |
| 77711 | * caller's value stack without potentially freeing 'thr'. |
| 77712 | * |
| 77713 | * Current approach is to capture the 'thr' return value and store |
| 77714 | * a reference to 'thr' in the caller value stack temporarily. This |
| 77715 | * keeps 'thr' reachable until final yield/return handling which |
| 77716 | * removes the references atomatically. |
| 77717 | */ |
| 77718 | |
| 77719 | DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom); |
| 77720 | duk_hthread_activation_unwind_norz(resumer); /* May remove last reference to 'thr', but is NORZ. */ |
| 77721 | duk_push_tval(resumer, thr->valstack_top - 1); /* Capture return value, side effect free. */ |
| 77722 | duk_push_hthread(resumer, thr); /* Make 'thr' reachable again, before side effects. */ |
| 77723 | |
| 77724 | duk_hthread_terminate(thr); /* Updates thread state, minimizes its allocations. */ |
| 77725 | thr->resumer = NULL; |
| 77726 | DUK_HTHREAD_DECREF(thr, resumer); |
| 77727 | DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED); |
| 77728 | |
| 77729 | resumer->state = DUK_HTHREAD_STATE_RUNNING; |
| 77730 | DUK_HEAP_SWITCH_THREAD(thr->heap, resumer); |
| 77731 | |
| 77732 | DUK_ASSERT(resumer->valstack_top - 2 >= resumer->valstack_bottom); |
| 77733 | duk__handle_yield(thr, resumer, resumer->valstack_top - 2); |
| 77734 | thr = NULL; /* 'thr' invalidated by call */ |
| 77735 | |
| 77736 | #if 0 |
| 77737 | thr = resumer; /* not needed */ |
| 77738 | #endif |
| 77739 | |
| 77740 | DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer" )); |
| 77741 | return DUK__RETHAND_RESTART; |
| 77742 | #else |
| 77743 | /* Without coroutine support this case should never happen. */ |
| 77744 | DUK_ERROR_INTERNAL(thr); |
| 77745 | DUK_WO_NORETURN(return 0;); |
| 77746 | #endif |
| 77747 | } |
| 77748 | |
| 77749 | /* |
| 77750 | * Executor interrupt handling |
| 77751 | * |
| 77752 | * The handler is called whenever the interrupt countdown reaches zero |
| 77753 | * (or below). The handler must perform whatever checks are activated, |
| 77754 | * e.g. check for cumulative step count to impose an execution step |
| 77755 | * limit or check for breakpoints or other debugger interaction. |
| 77756 | * |
| 77757 | * When the actions are done, the handler must reinit the interrupt |
| 77758 | * init and counter values. The 'init' value must indicate how many |
| 77759 | * bytecode instructions are executed before the next interrupt. The |
| 77760 | * counter must interface with the bytecode executor loop. Concretely, |
| 77761 | * the new init value is normally one higher than the new counter value. |
| 77762 | * For instance, to execute exactly one bytecode instruction the init |
| 77763 | * value is set to 1 and the counter to 0. If an error is thrown by the |
| 77764 | * interrupt handler, the counters are set to the same value (e.g. both |
| 77765 | * to 0 to cause an interrupt when the next bytecode instruction is about |
| 77766 | * to be executed after error handling). |
| 77767 | * |
| 77768 | * Maintaining the init/counter value properly is important for accurate |
| 77769 | * behavior. For instance, executor step limit needs a cumulative step |
| 77770 | * count which is simply computed as a sum of 'init' values. This must |
| 77771 | * work accurately even when single stepping. |
| 77772 | */ |
| 77773 | |
| 77774 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 77775 | |
| 77776 | #define DUK__INT_NOACTION 0 /* no specific action, resume normal execution */ |
| 77777 | #define DUK__INT_RESTART 1 /* must "goto restart_execution", e.g. breakpoints changed */ |
| 77778 | |
| 77779 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 77780 | DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) { |
| 77781 | duk_activation *act; |
| 77782 | duk_breakpoint *bp; |
| 77783 | duk_breakpoint **bp_active; |
| 77784 | duk_uint_fast32_t line = 0; |
| 77785 | duk_bool_t process_messages; |
| 77786 | duk_bool_t processed_messages = 0; |
| 77787 | |
| 77788 | DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */ |
| 77789 | |
| 77790 | act = thr->callstack_curr; |
| 77791 | DUK_ASSERT(act != NULL); |
| 77792 | |
| 77793 | /* It might seem that replacing 'thr->heap' with just 'heap' below |
| 77794 | * might be a good idea, but it increases code size slightly |
| 77795 | * (probably due to unnecessary spilling) at least on x64. |
| 77796 | */ |
| 77797 | |
| 77798 | /* |
| 77799 | * Single opcode step check |
| 77800 | */ |
| 77801 | |
| 77802 | if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE) { |
| 77803 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by one opcode step" )); |
| 77804 | duk_debug_set_paused(thr->heap); |
| 77805 | } |
| 77806 | |
| 77807 | /* |
| 77808 | * Breakpoint and step state checks |
| 77809 | */ |
| 77810 | |
| 77811 | if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || |
| 77812 | (thr->heap->dbg_pause_act == thr->callstack_curr)) { |
| 77813 | line = duk_debug_curr_line(thr); |
| 77814 | |
| 77815 | if (act->prev_line != line) { |
| 77816 | /* Stepped? Step out is handled by callstack unwind. */ |
| 77817 | if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) && |
| 77818 | (thr->heap->dbg_pause_act == thr->callstack_curr) && |
| 77819 | (line != thr->heap->dbg_pause_startline)) { |
| 77820 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by line change, at line %ld" , |
| 77821 | (long) line)); |
| 77822 | duk_debug_set_paused(thr->heap); |
| 77823 | } |
| 77824 | |
| 77825 | /* Check for breakpoints only on line transition. |
| 77826 | * Breakpoint is triggered when we enter the target |
| 77827 | * line from a different line, and the previous line |
| 77828 | * was within the same function. |
| 77829 | * |
| 77830 | * This condition is tricky: the condition used to be |
| 77831 | * that transition to -or across- the breakpoint line |
| 77832 | * triggered the breakpoint. This seems intuitively |
| 77833 | * better because it handles breakpoints on lines with |
| 77834 | * no emitted opcodes; but this leads to the issue |
| 77835 | * described in: https://github.com/svaarala/duktape/issues/263. |
| 77836 | */ |
| 77837 | bp_active = thr->heap->dbg_breakpoints_active; |
| 77838 | for (;;) { |
| 77839 | bp = *bp_active++; |
| 77840 | if (bp == NULL) { |
| 77841 | break; |
| 77842 | } |
| 77843 | |
| 77844 | DUK_ASSERT(bp->filename != NULL); |
| 77845 | if (act->prev_line != bp->line && line == bp->line) { |
| 77846 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by breakpoint at %!O:%ld" , |
| 77847 | (duk_heaphdr *) bp->filename, (long) bp->line)); |
| 77848 | duk_debug_set_paused(thr->heap); |
| 77849 | } |
| 77850 | } |
| 77851 | } else { |
| 77852 | ; |
| 77853 | } |
| 77854 | |
| 77855 | act->prev_line = (duk_uint32_t) line; |
| 77856 | } |
| 77857 | |
| 77858 | /* |
| 77859 | * Rate limit check for sending status update or peeking into |
| 77860 | * the debug transport. Both can be expensive operations that |
| 77861 | * we don't want to do on every opcode. |
| 77862 | * |
| 77863 | * Making sure the interval remains reasonable on a wide variety |
| 77864 | * of targets and bytecode is difficult without a timestamp, so |
| 77865 | * we use a Date-provided timestamp for the rate limit check. |
| 77866 | * But since it's also expensive to get a timestamp, a bytecode |
| 77867 | * counter is used to rate limit getting timestamps. |
| 77868 | */ |
| 77869 | |
| 77870 | process_messages = 0; |
| 77871 | if (thr->heap->dbg_state_dirty || DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->dbg_detaching) { |
| 77872 | /* Enter message processing loop for sending Status notifys and |
| 77873 | * to finish a pending detach. |
| 77874 | */ |
| 77875 | process_messages = 1; |
| 77876 | } |
| 77877 | |
| 77878 | /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */ |
| 77879 | DUK_ASSERT(thr->interrupt_init >= 0); |
| 77880 | thr->heap->dbg_exec_counter += (duk_uint_t) thr->interrupt_init; |
| 77881 | if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) { |
| 77882 | /* Overflow of the execution counter is fine and doesn't break |
| 77883 | * anything here. |
| 77884 | */ |
| 77885 | |
| 77886 | duk_double_t now, diff_last; |
| 77887 | |
| 77888 | thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter; |
| 77889 | now = duk_time_get_monotonic_time(thr); |
| 77890 | |
| 77891 | diff_last = now - thr->heap->dbg_last_time; |
| 77892 | if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) { |
| 77893 | /* Monotonic time should not experience time jumps, |
| 77894 | * but the provider may be missing and we're actually |
| 77895 | * using ECMAScript time. So, tolerate negative values |
| 77896 | * so that a time jump works reasonably. |
| 77897 | * |
| 77898 | * Same interval is now used for status sending and |
| 77899 | * peeking. |
| 77900 | */ |
| 77901 | |
| 77902 | thr->heap->dbg_last_time = now; |
| 77903 | thr->heap->dbg_state_dirty = 1; |
| 77904 | process_messages = 1; |
| 77905 | } |
| 77906 | } |
| 77907 | |
| 77908 | /* |
| 77909 | * Process messages and send status if necessary. |
| 77910 | * |
| 77911 | * If we're paused, we'll block for new messages. If we're not |
| 77912 | * paused, we'll process anything we can peek but won't block |
| 77913 | * for more. Detach (and re-attach) handling is all localized |
| 77914 | * to duk_debug_process_messages() too. |
| 77915 | * |
| 77916 | * Debugger writes outside the message loop may cause debugger |
| 77917 | * detach1 phase to run, after which dbg_read_cb == NULL and |
| 77918 | * dbg_detaching != 0. The message loop will finish the detach |
| 77919 | * by running detach2 phase, so enter the message loop also when |
| 77920 | * detaching. |
| 77921 | */ |
| 77922 | |
| 77923 | if (process_messages) { |
| 77924 | DUK_ASSERT(thr->heap->dbg_processing == 0); |
| 77925 | processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/); |
| 77926 | DUK_ASSERT(thr->heap->dbg_processing == 0); |
| 77927 | } |
| 77928 | |
| 77929 | /* Continue checked execution if there are breakpoints or we're stepping. |
| 77930 | * Also use checked execution if paused flag is active - it shouldn't be |
| 77931 | * because the debug message loop shouldn't terminate if it was. Step out |
| 77932 | * is handled by callstack unwind and doesn't need checked execution. |
| 77933 | * Note that debugger may have detached due to error or explicit request |
| 77934 | * above, so we must recheck attach status. |
| 77935 | */ |
| 77936 | |
| 77937 | if (duk_debug_is_attached(thr->heap)) { |
| 77938 | DUK_ASSERT(act == thr->callstack_curr); |
| 77939 | DUK_ASSERT(act != NULL); |
| 77940 | if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE || |
| 77941 | (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) || |
| 77942 | ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) && |
| 77943 | thr->heap->dbg_pause_act == thr->callstack_curr) || |
| 77944 | DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) { |
| 77945 | *out_immediate = 1; |
| 77946 | } |
| 77947 | |
| 77948 | /* If we processed any debug messages breakpoints may have |
| 77949 | * changed; restart execution to re-check active breakpoints. |
| 77950 | */ |
| 77951 | if (processed_messages) { |
| 77952 | DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints" )); |
| 77953 | *out_interrupt_retval = DUK__INT_RESTART; |
| 77954 | } else { |
| 77955 | if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) { |
| 77956 | /* Set 'pause after one opcode' active only when we're |
| 77957 | * actually just about to execute code. |
| 77958 | */ |
| 77959 | thr->heap->dbg_pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE; |
| 77960 | } |
| 77961 | } |
| 77962 | } else { |
| 77963 | DUK_D(DUK_DPRINT("debugger became detached, resume normal execution" )); |
| 77964 | } |
| 77965 | } |
| 77966 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 77967 | |
| 77968 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) { |
| 77969 | duk_int_t ctr; |
| 77970 | duk_activation *act; |
| 77971 | duk_hcompfunc *fun; |
| 77972 | duk_bool_t immediate = 0; |
| 77973 | duk_small_uint_t retval; |
| 77974 | |
| 77975 | DUK_ASSERT(thr != NULL); |
| 77976 | DUK_ASSERT(thr->heap != NULL); |
| 77977 | DUK_ASSERT(thr->callstack_top > 0); |
| 77978 | |
| 77979 | #if defined(DUK_USE_DEBUG) |
| 77980 | thr->heap->inst_count_interrupt += thr->interrupt_init; |
| 77981 | DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, " |
| 77982 | "instruction counts: executor=%ld, interrupt=%ld" , |
| 77983 | (long) thr->interrupt_counter, (long) thr->interrupt_init, |
| 77984 | (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt)); |
| 77985 | #endif |
| 77986 | |
| 77987 | retval = DUK__INT_NOACTION; |
| 77988 | ctr = DUK_HTHREAD_INTCTR_DEFAULT; |
| 77989 | |
| 77990 | /* |
| 77991 | * Avoid nested calls. Concretely this happens during debugging, e.g. |
| 77992 | * when we eval() an expression. |
| 77993 | * |
| 77994 | * Also don't interrupt if we're currently doing debug processing |
| 77995 | * (which can be initiated outside the bytecode executor) as this |
| 77996 | * may cause the debugger to be called recursively. Check required |
| 77997 | * for correct operation of throw intercept and other "exotic" halting |
| 77998 | * scenarios. |
| 77999 | */ |
| 78000 | |
| 78001 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 78002 | if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) { |
| 78003 | #else |
| 78004 | if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) { |
| 78005 | #endif |
| 78006 | DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring" )); |
| 78007 | |
| 78008 | /* Set a high interrupt counter; the original executor |
| 78009 | * interrupt invocation will rewrite before exiting. |
| 78010 | */ |
| 78011 | thr->interrupt_init = ctr; |
| 78012 | thr->interrupt_counter = ctr - 1; |
| 78013 | return DUK__INT_NOACTION; |
| 78014 | } |
| 78015 | DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap); |
| 78016 | |
| 78017 | act = thr->callstack_curr; |
| 78018 | DUK_ASSERT(act != NULL); |
| 78019 | |
| 78020 | fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); |
| 78021 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun)); |
| 78022 | |
| 78023 | DUK_UNREF(fun); |
| 78024 | |
| 78025 | #if defined(DUK_USE_EXEC_TIMEOUT_CHECK) |
| 78026 | /* |
| 78027 | * Execution timeout check |
| 78028 | */ |
| 78029 | |
| 78030 | if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) { |
| 78031 | /* Keep throwing an error whenever we get here. The unusual values |
| 78032 | * are set this way because no instruction is ever executed, we just |
| 78033 | * throw an error until all try/catch/finally and other catchpoints |
| 78034 | * have been exhausted. Duktape/C code gets control at each protected |
| 78035 | * call but whenever it enters back into Duktape the RangeError gets |
| 78036 | * raised. User exec timeout check must consistently indicate a timeout |
| 78037 | * until we've fully bubbled out of Duktape. |
| 78038 | */ |
| 78039 | DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError" )); |
| 78040 | thr->interrupt_init = 0; |
| 78041 | thr->interrupt_counter = 0; |
| 78042 | DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap); |
| 78043 | DUK_ERROR_RANGE(thr, "execution timeout" ); |
| 78044 | DUK_WO_NORETURN(return 0;); |
| 78045 | } |
| 78046 | #endif /* DUK_USE_EXEC_TIMEOUT_CHECK */ |
| 78047 | |
| 78048 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 78049 | if (!thr->heap->dbg_processing && |
| 78050 | (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) { |
| 78051 | /* Avoid recursive re-entry; enter when we're attached or |
| 78052 | * detaching (to finish off the pending detach). |
| 78053 | */ |
| 78054 | duk__interrupt_handle_debugger(thr, &immediate, &retval); |
| 78055 | DUK_ASSERT(act == thr->callstack_curr); |
| 78056 | } |
| 78057 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 78058 | |
| 78059 | /* |
| 78060 | * Update the interrupt counter |
| 78061 | */ |
| 78062 | |
| 78063 | if (immediate) { |
| 78064 | /* Cause an interrupt after executing one instruction. */ |
| 78065 | ctr = 1; |
| 78066 | } |
| 78067 | |
| 78068 | /* The counter value is one less than the init value: init value should |
| 78069 | * indicate how many instructions are executed before interrupt. To |
| 78070 | * execute 1 instruction (after interrupt handler return), counter must |
| 78071 | * be 0. |
| 78072 | */ |
| 78073 | DUK_ASSERT(ctr >= 1); |
| 78074 | thr->interrupt_init = ctr; |
| 78075 | thr->interrupt_counter = ctr - 1; |
| 78076 | DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap); |
| 78077 | |
| 78078 | return retval; |
| 78079 | } |
| 78080 | #endif /* DUK_USE_INTERRUPT_COUNTER */ |
| 78081 | |
| 78082 | /* |
| 78083 | * Debugger handling for executor restart |
| 78084 | * |
| 78085 | * Check for breakpoints, stepping, etc, and figure out if we should execute |
| 78086 | * in checked or normal mode. Note that we can't do this when an activation |
| 78087 | * is created, because breakpoint status (and stepping status) may change |
| 78088 | * later, so we must recheck every time we're executing an activation. |
| 78089 | * This primitive should be side effect free to avoid changes during check. |
| 78090 | */ |
| 78091 | |
| 78092 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 78093 | DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompfunc *fun) { |
| 78094 | duk_heap *heap; |
| 78095 | duk_tval *tv_tmp; |
| 78096 | duk_hstring *filename; |
| 78097 | duk_small_uint_t bp_idx; |
| 78098 | duk_breakpoint **bp_active; |
| 78099 | |
| 78100 | DUK_ASSERT(thr != NULL); |
| 78101 | DUK_ASSERT(act != NULL); |
| 78102 | DUK_ASSERT(fun != NULL); |
| 78103 | |
| 78104 | heap = thr->heap; |
| 78105 | bp_active = heap->dbg_breakpoints_active; |
| 78106 | act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE; |
| 78107 | |
| 78108 | tv_tmp = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) fun, DUK_STRIDX_FILE_NAME); |
| 78109 | if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) { |
| 78110 | filename = DUK_TVAL_GET_STRING(tv_tmp); |
| 78111 | |
| 78112 | /* Figure out all active breakpoints. A breakpoint is |
| 78113 | * considered active if the current function's fileName |
| 78114 | * matches the breakpoint's fileName, AND there is no |
| 78115 | * inner function that has matching line numbers |
| 78116 | * (otherwise a breakpoint would be triggered both |
| 78117 | * inside and outside of the inner function which would |
| 78118 | * be confusing). Example: |
| 78119 | * |
| 78120 | * function foo() { |
| 78121 | * print('foo'); |
| 78122 | * function bar() { <-. breakpoints in these |
| 78123 | * print('bar'); | lines should not affect |
| 78124 | * } <-' foo() execution |
| 78125 | * bar(); |
| 78126 | * } |
| 78127 | * |
| 78128 | * We need a few things that are only available when |
| 78129 | * debugger support is enabled: (1) a line range for |
| 78130 | * each function, and (2) access to the function |
| 78131 | * template to access the inner functions (and their |
| 78132 | * line ranges). |
| 78133 | * |
| 78134 | * It's important to have a narrow match for active |
| 78135 | * breakpoints so that we don't enter checked execution |
| 78136 | * when that's not necessary. For instance, if we're |
| 78137 | * running inside a certain function and there's |
| 78138 | * breakpoint outside in (after the call site), we |
| 78139 | * don't want to slow down execution of the function. |
| 78140 | */ |
| 78141 | |
| 78142 | for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) { |
| 78143 | duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx; |
| 78144 | duk_hobject **funcs, **funcs_end; |
| 78145 | duk_hcompfunc *inner_fun; |
| 78146 | duk_bool_t bp_match; |
| 78147 | |
| 78148 | if (bp->filename == filename && |
| 78149 | bp->line >= fun->start_line && bp->line <= fun->end_line) { |
| 78150 | bp_match = 1; |
| 78151 | DUK_DD(DUK_DDPRINT("breakpoint filename and line match: " |
| 78152 | "%s:%ld vs. %s (line %ld vs. %ld-%ld)" , |
| 78153 | DUK_HSTRING_GET_DATA(bp->filename), |
| 78154 | (long) bp->line, |
| 78155 | DUK_HSTRING_GET_DATA(filename), |
| 78156 | (long) bp->line, |
| 78157 | (long) fun->start_line, |
| 78158 | (long) fun->end_line)); |
| 78159 | |
| 78160 | funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun); |
| 78161 | funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, fun); |
| 78162 | while (funcs != funcs_end) { |
| 78163 | inner_fun = (duk_hcompfunc *) *funcs; |
| 78164 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) inner_fun)); |
| 78165 | if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) { |
| 78166 | DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint" )); |
| 78167 | bp_match = 0; |
| 78168 | break; |
| 78169 | } |
| 78170 | funcs++; |
| 78171 | } |
| 78172 | |
| 78173 | if (bp_match) { |
| 78174 | /* No need to check for size of bp_active list, |
| 78175 | * it's always larger than maximum number of |
| 78176 | * breakpoints. |
| 78177 | */ |
| 78178 | act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE; |
| 78179 | *bp_active = heap->dbg_breakpoints + bp_idx; |
| 78180 | bp_active++; |
| 78181 | } |
| 78182 | } |
| 78183 | } |
| 78184 | } |
| 78185 | |
| 78186 | *bp_active = NULL; /* terminate */ |
| 78187 | |
| 78188 | DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld" , (long) (bp_active - thr->heap->dbg_breakpoints_active))); |
| 78189 | |
| 78190 | /* Force pause if we were doing "step into" in another activation. */ |
| 78191 | if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) && |
| 78192 | thr->heap->dbg_pause_act != thr->callstack_curr) { |
| 78193 | DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry" )); |
| 78194 | duk_debug_set_paused(thr->heap); |
| 78195 | } |
| 78196 | |
| 78197 | /* Force interrupt right away if we're paused or in "checked mode". |
| 78198 | * Step out is handled by callstack unwind. |
| 78199 | */ |
| 78200 | if ((act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE) || |
| 78201 | DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || |
| 78202 | ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) && |
| 78203 | thr->heap->dbg_pause_act == thr->callstack_curr)) { |
| 78204 | /* We'll need to interrupt early so recompute the init |
| 78205 | * counter to reflect the number of bytecode instructions |
| 78206 | * executed so that step counts for e.g. debugger rate |
| 78207 | * limiting are accurate. |
| 78208 | */ |
| 78209 | DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init); |
| 78210 | thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter; |
| 78211 | thr->interrupt_counter = 0; |
| 78212 | } |
| 78213 | } |
| 78214 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 78215 | |
| 78216 | /* |
| 78217 | * Opcode handlers for opcodes with a lot of code and which are relatively |
| 78218 | * rare; NOINLINE to reduce amount of code in main bytecode dispatcher. |
| 78219 | */ |
| 78220 | |
| 78221 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_op_initset_initget(duk_hthread *thr, duk_uint_fast32_t ins) { |
| 78222 | duk_bool_t is_set = (DUK_DEC_OP(ins) == DUK_OP_INITSET); |
| 78223 | duk_uint_fast_t idx; |
| 78224 | duk_uint_t defprop_flags; |
| 78225 | |
| 78226 | /* A -> object register (acts as a source) |
| 78227 | * BC -> BC+0 contains key, BC+1 closure (value) |
| 78228 | */ |
| 78229 | |
| 78230 | /* INITSET/INITGET are only used to initialize object literal keys. |
| 78231 | * There may be a previous propery in ES2015 because duplicate property |
| 78232 | * names are allowed. |
| 78233 | */ |
| 78234 | |
| 78235 | /* This could be made more optimal by accessing internals directly. */ |
| 78236 | |
| 78237 | idx = (duk_uint_fast_t) DUK_DEC_BC(ins); |
| 78238 | duk_dup(thr, (duk_idx_t) (idx + 0)); /* key */ |
| 78239 | duk_dup(thr, (duk_idx_t) (idx + 1)); /* getter/setter */ |
| 78240 | if (is_set) { |
| 78241 | defprop_flags = DUK_DEFPROP_HAVE_SETTER | |
| 78242 | DUK_DEFPROP_FORCE | |
| 78243 | DUK_DEFPROP_SET_ENUMERABLE | |
| 78244 | DUK_DEFPROP_SET_CONFIGURABLE; |
| 78245 | } else { |
| 78246 | defprop_flags = DUK_DEFPROP_HAVE_GETTER | |
| 78247 | DUK_DEFPROP_FORCE | |
| 78248 | DUK_DEFPROP_SET_ENUMERABLE | |
| 78249 | DUK_DEFPROP_SET_CONFIGURABLE; |
| 78250 | } |
| 78251 | duk_def_prop(thr, (duk_idx_t) DUK_DEC_A(ins), defprop_flags); |
| 78252 | } |
| 78253 | |
| 78254 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_op_trycatch(duk_hthread *thr, duk_uint_fast32_t ins, duk_instr_t *curr_pc) { |
| 78255 | duk_activation *act; |
| 78256 | duk_catcher *cat; |
| 78257 | duk_tval *tv1; |
| 78258 | duk_small_uint_fast_t a; |
| 78259 | duk_small_uint_fast_t bc; |
| 78260 | |
| 78261 | /* A -> flags |
| 78262 | * BC -> reg_catch; base register for two registers used both during |
| 78263 | * trycatch setup and when catch is triggered |
| 78264 | * |
| 78265 | * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set: |
| 78266 | * reg_catch + 0: catch binding variable name (string). |
| 78267 | * Automatic declarative environment is established for |
| 78268 | * the duration of the 'catch' clause. |
| 78269 | * |
| 78270 | * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set: |
| 78271 | * reg_catch + 0: with 'target value', which is coerced to |
| 78272 | * an object and then used as a bindind object for an |
| 78273 | * environment record. The binding is initialized here, for |
| 78274 | * the 'try' clause. |
| 78275 | * |
| 78276 | * Note that a TRYCATCH generated for a 'with' statement has no |
| 78277 | * catch or finally parts. |
| 78278 | */ |
| 78279 | |
| 78280 | /* XXX: TRYCATCH handling should be reworked to avoid creating |
| 78281 | * an explicit scope unless it is actually needed (e.g. function |
| 78282 | * instances or eval is executed inside the catch block). This |
| 78283 | * rework is not trivial because the compiler doesn't have an |
| 78284 | * intermediate representation. When the rework is done, the |
| 78285 | * opcode format can also be made more straightforward. |
| 78286 | */ |
| 78287 | |
| 78288 | /* XXX: side effect handling is quite awkward here */ |
| 78289 | |
| 78290 | DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, " |
| 78291 | "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)" , |
| 78292 | (long) DUK_DEC_BC(ins), |
| 78293 | (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0), |
| 78294 | (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0), |
| 78295 | (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0), |
| 78296 | (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0), |
| 78297 | (unsigned long) DUK_DEC_A(ins))); |
| 78298 | |
| 78299 | a = DUK_DEC_A(ins); |
| 78300 | bc = DUK_DEC_BC(ins); |
| 78301 | |
| 78302 | /* Registers 'bc' and 'bc + 1' are written in longjmp handling |
| 78303 | * and if their previous values (which are temporaries) become |
| 78304 | * unreachable -and- have a finalizer, there'll be a function |
| 78305 | * call during error handling which is not supported now (GH-287). |
| 78306 | * Ensure that both 'bc' and 'bc + 1' have primitive values to |
| 78307 | * guarantee no finalizer calls in error handling. Scrubbing also |
| 78308 | * ensures finalizers for the previous values run here rather than |
| 78309 | * later. Error handling related values are also written to 'bc' |
| 78310 | * and 'bc + 1' but those values never become unreachable during |
| 78311 | * error handling, so there's no side effect problem even if the |
| 78312 | * error value has a finalizer. |
| 78313 | */ |
| 78314 | duk_dup(thr, (duk_idx_t) bc); /* Stabilize value. */ |
| 78315 | duk_to_undefined(thr, (duk_idx_t) bc); |
| 78316 | duk_to_undefined(thr, (duk_idx_t) (bc + 1)); |
| 78317 | |
| 78318 | /* Allocate catcher and populate it. Doesn't have to |
| 78319 | * be fully atomic, but the catcher must be in a |
| 78320 | * consistent state if side effects (such as finalizer |
| 78321 | * calls) occur. |
| 78322 | */ |
| 78323 | |
| 78324 | cat = duk_hthread_catcher_alloc(thr); |
| 78325 | DUK_ASSERT(cat != NULL); |
| 78326 | |
| 78327 | cat->flags = DUK_CAT_TYPE_TCF; |
| 78328 | cat->h_varname = NULL; |
| 78329 | cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ |
| 78330 | cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc; |
| 78331 | |
| 78332 | act = thr->callstack_curr; |
| 78333 | DUK_ASSERT(act != NULL); |
| 78334 | cat->parent = act->cat; |
| 78335 | act->cat = cat; |
| 78336 | |
| 78337 | if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) { |
| 78338 | cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED; |
| 78339 | } |
| 78340 | if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) { |
| 78341 | cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; |
| 78342 | } |
| 78343 | if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) { |
| 78344 | DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher" )); |
| 78345 | cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; |
| 78346 | tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 78347 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); |
| 78348 | |
| 78349 | /* borrowed reference; although 'tv1' comes from a register, |
| 78350 | * its value was loaded using LDCONST so the constant will |
| 78351 | * also exist and be reachable. |
| 78352 | */ |
| 78353 | cat->h_varname = DUK_TVAL_GET_STRING(tv1); |
| 78354 | } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) { |
| 78355 | duk_hobjenv *env; |
| 78356 | duk_hobject *target; |
| 78357 | |
| 78358 | /* Delayed env initialization for activation (if needed). */ |
| 78359 | DUK_ASSERT(thr->callstack_top >= 1); |
| 78360 | DUK_ASSERT(act == thr->callstack_curr); |
| 78361 | DUK_ASSERT(act != NULL); |
| 78362 | if (act->lex_env == NULL) { |
| 78363 | DUK_DDD(DUK_DDDPRINT("delayed environment initialization" )); |
| 78364 | DUK_ASSERT(act->var_env == NULL); |
| 78365 | |
| 78366 | duk_js_init_activation_environment_records_delayed(thr, act); |
| 78367 | DUK_ASSERT(act == thr->callstack_curr); |
| 78368 | DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */ |
| 78369 | } |
| 78370 | DUK_ASSERT(act->lex_env != NULL); |
| 78371 | DUK_ASSERT(act->var_env != NULL); |
| 78372 | |
| 78373 | /* Coerce 'with' target. */ |
| 78374 | target = duk_to_hobject(thr, -1); |
| 78375 | DUK_ASSERT(target != NULL); |
| 78376 | |
| 78377 | /* Create an object environment; it is not pushed |
| 78378 | * so avoid side effects very carefully until it is |
| 78379 | * referenced. |
| 78380 | */ |
| 78381 | env = duk_hobjenv_alloc(thr, |
| 78382 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 78383 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV)); |
| 78384 | DUK_ASSERT(env != NULL); |
| 78385 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); |
| 78386 | env->target = target; /* always provideThis=true */ |
| 78387 | DUK_HOBJECT_INCREF(thr, target); |
| 78388 | env->has_this = 1; |
| 78389 | DUK_HOBJENV_ASSERT_VALID(env); |
| 78390 | DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO" , env)); |
| 78391 | |
| 78392 | DUK_ASSERT(act == thr->callstack_curr); |
| 78393 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); |
| 78394 | DUK_ASSERT(act->lex_env != NULL); |
| 78395 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env); |
| 78396 | act->lex_env = (duk_hobject *) env; /* Now reachable. */ |
| 78397 | DUK_HOBJECT_INCREF(thr, (duk_hobject *) env); |
| 78398 | /* Net refcount change to act->lex_env is 0: incref for env's |
| 78399 | * prototype, decref for act->lex_env overwrite. |
| 78400 | */ |
| 78401 | |
| 78402 | /* Set catcher lex_env active (affects unwind) |
| 78403 | * only when the whole setup is complete. |
| 78404 | */ |
| 78405 | cat = act->cat; /* XXX: better to relookup? not mandatory because 'cat' is stable */ |
| 78406 | cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; |
| 78407 | } else { |
| 78408 | ; |
| 78409 | } |
| 78410 | |
| 78411 | DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, pc_base=%ld, " |
| 78412 | "idx_base=%ld, h_varname=%!O" , |
| 78413 | (unsigned long) cat->flags, |
| 78414 | (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname)); |
| 78415 | |
| 78416 | duk_pop_unsafe(thr); |
| 78417 | } |
| 78418 | |
| 78419 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_instr_t *duk__handle_op_endtry(duk_hthread *thr, duk_uint_fast32_t ins) { |
| 78420 | duk_activation *act; |
| 78421 | duk_catcher *cat; |
| 78422 | duk_tval *tv1; |
| 78423 | duk_instr_t *pc_base; |
| 78424 | |
| 78425 | DUK_UNREF(ins); |
| 78426 | |
| 78427 | DUK_ASSERT(thr->callstack_top >= 1); |
| 78428 | act = thr->callstack_curr; |
| 78429 | DUK_ASSERT(act != NULL); |
| 78430 | cat = act->cat; |
| 78431 | DUK_ASSERT(cat != NULL); |
| 78432 | DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF); |
| 78433 | |
| 78434 | DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)" )); |
| 78435 | DUK_CAT_CLEAR_CATCH_ENABLED(cat); |
| 78436 | |
| 78437 | pc_base = cat->pc_base; |
| 78438 | |
| 78439 | if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) { |
| 78440 | DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'" )); |
| 78441 | |
| 78442 | tv1 = thr->valstack + cat->idx_base; |
| 78443 | DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); |
| 78444 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */ |
| 78445 | tv1 = NULL; |
| 78446 | |
| 78447 | tv1 = thr->valstack + cat->idx_base + 1; |
| 78448 | DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); |
| 78449 | DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */ |
| 78450 | tv1 = NULL; |
| 78451 | |
| 78452 | DUK_CAT_CLEAR_FINALLY_ENABLED(cat); |
| 78453 | } else { |
| 78454 | DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)" )); |
| 78455 | |
| 78456 | duk_hthread_catcher_unwind_norz(thr, act); /* lexenv may be set for 'with' binding */ |
| 78457 | /* no need to unwind callstack */ |
| 78458 | } |
| 78459 | |
| 78460 | return pc_base + 1; /* new curr_pc value */ |
| 78461 | } |
| 78462 | |
| 78463 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_instr_t *duk__handle_op_endcatch(duk_hthread *thr, duk_uint_fast32_t ins) { |
| 78464 | duk_activation *act; |
| 78465 | duk_catcher *cat; |
| 78466 | duk_tval *tv1; |
| 78467 | duk_instr_t *pc_base; |
| 78468 | |
| 78469 | DUK_UNREF(ins); |
| 78470 | |
| 78471 | DUK_ASSERT(thr->callstack_top >= 1); |
| 78472 | act = thr->callstack_curr; |
| 78473 | DUK_ASSERT(act != NULL); |
| 78474 | cat = act->cat; |
| 78475 | DUK_ASSERT(cat != NULL); |
| 78476 | DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */ |
| 78477 | |
| 78478 | if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) { |
| 78479 | duk_hobject *prev_env; |
| 78480 | |
| 78481 | /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */ |
| 78482 | DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)); |
| 78483 | DUK_ASSERT(act->lex_env != NULL); |
| 78484 | |
| 78485 | DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment" )); |
| 78486 | |
| 78487 | prev_env = act->lex_env; |
| 78488 | DUK_ASSERT(prev_env != NULL); |
| 78489 | act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env); |
| 78490 | DUK_CAT_CLEAR_LEXENV_ACTIVE(cat); |
| 78491 | DUK_HOBJECT_INCREF(thr, act->lex_env); |
| 78492 | DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */ |
| 78493 | |
| 78494 | DUK_ASSERT(act == thr->callstack_curr); |
| 78495 | DUK_ASSERT(act != NULL); |
| 78496 | } |
| 78497 | |
| 78498 | pc_base = cat->pc_base; |
| 78499 | |
| 78500 | if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) { |
| 78501 | DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'" )); |
| 78502 | |
| 78503 | tv1 = thr->valstack + cat->idx_base; |
| 78504 | DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); |
| 78505 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */ |
| 78506 | tv1 = NULL; |
| 78507 | |
| 78508 | tv1 = thr->valstack + cat->idx_base + 1; |
| 78509 | DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); |
| 78510 | DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */ |
| 78511 | tv1 = NULL; |
| 78512 | |
| 78513 | DUK_CAT_CLEAR_FINALLY_ENABLED(cat); |
| 78514 | } else { |
| 78515 | DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)" )); |
| 78516 | |
| 78517 | duk_hthread_catcher_unwind_norz(thr, act); |
| 78518 | /* no need to unwind callstack */ |
| 78519 | } |
| 78520 | |
| 78521 | return pc_base + 1; /* new curr_pc value */ |
| 78522 | } |
| 78523 | |
| 78524 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_small_uint_t duk__handle_op_endfin(duk_hthread *thr, duk_uint_fast32_t ins, duk_activation *entry_act) { |
| 78525 | duk_activation *act; |
| 78526 | duk_tval *tv1; |
| 78527 | duk_uint_t reg_catch; |
| 78528 | duk_small_uint_t cont_type; |
| 78529 | duk_small_uint_t ret_result; |
| 78530 | |
| 78531 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 78532 | DUK_ASSERT(thr->callstack_top >= 1); |
| 78533 | act = thr->callstack_curr; |
| 78534 | DUK_ASSERT(act != NULL); |
| 78535 | reg_catch = DUK_DEC_ABC(ins); |
| 78536 | |
| 78537 | /* CATCH flag may be enabled or disabled here; it may be enabled if |
| 78538 | * the statement has a catch block but the try block does not throw |
| 78539 | * an error. |
| 78540 | */ |
| 78541 | |
| 78542 | DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T" , |
| 78543 | (duk_tval *) (thr->valstack_bottom + reg_catch + 0), |
| 78544 | (duk_tval *) (thr->valstack_bottom + reg_catch + 1))); |
| 78545 | |
| 78546 | tv1 = thr->valstack_bottom + reg_catch + 1; /* type */ |
| 78547 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); |
| 78548 | #if defined(DUK_USE_FASTINT) |
| 78549 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); |
| 78550 | cont_type = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1); |
| 78551 | #else |
| 78552 | cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1); |
| 78553 | #endif |
| 78554 | |
| 78555 | tv1--; /* value */ |
| 78556 | |
| 78557 | switch (cont_type) { |
| 78558 | case DUK_LJ_TYPE_NORMAL: { |
| 78559 | DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> " |
| 78560 | "dismantle catcher, resume execution after ENDFIN" )); |
| 78561 | |
| 78562 | duk_hthread_catcher_unwind_norz(thr, act); |
| 78563 | /* no need to unwind callstack */ |
| 78564 | return 0; /* restart execution */ |
| 78565 | } |
| 78566 | case DUK_LJ_TYPE_RETURN: { |
| 78567 | DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle " |
| 78568 | "catcher, handle return, lj.value1=%!T" , tv1)); |
| 78569 | |
| 78570 | /* Not necessary to unwind catch stack: return handling will |
| 78571 | * do it. The finally flag of 'cat' is no longer set. The |
| 78572 | * catch flag may be set, but it's not checked by return handling. |
| 78573 | */ |
| 78574 | |
| 78575 | duk_push_tval(thr, tv1); |
| 78576 | ret_result = duk__handle_return(thr, entry_act); |
| 78577 | if (ret_result == DUK__RETHAND_RESTART) { |
| 78578 | return 0; /* restart execution */ |
| 78579 | } |
| 78580 | DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); |
| 78581 | |
| 78582 | DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type" )); |
| 78583 | return 1; /* exit executor */ |
| 78584 | } |
| 78585 | case DUK_LJ_TYPE_BREAK: |
| 78586 | case DUK_LJ_TYPE_CONTINUE: { |
| 78587 | duk_uint_t label_id; |
| 78588 | duk_small_uint_t lj_type; |
| 78589 | |
| 78590 | /* Not necessary to unwind catch stack: break/continue |
| 78591 | * handling will do it. The finally flag of 'cat' is |
| 78592 | * no longer set. The catch flag may be set, but it's |
| 78593 | * not checked by break/continue handling. |
| 78594 | */ |
| 78595 | |
| 78596 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); |
| 78597 | #if defined(DUK_USE_FASTINT) |
| 78598 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); |
| 78599 | label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1); |
| 78600 | #else |
| 78601 | label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1); |
| 78602 | #endif |
| 78603 | lj_type = cont_type; |
| 78604 | duk__handle_break_or_continue(thr, label_id, lj_type); |
| 78605 | return 0; /* restart execution */ |
| 78606 | } |
| 78607 | default: { |
| 78608 | DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> " |
| 78609 | "dismantle catcher, re-throw error" , |
| 78610 | (long) cont_type)); |
| 78611 | |
| 78612 | duk_err_setup_ljstate1(thr, (duk_small_uint_t) cont_type, tv1); |
| 78613 | /* No debugger Throw notify check on purpose (rethrow). */ |
| 78614 | |
| 78615 | DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ |
| 78616 | duk_err_longjmp(thr); |
| 78617 | DUK_UNREACHABLE(); |
| 78618 | } |
| 78619 | } |
| 78620 | |
| 78621 | DUK_UNREACHABLE(); |
| 78622 | return 0; |
| 78623 | } |
| 78624 | |
| 78625 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF void duk__handle_op_initenum(duk_hthread *thr, duk_uint_fast32_t ins) { |
| 78626 | duk_small_uint_t b; |
| 78627 | duk_small_uint_t c; |
| 78628 | |
| 78629 | /* |
| 78630 | * Enumeration semantics come from for-in statement, E5 Section 12.6.4. |
| 78631 | * If called with 'null' or 'undefined', this opcode returns 'null' as |
| 78632 | * the enumerator, which is special cased in NEXTENUM. This simplifies |
| 78633 | * the compiler part |
| 78634 | */ |
| 78635 | |
| 78636 | /* B -> register for writing enumerator object |
| 78637 | * C -> value to be enumerated (register) |
| 78638 | */ |
| 78639 | b = DUK_DEC_B(ins); |
| 78640 | c = DUK_DEC_C(ins); |
| 78641 | |
| 78642 | if (duk_is_null_or_undefined(thr, (duk_idx_t) c)) { |
| 78643 | duk_push_null(thr); |
| 78644 | duk_replace(thr, (duk_idx_t) b); |
| 78645 | } else { |
| 78646 | duk_dup(thr, (duk_idx_t) c); |
| 78647 | duk_to_object(thr, -1); |
| 78648 | duk_hobject_enumerator_create(thr, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */ |
| 78649 | duk_replace(thr, (duk_idx_t) b); |
| 78650 | } |
| 78651 | } |
| 78652 | |
| 78653 | DUK_LOCAL DUK_EXEC_NOINLINE_PERF duk_small_uint_t duk__handle_op_nextenum(duk_hthread *thr, duk_uint_fast32_t ins) { |
| 78654 | duk_small_uint_t b; |
| 78655 | duk_small_uint_t c; |
| 78656 | duk_small_uint_t pc_skip = 0; |
| 78657 | |
| 78658 | /* |
| 78659 | * NEXTENUM checks whether the enumerator still has unenumerated |
| 78660 | * keys. If so, the next key is loaded to the target register |
| 78661 | * and the next instruction is skipped. Otherwise the next instruction |
| 78662 | * will be executed, jumping out of the enumeration loop. |
| 78663 | */ |
| 78664 | |
| 78665 | /* B -> target register for next key |
| 78666 | * C -> enum register |
| 78667 | */ |
| 78668 | b = DUK_DEC_B(ins); |
| 78669 | c = DUK_DEC_C(ins); |
| 78670 | |
| 78671 | DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T" , |
| 78672 | (duk_tval *) duk_get_tval(thr, (duk_idx_t) b), |
| 78673 | (duk_tval *) duk_get_tval(thr, (duk_idx_t) c))); |
| 78674 | |
| 78675 | if (duk_is_object(thr, (duk_idx_t) c)) { |
| 78676 | /* XXX: assert 'c' is an enumerator */ |
| 78677 | duk_dup(thr, (duk_idx_t) c); |
| 78678 | if (duk_hobject_enumerator_next(thr, 0 /*get_value*/)) { |
| 78679 | /* [ ... enum ] -> [ ... next_key ] */ |
| 78680 | DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot " , |
| 78681 | (duk_tval *) duk_get_tval(thr, -1))); |
| 78682 | pc_skip = 1; |
| 78683 | } else { |
| 78684 | /* [ ... enum ] -> [ ... ] */ |
| 78685 | DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot" )); |
| 78686 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ |
| 78687 | thr->valstack_top++; |
| 78688 | } |
| 78689 | duk_replace(thr, (duk_idx_t) b); |
| 78690 | } else { |
| 78691 | /* 'null' enumerator case -> behave as with an empty enumerator */ |
| 78692 | DUK_ASSERT(duk_is_null(thr, (duk_idx_t) c)); |
| 78693 | DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot" )); |
| 78694 | } |
| 78695 | |
| 78696 | return pc_skip; |
| 78697 | } |
| 78698 | |
| 78699 | /* |
| 78700 | * Call handling helpers. |
| 78701 | */ |
| 78702 | |
| 78703 | DUK_LOCAL duk_bool_t duk__executor_handle_call(duk_hthread *thr, duk_idx_t idx, duk_idx_t nargs, duk_small_uint_t call_flags) { |
| 78704 | duk_bool_t rc; |
| 78705 | |
| 78706 | duk_set_top_unsafe(thr, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */ |
| 78707 | |
| 78708 | /* Attempt an Ecma-to-Ecma call setup. If the call |
| 78709 | * target is (directly or indirectly) Reflect.construct(), |
| 78710 | * the call may change into a constructor call on the fly. |
| 78711 | */ |
| 78712 | rc = (duk_bool_t) duk_handle_call_unprotected(thr, idx, call_flags); |
| 78713 | if (rc != 0) { |
| 78714 | /* Ecma-to-ecma call possible, may or may not |
| 78715 | * be a tail call. Avoid C recursion by |
| 78716 | * reusing current executor instance. |
| 78717 | */ |
| 78718 | DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution" )); |
| 78719 | /* curr_pc synced by duk_handle_call_unprotected() */ |
| 78720 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 78721 | return rc; |
| 78722 | } else { |
| 78723 | /* Call was handled inline. */ |
| 78724 | } |
| 78725 | DUK_ASSERT(thr->ptr_curr_pc != NULL); |
| 78726 | return rc; |
| 78727 | } |
| 78728 | |
| 78729 | /* |
| 78730 | * ECMAScript bytecode executor. |
| 78731 | * |
| 78732 | * Resume execution for the current thread from its current activation. |
| 78733 | * Returns when execution would return from the entry level activation, |
| 78734 | * leaving a single return value on top of the stack. Function calls |
| 78735 | * and thread resumptions are handled internally. If an error occurs, |
| 78736 | * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level |
| 78737 | * setjmp() jmpbuf. |
| 78738 | * |
| 78739 | * ECMAScript function calls and coroutine resumptions are handled |
| 78740 | * internally (by the outer executor function) without recursive C calls. |
| 78741 | * Other function calls are handled using duk_handle_call(), increasing |
| 78742 | * C recursion depth. |
| 78743 | * |
| 78744 | * Abrupt completions (= long control tranfers) are handled either |
| 78745 | * directly by reconfiguring relevant stacks and restarting execution, |
| 78746 | * or via a longjmp. Longjmp-free handling is preferable for performance |
| 78747 | * (especially Emscripten performance), and is used for: break, continue, |
| 78748 | * and return. |
| 78749 | * |
| 78750 | * For more detailed notes, see doc/execution.rst. |
| 78751 | * |
| 78752 | * Also see doc/code-issues.rst for discussion of setjmp(), longjmp(), |
| 78753 | * and volatile. |
| 78754 | */ |
| 78755 | |
| 78756 | /* Presence of 'fun' is config based, there's a marginal performance |
| 78757 | * difference and the best option is architecture dependent. |
| 78758 | */ |
| 78759 | #if defined(DUK_USE_EXEC_FUN_LOCAL) |
| 78760 | #define DUK__FUN() fun |
| 78761 | #else |
| 78762 | #define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr)) |
| 78763 | #endif |
| 78764 | |
| 78765 | /* Strict flag. */ |
| 78766 | #define DUK__STRICT() ((duk_small_uint_t) DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN())) |
| 78767 | |
| 78768 | /* Reg/const access macros: these are very footprint and performance sensitive |
| 78769 | * so modify with care. Arguments are sometimes evaluated multiple times which |
| 78770 | * is not ideal. |
| 78771 | */ |
| 78772 | #define DUK__REG(x) (*(thr->valstack_bottom + (x))) |
| 78773 | #define DUK__REGP(x) (thr->valstack_bottom + (x)) |
| 78774 | #define DUK__CONST(x) (*(consts + (x))) |
| 78775 | #define DUK__CONSTP(x) (consts + (x)) |
| 78776 | |
| 78777 | /* Reg/const access macros which take the 32-bit instruction and avoid an |
| 78778 | * explicit field decoding step by using shifts and masks. These must be |
| 78779 | * kept in sync with duk_js_bytecode.h. The shift/mask values are chosen |
| 78780 | * so that 'ins' can be shifted and masked and used as a -byte- offset |
| 78781 | * instead of a duk_tval offset which needs further shifting (which is an |
| 78782 | * issue on some, but not all, CPUs). |
| 78783 | */ |
| 78784 | #define DUK__RCBIT_B DUK_BC_REGCONST_B |
| 78785 | #define DUK__RCBIT_C DUK_BC_REGCONST_C |
| 78786 | #if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE) |
| 78787 | #if defined(DUK_USE_PACKED_TVAL) |
| 78788 | #define DUK__TVAL_SHIFT 3 /* sizeof(duk_tval) == 8 */ |
| 78789 | #else |
| 78790 | #define DUK__TVAL_SHIFT 4 /* sizeof(duk_tval) == 16; not always the case so also asserted for */ |
| 78791 | #endif |
| 78792 | #define DUK__SHIFT_A (DUK_BC_SHIFT_A - DUK__TVAL_SHIFT) |
| 78793 | #define DUK__SHIFT_B (DUK_BC_SHIFT_B - DUK__TVAL_SHIFT) |
| 78794 | #define DUK__SHIFT_C (DUK_BC_SHIFT_C - DUK__TVAL_SHIFT) |
| 78795 | #define DUK__SHIFT_BC (DUK_BC_SHIFT_BC - DUK__TVAL_SHIFT) |
| 78796 | #define DUK__MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK__TVAL_SHIFT) |
| 78797 | #define DUK__MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK__TVAL_SHIFT) |
| 78798 | #define DUK__MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK__TVAL_SHIFT) |
| 78799 | #define DUK__MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK__TVAL_SHIFT) |
| 78800 | #define DUK__BYTEOFF_A(ins) (((ins) >> DUK__SHIFT_A) & DUK__MASK_A) |
| 78801 | #define DUK__BYTEOFF_B(ins) (((ins) >> DUK__SHIFT_B) & DUK__MASK_B) |
| 78802 | #define DUK__BYTEOFF_C(ins) (((ins) >> DUK__SHIFT_C) & DUK__MASK_C) |
| 78803 | #define DUK__BYTEOFF_BC(ins) (((ins) >> DUK__SHIFT_BC) & DUK__MASK_BC) |
| 78804 | |
| 78805 | #define DUK__REGP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_A((ins)))) |
| 78806 | #define DUK__REGP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_B((ins)))) |
| 78807 | #define DUK__REGP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_C((ins)))) |
| 78808 | #define DUK__REGP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_BC((ins)))) |
| 78809 | #define DUK__CONSTP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_A((ins)))) |
| 78810 | #define DUK__CONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_B((ins)))) |
| 78811 | #define DUK__CONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_C((ins)))) |
| 78812 | #define DUK__CONSTP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_BC((ins)))) |
| 78813 | #define DUK__REGCONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_B((ins)))) |
| 78814 | #define DUK__REGCONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_C((ins)))) |
| 78815 | #else /* DUK_USE_EXEC_REGCONST_OPTIMIZE */ |
| 78816 | /* Safe alternatives, no assumption about duk_tval size. */ |
| 78817 | #define DUK__REGP_A(ins) DUK__REGP(DUK_DEC_A((ins))) |
| 78818 | #define DUK__REGP_B(ins) DUK__REGP(DUK_DEC_B((ins))) |
| 78819 | #define DUK__REGP_C(ins) DUK__REGP(DUK_DEC_C((ins))) |
| 78820 | #define DUK__REGP_BC(ins) DUK__REGP(DUK_DEC_BC((ins))) |
| 78821 | #define DUK__CONSTP_A(ins) DUK__CONSTP(DUK_DEC_A((ins))) |
| 78822 | #define DUK__CONSTP_B(ins) DUK__CONSTP(DUK_DEC_B((ins))) |
| 78823 | #define DUK__CONSTP_C(ins) DUK__CONSTP(DUK_DEC_C((ins))) |
| 78824 | #define DUK__CONSTP_BC(ins) DUK__CONSTP(DUK_DEC_BC((ins))) |
| 78825 | #define DUK__REGCONSTP_B(ins) ((((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK_DEC_B((ins))) |
| 78826 | #define DUK__REGCONSTP_C(ins) ((((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK_DEC_C((ins))) |
| 78827 | #endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */ |
| 78828 | |
| 78829 | #if defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS) |
| 78830 | #define DUK__INTERNAL_ERROR(msg) do { \ |
| 78831 | DUK_ERROR_ERROR(thr, (msg)); \ |
| 78832 | DUK_WO_NORETURN(return;); \ |
| 78833 | } while (0) |
| 78834 | #else |
| 78835 | #define DUK__INTERNAL_ERROR(msg) do { \ |
| 78836 | goto internal_error; \ |
| 78837 | } while (0) |
| 78838 | #endif |
| 78839 | |
| 78840 | #define DUK__SYNC_CURR_PC() do { \ |
| 78841 | duk_activation *duk__act; \ |
| 78842 | duk__act = thr->callstack_curr; \ |
| 78843 | duk__act->curr_pc = curr_pc; \ |
| 78844 | } while (0) |
| 78845 | #define DUK__SYNC_AND_NULL_CURR_PC() do { \ |
| 78846 | duk_activation *duk__act; \ |
| 78847 | duk__act = thr->callstack_curr; \ |
| 78848 | duk__act->curr_pc = curr_pc; \ |
| 78849 | thr->ptr_curr_pc = NULL; \ |
| 78850 | } while (0) |
| 78851 | |
| 78852 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 78853 | #define DUK__LOOKUP_INDIRECT(idx) do { \ |
| 78854 | (idx) = (duk_uint_fast_t) duk_get_uint(thr, (duk_idx_t) (idx)); \ |
| 78855 | } while (0) |
| 78856 | #elif defined(DUK_USE_FASTINT) |
| 78857 | #define DUK__LOOKUP_INDIRECT(idx) do { \ |
| 78858 | duk_tval *tv_ind; \ |
| 78859 | tv_ind = DUK__REGP((idx)); \ |
| 78860 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \ |
| 78861 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_ind)); /* compiler guarantees */ \ |
| 78862 | (idx) = (duk_uint_fast_t) DUK_TVAL_GET_FASTINT_U32(tv_ind); \ |
| 78863 | } while (0) |
| 78864 | #else |
| 78865 | #define DUK__LOOKUP_INDIRECT(idx) do { \ |
| 78866 | duk_tval *tv_ind; \ |
| 78867 | tv_ind = DUK__REGP(idx); \ |
| 78868 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \ |
| 78869 | idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind); \ |
| 78870 | } while (0) |
| 78871 | #endif |
| 78872 | |
| 78873 | DUK_LOCAL void duk__handle_executor_error(duk_heap *heap, |
| 78874 | duk_activation *entry_act, |
| 78875 | duk_int_t entry_call_recursion_depth, |
| 78876 | duk_jmpbuf *entry_jmpbuf_ptr, |
| 78877 | volatile duk_bool_t *out_delayed_catch_setup) { |
| 78878 | duk_small_uint_t lj_ret; |
| 78879 | |
| 78880 | /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc |
| 78881 | * before longjmp. |
| 78882 | */ |
| 78883 | DUK_ASSERT(heap->curr_thread != NULL); |
| 78884 | DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL); |
| 78885 | |
| 78886 | /* XXX: signalling the need to shrink check (only if unwound) */ |
| 78887 | |
| 78888 | /* Must be restored here to handle e.g. yields properly. */ |
| 78889 | heap->call_recursion_depth = entry_call_recursion_depth; |
| 78890 | |
| 78891 | /* Switch to caller's setjmp() catcher so that if an error occurs |
| 78892 | * during error handling, it is always propagated outwards instead |
| 78893 | * of causing an infinite loop in our own handler. |
| 78894 | */ |
| 78895 | heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr; |
| 78896 | |
| 78897 | lj_ret = duk__handle_longjmp(heap->curr_thread, entry_act, out_delayed_catch_setup); |
| 78898 | |
| 78899 | /* Error handling complete, remove side effect protections. |
| 78900 | */ |
| 78901 | #if defined(DUK_USE_ASSERTIONS) |
| 78902 | DUK_ASSERT(heap->error_not_allowed == 1); |
| 78903 | heap->error_not_allowed = 0; |
| 78904 | #endif |
| 78905 | DUK_ASSERT(heap->pf_prevent_count > 0); |
| 78906 | heap->pf_prevent_count--; |
| 78907 | DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld" , (long) heap->pf_prevent_count)); |
| 78908 | |
| 78909 | if (lj_ret == DUK__LONGJMP_RESTART) { |
| 78910 | /* Restart bytecode execution, possibly with a changed thread. */ |
| 78911 | DUK_REFZERO_CHECK_SLOW(heap->curr_thread); |
| 78912 | } else { |
| 78913 | /* If an error is propagated, don't run refzero checks here. |
| 78914 | * The next catcher will deal with that. Pf_prevent_count |
| 78915 | * will be re-bumped by the longjmp. |
| 78916 | */ |
| 78917 | |
| 78918 | DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW); /* Rethrow error to calling state. */ |
| 78919 | DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr); /* Longjmp handling has restored jmpbuf_ptr. */ |
| 78920 | |
| 78921 | /* Thread may have changed, e.g. YIELD converted to THROW. */ |
| 78922 | duk_err_longjmp(heap->curr_thread); |
| 78923 | DUK_UNREACHABLE(); |
| 78924 | } |
| 78925 | } |
| 78926 | |
| 78927 | /* Outer executor with setjmp/longjmp handling. */ |
| 78928 | DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) { |
| 78929 | /* Entry level info. */ |
| 78930 | duk_hthread *entry_thread; |
| 78931 | duk_activation *entry_act; |
| 78932 | duk_int_t entry_call_recursion_depth; |
| 78933 | duk_jmpbuf *entry_jmpbuf_ptr; |
| 78934 | duk_jmpbuf our_jmpbuf; |
| 78935 | duk_heap *heap; |
| 78936 | volatile duk_bool_t delayed_catch_setup = 0; |
| 78937 | |
| 78938 | DUK_ASSERT(exec_thr != NULL); |
| 78939 | DUK_ASSERT(exec_thr->heap != NULL); |
| 78940 | DUK_ASSERT(exec_thr->heap->curr_thread != NULL); |
| 78941 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr); |
| 78942 | DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */ |
| 78943 | DUK_ASSERT(exec_thr->callstack_curr != NULL); |
| 78944 | DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL); |
| 78945 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr))); |
| 78946 | |
| 78947 | DUK_GC_TORTURE(exec_thr->heap); |
| 78948 | |
| 78949 | entry_thread = exec_thr; |
| 78950 | heap = entry_thread->heap; |
| 78951 | entry_act = entry_thread->callstack_curr; |
| 78952 | DUK_ASSERT(entry_act != NULL); |
| 78953 | entry_call_recursion_depth = entry_thread->heap->call_recursion_depth; |
| 78954 | entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr; |
| 78955 | |
| 78956 | /* |
| 78957 | * Note: we currently assume that the setjmp() catchpoint is |
| 78958 | * not re-entrant (longjmp() cannot be called more than once |
| 78959 | * for a single setjmp()). |
| 78960 | * |
| 78961 | * See doc/code-issues.rst for notes on variable assignment |
| 78962 | * before and after setjmp(). |
| 78963 | */ |
| 78964 | |
| 78965 | for (;;) { |
| 78966 | heap->lj.jmpbuf_ptr = &our_jmpbuf; |
| 78967 | DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL); |
| 78968 | |
| 78969 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 78970 | try { |
| 78971 | #else |
| 78972 | DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf); |
| 78973 | if (DUK_SETJMP(our_jmpbuf.jb) == 0) { |
| 78974 | #endif |
| 78975 | DUK_DDD(DUK_DDDPRINT("after setjmp, delayed catch setup: %ld\n" , (long) delayed_catch_setup)); |
| 78976 | |
| 78977 | if (DUK_UNLIKELY(delayed_catch_setup != 0)) { |
| 78978 | duk_hthread *thr = entry_thread->heap->curr_thread; |
| 78979 | |
| 78980 | delayed_catch_setup = 0; |
| 78981 | duk__handle_catch_part2(thr); |
| 78982 | DUK_ASSERT(delayed_catch_setup == 0); |
| 78983 | DUK_DDD(DUK_DDDPRINT("top after delayed catch setup: %ld" , (long) duk_get_top(entry_thread))); |
| 78984 | } |
| 78985 | |
| 78986 | /* Execute bytecode until returned or longjmp(). */ |
| 78987 | duk__js_execute_bytecode_inner(entry_thread, entry_act); |
| 78988 | |
| 78989 | /* Successful return: restore jmpbuf and return to caller. */ |
| 78990 | heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr; |
| 78991 | |
| 78992 | return; |
| 78993 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 78994 | } catch (duk_internal_exception &exc) { |
| 78995 | #else |
| 78996 | } else { |
| 78997 | #endif |
| 78998 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 78999 | DUK_UNREF(exc); |
| 79000 | #endif |
| 79001 | DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor" )); |
| 79002 | DUK_STATS_INC(exec_thr->heap, stats_exec_throw); |
| 79003 | |
| 79004 | duk__handle_executor_error(heap, |
| 79005 | entry_act, |
| 79006 | entry_call_recursion_depth, |
| 79007 | entry_jmpbuf_ptr, |
| 79008 | &delayed_catch_setup); |
| 79009 | } |
| 79010 | #if defined(DUK_USE_CPP_EXCEPTIONS) |
| 79011 | catch (duk_fatal_exception &exc) { |
| 79012 | DUK_D(DUK_DPRINT("rethrow duk_fatal_exception" )); |
| 79013 | DUK_UNREF(exc); |
| 79014 | throw; |
| 79015 | } catch (std::exception &exc) { |
| 79016 | const char *what = exc.what(); |
| 79017 | if (!what) { |
| 79018 | what = "unknown" ; |
| 79019 | } |
| 79020 | DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)" )); |
| 79021 | DUK_STATS_INC(exec_thr->heap, stats_exec_throw); |
| 79022 | try { |
| 79023 | DUK_ASSERT(heap->curr_thread != NULL); |
| 79024 | DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)" , what); |
| 79025 | DUK_WO_NORETURN(return;); |
| 79026 | } catch (duk_internal_exception exc) { |
| 79027 | DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception" )); |
| 79028 | DUK_UNREF(exc); |
| 79029 | duk__handle_executor_error(heap, |
| 79030 | entry_act, |
| 79031 | entry_call_recursion_depth, |
| 79032 | entry_jmpbuf_ptr, |
| 79033 | &delayed_catch_setup); |
| 79034 | } |
| 79035 | } catch (...) { |
| 79036 | DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)" )); |
| 79037 | DUK_STATS_INC(exec_thr->heap, stats_exec_throw); |
| 79038 | try { |
| 79039 | DUK_ASSERT(heap->curr_thread != NULL); |
| 79040 | DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)" ); |
| 79041 | DUK_WO_NORETURN(return;); |
| 79042 | } catch (duk_internal_exception exc) { |
| 79043 | DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception" )); |
| 79044 | DUK_UNREF(exc); |
| 79045 | duk__handle_executor_error(heap, |
| 79046 | entry_act, |
| 79047 | entry_call_recursion_depth, |
| 79048 | entry_jmpbuf_ptr, |
| 79049 | &delayed_catch_setup); |
| 79050 | } |
| 79051 | } |
| 79052 | #endif |
| 79053 | } |
| 79054 | |
| 79055 | DUK_WO_NORETURN(return;); |
| 79056 | } |
| 79057 | |
| 79058 | /* Inner executor, performance critical. */ |
| 79059 | DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act) { |
| 79060 | /* Current PC, accessed by other functions through thr->ptr_to_curr_pc. |
| 79061 | * Critical for performance. It would be safest to make this volatile, |
| 79062 | * but that eliminates performance benefits; aliasing guarantees |
| 79063 | * should be enough though. |
| 79064 | */ |
| 79065 | duk_instr_t *curr_pc; /* bytecode has a stable pointer */ |
| 79066 | |
| 79067 | /* Hot variables for interpretation. Critical for performance, |
| 79068 | * but must add sparingly to minimize register shuffling. |
| 79069 | */ |
| 79070 | duk_hthread *thr; /* stable */ |
| 79071 | duk_tval *consts; /* stable */ |
| 79072 | duk_uint_fast32_t ins; |
| 79073 | /* 'funcs' is quite rarely used, so no local for it */ |
| 79074 | #if defined(DUK_USE_EXEC_FUN_LOCAL) |
| 79075 | duk_hcompfunc *fun; |
| 79076 | #else |
| 79077 | /* 'fun' is quite rarely used, so no local for it */ |
| 79078 | #endif |
| 79079 | |
| 79080 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 79081 | duk_int_t int_ctr; |
| 79082 | #endif |
| 79083 | |
| 79084 | #if defined(DUK_USE_ASSERTIONS) |
| 79085 | duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */ |
| 79086 | #endif |
| 79087 | |
| 79088 | /* Optimized reg/const access macros assume sizeof(duk_tval) to be |
| 79089 | * either 8 or 16. Heap allocation checks this even without asserts |
| 79090 | * enabled now because it can't be autodetected in duk_config.h. |
| 79091 | */ |
| 79092 | #if 1 |
| 79093 | #if defined(DUK_USE_PACKED_TVAL) |
| 79094 | DUK_ASSERT(sizeof(duk_tval) == 8); |
| 79095 | #else |
| 79096 | DUK_ASSERT(sizeof(duk_tval) == 16); |
| 79097 | #endif |
| 79098 | #endif |
| 79099 | |
| 79100 | DUK_GC_TORTURE(entry_thread->heap); |
| 79101 | |
| 79102 | /* |
| 79103 | * Restart execution by reloading thread state. |
| 79104 | * |
| 79105 | * Note that 'thr' and any thread configuration may have changed, |
| 79106 | * so all local variables are suspect and we need to reinitialize. |
| 79107 | * |
| 79108 | * The number of local variables should be kept to a minimum: if |
| 79109 | * the variables are spilled, they will need to be loaded from |
| 79110 | * memory anyway. |
| 79111 | * |
| 79112 | * Any 'goto restart_execution;' code path in opcode dispatch must |
| 79113 | * ensure 'curr_pc' is synced back to act->curr_pc before the goto |
| 79114 | * takes place. |
| 79115 | * |
| 79116 | * The interpreter must be very careful with memory pointers, as |
| 79117 | * many pointers are not guaranteed to be 'stable' and may be |
| 79118 | * reallocated and relocated on-the-fly quite easily (e.g. by a |
| 79119 | * memory allocation or a property access). |
| 79120 | * |
| 79121 | * The following are assumed to have stable pointers: |
| 79122 | * - the current thread |
| 79123 | * - the current function |
| 79124 | * - the bytecode, constant table, inner function table of the |
| 79125 | * current function (as they are a part of the function allocation) |
| 79126 | * |
| 79127 | * The following are assumed to have semi-stable pointers: |
| 79128 | * - the current activation entry: stable as long as callstack |
| 79129 | * is not changed (reallocated by growing or shrinking), or |
| 79130 | * by any garbage collection invocation (through finalizers) |
| 79131 | * - Note in particular that ANY DECREF can invalidate the |
| 79132 | * activation pointer, so for the most part a fresh lookup |
| 79133 | * is required |
| 79134 | * |
| 79135 | * The following are not assumed to have stable pointers at all: |
| 79136 | * - the value stack (registers) of the current thread |
| 79137 | * |
| 79138 | * See execution.rst for discussion. |
| 79139 | */ |
| 79140 | |
| 79141 | restart_execution: |
| 79142 | |
| 79143 | /* Lookup current thread; use the stable 'entry_thread' for this to |
| 79144 | * avoid clobber warnings. Any valid, reachable 'thr' value would be |
| 79145 | * fine for this, so using 'entry_thread' is just to silence warnings. |
| 79146 | */ |
| 79147 | thr = entry_thread->heap->curr_thread; |
| 79148 | DUK_ASSERT(thr != NULL); |
| 79149 | DUK_ASSERT(thr->callstack_top >= 1); |
| 79150 | DUK_ASSERT(thr->callstack_curr != NULL); |
| 79151 | DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); |
| 79152 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr))); |
| 79153 | |
| 79154 | DUK_GC_TORTURE(thr->heap); |
| 79155 | |
| 79156 | thr->ptr_curr_pc = &curr_pc; |
| 79157 | |
| 79158 | /* Relookup and initialize dispatch loop variables. Debugger check. */ |
| 79159 | { |
| 79160 | duk_activation *act; |
| 79161 | #if !defined(DUK_USE_EXEC_FUN_LOCAL) |
| 79162 | duk_hcompfunc *fun; |
| 79163 | #endif |
| 79164 | |
| 79165 | /* Assume interrupt init/counter are properly initialized here. */ |
| 79166 | /* Assume that thr->valstack_bottom has been set-up before getting here. */ |
| 79167 | |
| 79168 | act = thr->callstack_curr; |
| 79169 | DUK_ASSERT(act != NULL); |
| 79170 | fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); |
| 79171 | DUK_ASSERT(fun != NULL); |
| 79172 | DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs); |
| 79173 | consts = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, fun); |
| 79174 | DUK_ASSERT(consts != NULL); |
| 79175 | |
| 79176 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 79177 | if (DUK_UNLIKELY(duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing)) { |
| 79178 | duk__executor_recheck_debugger(thr, act, fun); |
| 79179 | DUK_ASSERT(act == thr->callstack_curr); |
| 79180 | DUK_ASSERT(act != NULL); |
| 79181 | } |
| 79182 | #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| 79183 | |
| 79184 | #if defined(DUK_USE_ASSERTIONS) |
| 79185 | valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack); |
| 79186 | #endif |
| 79187 | |
| 79188 | /* Set up curr_pc for opcode dispatch. */ |
| 79189 | curr_pc = act->curr_pc; |
| 79190 | } |
| 79191 | |
| 79192 | DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p," |
| 79193 | "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, " |
| 79194 | "preventcount=%ld" , |
| 79195 | (void *) thr, |
| 79196 | (long) (thr->callstack_top - 1), |
| 79197 | (void *) DUK__FUN(), |
| 79198 | (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, DUK__FUN()), |
| 79199 | (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, DUK__FUN()), |
| 79200 | (long) (thr->callstack_top - 1), |
| 79201 | (long) (thr->valstack_bottom - thr->valstack), |
| 79202 | (long) (thr->valstack_top - thr->valstack), |
| 79203 | (long) thr->callstack_preventcount)); |
| 79204 | |
| 79205 | /* Dispatch loop. */ |
| 79206 | |
| 79207 | for (;;) { |
| 79208 | duk_uint8_t op; |
| 79209 | |
| 79210 | DUK_ASSERT(thr->callstack_top >= 1); |
| 79211 | DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs); |
| 79212 | DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base); |
| 79213 | |
| 79214 | /* Executor interrupt counter check, used to implement breakpoints, |
| 79215 | * debugging interface, execution timeouts, etc. The counter is heap |
| 79216 | * specific but is maintained in the current thread to make the check |
| 79217 | * as fast as possible. The counter is copied back to the heap struct |
| 79218 | * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro. |
| 79219 | */ |
| 79220 | #if defined(DUK_USE_INTERRUPT_COUNTER) |
| 79221 | int_ctr = thr->interrupt_counter; |
| 79222 | if (DUK_LIKELY(int_ctr > 0)) { |
| 79223 | thr->interrupt_counter = int_ctr - 1; |
| 79224 | } else { |
| 79225 | /* Trigger at zero or below */ |
| 79226 | duk_small_uint_t exec_int_ret; |
| 79227 | |
| 79228 | DUK_STATS_INC(thr->heap, stats_exec_interrupt); |
| 79229 | |
| 79230 | /* Write curr_pc back for the debugger. */ |
| 79231 | { |
| 79232 | duk_activation *act; |
| 79233 | DUK_ASSERT(thr->callstack_top > 0); |
| 79234 | act = thr->callstack_curr; |
| 79235 | DUK_ASSERT(act != NULL); |
| 79236 | act->curr_pc = (duk_instr_t *) curr_pc; |
| 79237 | } |
| 79238 | |
| 79239 | /* Forced restart caused by a function return; must recheck |
| 79240 | * debugger breakpoints before checking line transitions, |
| 79241 | * see GH-303. Restart and then handle interrupt_counter |
| 79242 | * zero again. |
| 79243 | */ |
| 79244 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 79245 | if (thr->heap->dbg_force_restart) { |
| 79246 | DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution" )); /* GH-303 */ |
| 79247 | thr->heap->dbg_force_restart = 0; |
| 79248 | goto restart_execution; |
| 79249 | } |
| 79250 | #endif |
| 79251 | |
| 79252 | exec_int_ret = duk__executor_interrupt(thr); |
| 79253 | if (exec_int_ret == DUK__INT_RESTART) { |
| 79254 | /* curr_pc synced back above */ |
| 79255 | goto restart_execution; |
| 79256 | } |
| 79257 | } |
| 79258 | #endif /* DUK_USE_INTERRUPT_COUNTER */ |
| 79259 | #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG) |
| 79260 | /* For cross-checking during development: ensure dispatch count |
| 79261 | * matches cumulative interrupt counter init value sums. |
| 79262 | */ |
| 79263 | thr->heap->inst_count_exec++; |
| 79264 | #endif |
| 79265 | |
| 79266 | #if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG) |
| 79267 | { |
| 79268 | duk_activation *act; |
| 79269 | act = thr->callstack_curr; |
| 79270 | DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())); |
| 79271 | DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN())); |
| 79272 | DUK_UNREF(act); /* if debugging disabled */ |
| 79273 | |
| 79274 | DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I" , |
| 79275 | (long) (curr_pc - DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())), |
| 79276 | (unsigned long) *curr_pc, |
| 79277 | (long) DUK_DEC_OP(*curr_pc), |
| 79278 | (long) (thr->valstack_top - thr->valstack), |
| 79279 | (long) (thr->valstack_end - thr->valstack), |
| 79280 | (long) (DUK__FUN() ? DUK__FUN()->nregs : -1), |
| 79281 | (duk_instr_t) *curr_pc)); |
| 79282 | } |
| 79283 | #endif |
| 79284 | |
| 79285 | #if defined(DUK_USE_ASSERTIONS) |
| 79286 | /* Quite heavy assert: check valstack policy. Improper |
| 79287 | * shuffle instructions can write beyond valstack_top/end |
| 79288 | * so this check catches them in the act. |
| 79289 | */ |
| 79290 | { |
| 79291 | duk_tval *tv; |
| 79292 | tv = thr->valstack_top; |
| 79293 | while (tv != thr->valstack_end) { |
| 79294 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); |
| 79295 | tv++; |
| 79296 | } |
| 79297 | } |
| 79298 | #endif |
| 79299 | |
| 79300 | ins = *curr_pc++; |
| 79301 | DUK_STATS_INC(thr->heap, stats_exec_opcodes); |
| 79302 | |
| 79303 | /* Typing: use duk_small_(u)int_fast_t when decoding small |
| 79304 | * opcode fields (op, A, B, C, BC) which fit into 16 bits |
| 79305 | * and duk_(u)int_fast_t when decoding larger fields (e.g. |
| 79306 | * ABC). Use unsigned variant by default, signed when the |
| 79307 | * value is used in signed arithmetic. Using variable names |
| 79308 | * such as 'a', 'b', 'c', 'bc', etc makes it easier to spot |
| 79309 | * typing mismatches. |
| 79310 | */ |
| 79311 | |
| 79312 | /* Switch based on opcode. Cast to 8-bit unsigned value and |
| 79313 | * use a fully populated case clauses so that the compiler |
| 79314 | * will (at least usually) omit a bounds check. |
| 79315 | */ |
| 79316 | op = (duk_uint8_t) DUK_DEC_OP(ins); |
| 79317 | switch (op) { |
| 79318 | |
| 79319 | /* Some useful macros. These access inner executor variables |
| 79320 | * directly so they only apply within the executor. |
| 79321 | */ |
| 79322 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79323 | #define DUK__REPLACE_TOP_A_BREAK() { goto replace_top_a; } |
| 79324 | #define DUK__REPLACE_TOP_BC_BREAK() { goto replace_top_bc; } |
| 79325 | #define DUK__REPLACE_BOOL_A_BREAK(bval) { \ |
| 79326 | duk_bool_t duk__bval; \ |
| 79327 | duk__bval = (bval); \ |
| 79328 | DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \ |
| 79329 | duk_push_boolean(thr, duk__bval); \ |
| 79330 | DUK__REPLACE_TOP_A_BREAK(); \ |
| 79331 | } |
| 79332 | #else |
| 79333 | #define DUK__REPLACE_TOP_A_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); break; } |
| 79334 | #define DUK__REPLACE_TOP_BC_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); break; } |
| 79335 | #define DUK__REPLACE_BOOL_A_BREAK(bval) { \ |
| 79336 | duk_bool_t duk__bval; \ |
| 79337 | duk_tval *duk__tvdst; \ |
| 79338 | duk__bval = (bval); \ |
| 79339 | DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \ |
| 79340 | duk__tvdst = DUK__REGP_A(ins); \ |
| 79341 | DUK_TVAL_SET_BOOLEAN_UPDREF(thr, duk__tvdst, duk__bval); \ |
| 79342 | break; \ |
| 79343 | } |
| 79344 | #endif |
| 79345 | |
| 79346 | /* XXX: 12 + 12 bit variant might make sense too, for both reg and |
| 79347 | * const loads. |
| 79348 | */ |
| 79349 | |
| 79350 | /* For LDREG, STREG, LDCONST footprint optimized variants would just |
| 79351 | * duk_dup() + duk_replace(), but because they're used quite a lot |
| 79352 | * they're currently intentionally not size optimized. |
| 79353 | */ |
| 79354 | case DUK_OP_LDREG: { |
| 79355 | duk_tval *tv1, *tv2; |
| 79356 | |
| 79357 | tv1 = DUK__REGP_A(ins); |
| 79358 | tv2 = DUK__REGP_BC(ins); |
| 79359 | DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */ |
| 79360 | break; |
| 79361 | } |
| 79362 | |
| 79363 | case DUK_OP_STREG: { |
| 79364 | duk_tval *tv1, *tv2; |
| 79365 | |
| 79366 | tv1 = DUK__REGP_A(ins); |
| 79367 | tv2 = DUK__REGP_BC(ins); |
| 79368 | DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */ |
| 79369 | break; |
| 79370 | } |
| 79371 | |
| 79372 | case DUK_OP_LDCONST: { |
| 79373 | duk_tval *tv1, *tv2; |
| 79374 | |
| 79375 | tv1 = DUK__REGP_A(ins); |
| 79376 | tv2 = DUK__CONSTP_BC(ins); |
| 79377 | DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */ |
| 79378 | break; |
| 79379 | } |
| 79380 | |
| 79381 | /* LDINT and LDINTX are intended to load an arbitrary signed |
| 79382 | * 32-bit value. Only an LDINT+LDINTX sequence is supported. |
| 79383 | * This also guarantees all values remain fastints. |
| 79384 | */ |
| 79385 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79386 | case DUK_OP_LDINT: { |
| 79387 | duk_int32_t val; |
| 79388 | |
| 79389 | val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS; |
| 79390 | duk_push_int(thr, val); |
| 79391 | DUK__REPLACE_TOP_A_BREAK(); |
| 79392 | } |
| 79393 | case DUK_OP_LDINTX: { |
| 79394 | duk_int32_t val; |
| 79395 | |
| 79396 | val = (duk_int32_t) duk_get_int(thr, DUK_DEC_A(ins)); |
| 79397 | val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */ |
| 79398 | duk_push_int(thr, val); |
| 79399 | DUK__REPLACE_TOP_A_BREAK(); |
| 79400 | } |
| 79401 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79402 | case DUK_OP_LDINT: { |
| 79403 | duk_tval *tv1; |
| 79404 | duk_int32_t val; |
| 79405 | |
| 79406 | val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS; |
| 79407 | tv1 = DUK__REGP_A(ins); |
| 79408 | DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */ |
| 79409 | break; |
| 79410 | } |
| 79411 | case DUK_OP_LDINTX: { |
| 79412 | duk_tval *tv1; |
| 79413 | duk_int32_t val; |
| 79414 | |
| 79415 | tv1 = DUK__REGP_A(ins); |
| 79416 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); |
| 79417 | #if defined(DUK_USE_FASTINT) |
| 79418 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); |
| 79419 | val = DUK_TVAL_GET_FASTINT_I32(tv1); |
| 79420 | #else |
| 79421 | /* XXX: fast double-to-int conversion, we know number is integer in [-0x80000000,0xffffffff]. */ |
| 79422 | val = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv1); |
| 79423 | #endif |
| 79424 | val = (duk_int32_t) ((duk_uint32_t) val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */ |
| 79425 | DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */ |
| 79426 | break; |
| 79427 | } |
| 79428 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79429 | |
| 79430 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79431 | case DUK_OP_LDTHIS: { |
| 79432 | duk_push_this(thr); |
| 79433 | DUK__REPLACE_TOP_BC_BREAK(); |
| 79434 | } |
| 79435 | case DUK_OP_LDUNDEF: { |
| 79436 | duk_to_undefined(thr, (duk_idx_t) DUK_DEC_BC(ins)); |
| 79437 | break; |
| 79438 | } |
| 79439 | case DUK_OP_LDNULL: { |
| 79440 | duk_to_null(thr, (duk_idx_t) DUK_DEC_BC(ins)); |
| 79441 | break; |
| 79442 | } |
| 79443 | case DUK_OP_LDTRUE: { |
| 79444 | duk_push_true(thr); |
| 79445 | DUK__REPLACE_TOP_BC_BREAK(); |
| 79446 | } |
| 79447 | case DUK_OP_LDFALSE: { |
| 79448 | duk_push_false(thr); |
| 79449 | DUK__REPLACE_TOP_BC_BREAK(); |
| 79450 | } |
| 79451 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79452 | case DUK_OP_LDTHIS: { |
| 79453 | /* Note: 'this' may be bound to any value, not just an object */ |
| 79454 | duk_tval *tv1, *tv2; |
| 79455 | |
| 79456 | tv1 = DUK__REGP_BC(ins); |
| 79457 | tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */ |
| 79458 | DUK_ASSERT(tv2 >= thr->valstack); |
| 79459 | DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */ |
| 79460 | break; |
| 79461 | } |
| 79462 | case DUK_OP_LDUNDEF: { |
| 79463 | duk_tval *tv1; |
| 79464 | |
| 79465 | tv1 = DUK__REGP_BC(ins); |
| 79466 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */ |
| 79467 | break; |
| 79468 | } |
| 79469 | case DUK_OP_LDNULL: { |
| 79470 | duk_tval *tv1; |
| 79471 | |
| 79472 | tv1 = DUK__REGP_BC(ins); |
| 79473 | DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */ |
| 79474 | break; |
| 79475 | } |
| 79476 | case DUK_OP_LDTRUE: { |
| 79477 | duk_tval *tv1; |
| 79478 | |
| 79479 | tv1 = DUK__REGP_BC(ins); |
| 79480 | DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 1); /* side effects */ |
| 79481 | break; |
| 79482 | } |
| 79483 | case DUK_OP_LDFALSE: { |
| 79484 | duk_tval *tv1; |
| 79485 | |
| 79486 | tv1 = DUK__REGP_BC(ins); |
| 79487 | DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 0); /* side effects */ |
| 79488 | break; |
| 79489 | } |
| 79490 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79491 | |
| 79492 | case DUK_OP_BNOT: { |
| 79493 | duk__vm_bitwise_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins)); |
| 79494 | break; |
| 79495 | } |
| 79496 | |
| 79497 | case DUK_OP_LNOT: { |
| 79498 | duk__vm_logical_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins)); |
| 79499 | break; |
| 79500 | } |
| 79501 | |
| 79502 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79503 | case DUK_OP_UNM: |
| 79504 | case DUK_OP_UNP: { |
| 79505 | duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), op); |
| 79506 | break; |
| 79507 | } |
| 79508 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79509 | case DUK_OP_UNM: { |
| 79510 | duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNM); |
| 79511 | break; |
| 79512 | } |
| 79513 | case DUK_OP_UNP: { |
| 79514 | duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNP); |
| 79515 | break; |
| 79516 | } |
| 79517 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79518 | |
| 79519 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79520 | case DUK_OP_TYPEOF: { |
| 79521 | duk_small_uint_t stridx; |
| 79522 | |
| 79523 | stridx = duk_js_typeof_stridx(DUK__REGP_BC(ins)); |
| 79524 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 79525 | duk_push_hstring_stridx(thr, stridx); |
| 79526 | DUK__REPLACE_TOP_A_BREAK(); |
| 79527 | } |
| 79528 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79529 | case DUK_OP_TYPEOF: { |
| 79530 | duk_tval *tv; |
| 79531 | duk_small_uint_t stridx; |
| 79532 | duk_hstring *h_str; |
| 79533 | |
| 79534 | tv = DUK__REGP_BC(ins); |
| 79535 | stridx = duk_js_typeof_stridx(tv); |
| 79536 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 79537 | h_str = DUK_HTHREAD_GET_STRING(thr, stridx); |
| 79538 | tv = DUK__REGP_A(ins); |
| 79539 | DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str); |
| 79540 | break; |
| 79541 | } |
| 79542 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79543 | |
| 79544 | case DUK_OP_TYPEOFID: { |
| 79545 | duk_small_uint_t stridx; |
| 79546 | #if !defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79547 | duk_hstring *h_str; |
| 79548 | #endif |
| 79549 | duk_activation *act; |
| 79550 | duk_hstring *name; |
| 79551 | duk_tval *tv; |
| 79552 | |
| 79553 | /* A -> target register |
| 79554 | * BC -> constant index of identifier name |
| 79555 | */ |
| 79556 | |
| 79557 | tv = DUK__CONSTP_BC(ins); |
| 79558 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv)); |
| 79559 | name = DUK_TVAL_GET_STRING(tv); |
| 79560 | tv = NULL; /* lookup has side effects */ |
| 79561 | act = thr->callstack_curr; |
| 79562 | if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) { |
| 79563 | /* -> [... val this] */ |
| 79564 | tv = DUK_GET_TVAL_NEGIDX(thr, -2); |
| 79565 | stridx = duk_js_typeof_stridx(tv); |
| 79566 | tv = NULL; /* no longer needed */ |
| 79567 | duk_pop_2_unsafe(thr); |
| 79568 | } else { |
| 79569 | /* unresolvable, no stack changes */ |
| 79570 | stridx = DUK_STRIDX_LC_UNDEFINED; |
| 79571 | } |
| 79572 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 79573 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79574 | duk_push_hstring_stridx(thr, stridx); |
| 79575 | DUK__REPLACE_TOP_A_BREAK(); |
| 79576 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79577 | h_str = DUK_HTHREAD_GET_STRING(thr, stridx); |
| 79578 | tv = DUK__REGP_A(ins); |
| 79579 | DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str); |
| 79580 | break; |
| 79581 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79582 | } |
| 79583 | |
| 79584 | /* Equality: E5 Sections 11.9.1, 11.9.3 */ |
| 79585 | |
| 79586 | #define DUK__EQ_BODY(barg,carg) { \ |
| 79587 | duk_bool_t tmp; \ |
| 79588 | tmp = duk_js_equals(thr, (barg), (carg)); \ |
| 79589 | DUK_ASSERT(tmp == 0 || tmp == 1); \ |
| 79590 | DUK__REPLACE_BOOL_A_BREAK(tmp); \ |
| 79591 | } |
| 79592 | #define DUK__NEQ_BODY(barg,carg) { \ |
| 79593 | duk_bool_t tmp; \ |
| 79594 | tmp = duk_js_equals(thr, (barg), (carg)); \ |
| 79595 | DUK_ASSERT(tmp == 0 || tmp == 1); \ |
| 79596 | tmp ^= 1; \ |
| 79597 | DUK__REPLACE_BOOL_A_BREAK(tmp); \ |
| 79598 | } |
| 79599 | #define DUK__SEQ_BODY(barg,carg) { \ |
| 79600 | duk_bool_t tmp; \ |
| 79601 | tmp = duk_js_strict_equals((barg), (carg)); \ |
| 79602 | DUK_ASSERT(tmp == 0 || tmp == 1); \ |
| 79603 | DUK__REPLACE_BOOL_A_BREAK(tmp); \ |
| 79604 | } |
| 79605 | #define DUK__SNEQ_BODY(barg,carg) { \ |
| 79606 | duk_bool_t tmp; \ |
| 79607 | tmp = duk_js_strict_equals((barg), (carg)); \ |
| 79608 | DUK_ASSERT(tmp == 0 || tmp == 1); \ |
| 79609 | tmp ^= 1; \ |
| 79610 | DUK__REPLACE_BOOL_A_BREAK(tmp); \ |
| 79611 | } |
| 79612 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79613 | case DUK_OP_EQ_RR: |
| 79614 | case DUK_OP_EQ_CR: |
| 79615 | case DUK_OP_EQ_RC: |
| 79616 | case DUK_OP_EQ_CC: |
| 79617 | DUK__EQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79618 | case DUK_OP_NEQ_RR: |
| 79619 | case DUK_OP_NEQ_CR: |
| 79620 | case DUK_OP_NEQ_RC: |
| 79621 | case DUK_OP_NEQ_CC: |
| 79622 | DUK__NEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79623 | case DUK_OP_SEQ_RR: |
| 79624 | case DUK_OP_SEQ_CR: |
| 79625 | case DUK_OP_SEQ_RC: |
| 79626 | case DUK_OP_SEQ_CC: |
| 79627 | DUK__SEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79628 | case DUK_OP_SNEQ_RR: |
| 79629 | case DUK_OP_SNEQ_CR: |
| 79630 | case DUK_OP_SNEQ_RC: |
| 79631 | case DUK_OP_SNEQ_CC: |
| 79632 | DUK__SNEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79633 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79634 | case DUK_OP_EQ_RR: |
| 79635 | DUK__EQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79636 | case DUK_OP_EQ_CR: |
| 79637 | DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79638 | case DUK_OP_EQ_RC: |
| 79639 | DUK__EQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79640 | case DUK_OP_EQ_CC: |
| 79641 | DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79642 | case DUK_OP_NEQ_RR: |
| 79643 | DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79644 | case DUK_OP_NEQ_CR: |
| 79645 | DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79646 | case DUK_OP_NEQ_RC: |
| 79647 | DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79648 | case DUK_OP_NEQ_CC: |
| 79649 | DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79650 | case DUK_OP_SEQ_RR: |
| 79651 | DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79652 | case DUK_OP_SEQ_CR: |
| 79653 | DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79654 | case DUK_OP_SEQ_RC: |
| 79655 | DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79656 | case DUK_OP_SEQ_CC: |
| 79657 | DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79658 | case DUK_OP_SNEQ_RR: |
| 79659 | DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79660 | case DUK_OP_SNEQ_CR: |
| 79661 | DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79662 | case DUK_OP_SNEQ_RC: |
| 79663 | DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79664 | case DUK_OP_SNEQ_CC: |
| 79665 | DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79666 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79667 | |
| 79668 | #define DUK__COMPARE_BODY(arg1,arg2,flags) { \ |
| 79669 | duk_bool_t tmp; \ |
| 79670 | tmp = duk_js_compare_helper(thr, (arg1), (arg2), (flags)); \ |
| 79671 | DUK_ASSERT(tmp == 0 || tmp == 1); \ |
| 79672 | DUK__REPLACE_BOOL_A_BREAK(tmp); \ |
| 79673 | } |
| 79674 | #define DUK__GT_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), 0) |
| 79675 | #define DUK__GE_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE) |
| 79676 | #define DUK__LT_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) |
| 79677 | #define DUK__LE_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), DUK_COMPARE_FLAG_NEGATE) |
| 79678 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79679 | case DUK_OP_GT_RR: |
| 79680 | case DUK_OP_GT_CR: |
| 79681 | case DUK_OP_GT_RC: |
| 79682 | case DUK_OP_GT_CC: |
| 79683 | DUK__GT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79684 | case DUK_OP_GE_RR: |
| 79685 | case DUK_OP_GE_CR: |
| 79686 | case DUK_OP_GE_RC: |
| 79687 | case DUK_OP_GE_CC: |
| 79688 | DUK__GE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79689 | case DUK_OP_LT_RR: |
| 79690 | case DUK_OP_LT_CR: |
| 79691 | case DUK_OP_LT_RC: |
| 79692 | case DUK_OP_LT_CC: |
| 79693 | DUK__LT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79694 | case DUK_OP_LE_RR: |
| 79695 | case DUK_OP_LE_CR: |
| 79696 | case DUK_OP_LE_RC: |
| 79697 | case DUK_OP_LE_CC: |
| 79698 | DUK__LE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 79699 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79700 | case DUK_OP_GT_RR: |
| 79701 | DUK__GT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79702 | case DUK_OP_GT_CR: |
| 79703 | DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79704 | case DUK_OP_GT_RC: |
| 79705 | DUK__GT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79706 | case DUK_OP_GT_CC: |
| 79707 | DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79708 | case DUK_OP_GE_RR: |
| 79709 | DUK__GE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79710 | case DUK_OP_GE_CR: |
| 79711 | DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79712 | case DUK_OP_GE_RC: |
| 79713 | DUK__GE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79714 | case DUK_OP_GE_CC: |
| 79715 | DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79716 | case DUK_OP_LT_RR: |
| 79717 | DUK__LT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79718 | case DUK_OP_LT_CR: |
| 79719 | DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79720 | case DUK_OP_LT_RC: |
| 79721 | DUK__LT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79722 | case DUK_OP_LT_CC: |
| 79723 | DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79724 | case DUK_OP_LE_RR: |
| 79725 | DUK__LE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 79726 | case DUK_OP_LE_CR: |
| 79727 | DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 79728 | case DUK_OP_LE_RC: |
| 79729 | DUK__LE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 79730 | case DUK_OP_LE_CC: |
| 79731 | DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 79732 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79733 | |
| 79734 | /* No size optimized variant at present for IF. */ |
| 79735 | case DUK_OP_IFTRUE_R: { |
| 79736 | if (duk_js_toboolean(DUK__REGP_BC(ins)) != 0) { |
| 79737 | curr_pc++; |
| 79738 | } |
| 79739 | break; |
| 79740 | } |
| 79741 | case DUK_OP_IFTRUE_C: { |
| 79742 | if (duk_js_toboolean(DUK__CONSTP_BC(ins)) != 0) { |
| 79743 | curr_pc++; |
| 79744 | } |
| 79745 | break; |
| 79746 | } |
| 79747 | case DUK_OP_IFFALSE_R: { |
| 79748 | if (duk_js_toboolean(DUK__REGP_BC(ins)) == 0) { |
| 79749 | curr_pc++; |
| 79750 | } |
| 79751 | break; |
| 79752 | } |
| 79753 | case DUK_OP_IFFALSE_C: { |
| 79754 | if (duk_js_toboolean(DUK__CONSTP_BC(ins)) == 0) { |
| 79755 | curr_pc++; |
| 79756 | } |
| 79757 | break; |
| 79758 | } |
| 79759 | |
| 79760 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79761 | case DUK_OP_ADD_RR: |
| 79762 | case DUK_OP_ADD_CR: |
| 79763 | case DUK_OP_ADD_RC: |
| 79764 | case DUK_OP_ADD_CC: { |
| 79765 | /* XXX: could leave value on stack top and goto replace_top_a; */ |
| 79766 | duk__vm_arith_add(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins)); |
| 79767 | break; |
| 79768 | } |
| 79769 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79770 | case DUK_OP_ADD_RR: { |
| 79771 | duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins)); |
| 79772 | break; |
| 79773 | } |
| 79774 | case DUK_OP_ADD_CR: { |
| 79775 | duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins)); |
| 79776 | break; |
| 79777 | } |
| 79778 | case DUK_OP_ADD_RC: { |
| 79779 | duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins)); |
| 79780 | break; |
| 79781 | } |
| 79782 | case DUK_OP_ADD_CC: { |
| 79783 | duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins)); |
| 79784 | break; |
| 79785 | } |
| 79786 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79787 | |
| 79788 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79789 | case DUK_OP_SUB_RR: |
| 79790 | case DUK_OP_SUB_CR: |
| 79791 | case DUK_OP_SUB_RC: |
| 79792 | case DUK_OP_SUB_CC: |
| 79793 | case DUK_OP_MUL_RR: |
| 79794 | case DUK_OP_MUL_CR: |
| 79795 | case DUK_OP_MUL_RC: |
| 79796 | case DUK_OP_MUL_CC: |
| 79797 | case DUK_OP_DIV_RR: |
| 79798 | case DUK_OP_DIV_CR: |
| 79799 | case DUK_OP_DIV_RC: |
| 79800 | case DUK_OP_DIV_CC: |
| 79801 | case DUK_OP_MOD_RR: |
| 79802 | case DUK_OP_MOD_CR: |
| 79803 | case DUK_OP_MOD_RC: |
| 79804 | case DUK_OP_MOD_CC: |
| 79805 | #if defined(DUK_USE_ES7_EXP_OPERATOR) |
| 79806 | case DUK_OP_EXP_RR: |
| 79807 | case DUK_OP_EXP_CR: |
| 79808 | case DUK_OP_EXP_RC: |
| 79809 | case DUK_OP_EXP_CC: |
| 79810 | #endif /* DUK_USE_ES7_EXP_OPERATOR */ |
| 79811 | { |
| 79812 | /* XXX: could leave value on stack top and goto replace_top_a; */ |
| 79813 | duk__vm_arith_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op); |
| 79814 | break; |
| 79815 | } |
| 79816 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79817 | case DUK_OP_SUB_RR: { |
| 79818 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); |
| 79819 | break; |
| 79820 | } |
| 79821 | case DUK_OP_SUB_CR: { |
| 79822 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); |
| 79823 | break; |
| 79824 | } |
| 79825 | case DUK_OP_SUB_RC: { |
| 79826 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); |
| 79827 | break; |
| 79828 | } |
| 79829 | case DUK_OP_SUB_CC: { |
| 79830 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB); |
| 79831 | break; |
| 79832 | } |
| 79833 | case DUK_OP_MUL_RR: { |
| 79834 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); |
| 79835 | break; |
| 79836 | } |
| 79837 | case DUK_OP_MUL_CR: { |
| 79838 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); |
| 79839 | break; |
| 79840 | } |
| 79841 | case DUK_OP_MUL_RC: { |
| 79842 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); |
| 79843 | break; |
| 79844 | } |
| 79845 | case DUK_OP_MUL_CC: { |
| 79846 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL); |
| 79847 | break; |
| 79848 | } |
| 79849 | case DUK_OP_DIV_RR: { |
| 79850 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); |
| 79851 | break; |
| 79852 | } |
| 79853 | case DUK_OP_DIV_CR: { |
| 79854 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); |
| 79855 | break; |
| 79856 | } |
| 79857 | case DUK_OP_DIV_RC: { |
| 79858 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); |
| 79859 | break; |
| 79860 | } |
| 79861 | case DUK_OP_DIV_CC: { |
| 79862 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV); |
| 79863 | break; |
| 79864 | } |
| 79865 | case DUK_OP_MOD_RR: { |
| 79866 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); |
| 79867 | break; |
| 79868 | } |
| 79869 | case DUK_OP_MOD_CR: { |
| 79870 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); |
| 79871 | break; |
| 79872 | } |
| 79873 | case DUK_OP_MOD_RC: { |
| 79874 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); |
| 79875 | break; |
| 79876 | } |
| 79877 | case DUK_OP_MOD_CC: { |
| 79878 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD); |
| 79879 | break; |
| 79880 | } |
| 79881 | #if defined(DUK_USE_ES7_EXP_OPERATOR) |
| 79882 | case DUK_OP_EXP_RR: { |
| 79883 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); |
| 79884 | break; |
| 79885 | } |
| 79886 | case DUK_OP_EXP_CR: { |
| 79887 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); |
| 79888 | break; |
| 79889 | } |
| 79890 | case DUK_OP_EXP_RC: { |
| 79891 | duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); |
| 79892 | break; |
| 79893 | } |
| 79894 | case DUK_OP_EXP_CC: { |
| 79895 | duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP); |
| 79896 | break; |
| 79897 | } |
| 79898 | #endif /* DUK_USE_ES7_EXP_OPERATOR */ |
| 79899 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79900 | |
| 79901 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 79902 | case DUK_OP_BAND_RR: |
| 79903 | case DUK_OP_BAND_CR: |
| 79904 | case DUK_OP_BAND_RC: |
| 79905 | case DUK_OP_BAND_CC: |
| 79906 | case DUK_OP_BOR_RR: |
| 79907 | case DUK_OP_BOR_CR: |
| 79908 | case DUK_OP_BOR_RC: |
| 79909 | case DUK_OP_BOR_CC: |
| 79910 | case DUK_OP_BXOR_RR: |
| 79911 | case DUK_OP_BXOR_CR: |
| 79912 | case DUK_OP_BXOR_RC: |
| 79913 | case DUK_OP_BXOR_CC: |
| 79914 | case DUK_OP_BASL_RR: |
| 79915 | case DUK_OP_BASL_CR: |
| 79916 | case DUK_OP_BASL_RC: |
| 79917 | case DUK_OP_BASL_CC: |
| 79918 | case DUK_OP_BLSR_RR: |
| 79919 | case DUK_OP_BLSR_CR: |
| 79920 | case DUK_OP_BLSR_RC: |
| 79921 | case DUK_OP_BLSR_CC: |
| 79922 | case DUK_OP_BASR_RR: |
| 79923 | case DUK_OP_BASR_CR: |
| 79924 | case DUK_OP_BASR_RC: |
| 79925 | case DUK_OP_BASR_CC: { |
| 79926 | /* XXX: could leave value on stack top and goto replace_top_a; */ |
| 79927 | duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op); |
| 79928 | break; |
| 79929 | } |
| 79930 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 79931 | case DUK_OP_BAND_RR: { |
| 79932 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); |
| 79933 | break; |
| 79934 | } |
| 79935 | case DUK_OP_BAND_CR: { |
| 79936 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); |
| 79937 | break; |
| 79938 | } |
| 79939 | case DUK_OP_BAND_RC: { |
| 79940 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); |
| 79941 | break; |
| 79942 | } |
| 79943 | case DUK_OP_BAND_CC: { |
| 79944 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND); |
| 79945 | break; |
| 79946 | } |
| 79947 | case DUK_OP_BOR_RR: { |
| 79948 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); |
| 79949 | break; |
| 79950 | } |
| 79951 | case DUK_OP_BOR_CR: { |
| 79952 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); |
| 79953 | break; |
| 79954 | } |
| 79955 | case DUK_OP_BOR_RC: { |
| 79956 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); |
| 79957 | break; |
| 79958 | } |
| 79959 | case DUK_OP_BOR_CC: { |
| 79960 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR); |
| 79961 | break; |
| 79962 | } |
| 79963 | case DUK_OP_BXOR_RR: { |
| 79964 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); |
| 79965 | break; |
| 79966 | } |
| 79967 | case DUK_OP_BXOR_CR: { |
| 79968 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); |
| 79969 | break; |
| 79970 | } |
| 79971 | case DUK_OP_BXOR_RC: { |
| 79972 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); |
| 79973 | break; |
| 79974 | } |
| 79975 | case DUK_OP_BXOR_CC: { |
| 79976 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR); |
| 79977 | break; |
| 79978 | } |
| 79979 | case DUK_OP_BASL_RR: { |
| 79980 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); |
| 79981 | break; |
| 79982 | } |
| 79983 | case DUK_OP_BASL_CR: { |
| 79984 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); |
| 79985 | break; |
| 79986 | } |
| 79987 | case DUK_OP_BASL_RC: { |
| 79988 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); |
| 79989 | break; |
| 79990 | } |
| 79991 | case DUK_OP_BASL_CC: { |
| 79992 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL); |
| 79993 | break; |
| 79994 | } |
| 79995 | case DUK_OP_BLSR_RR: { |
| 79996 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); |
| 79997 | break; |
| 79998 | } |
| 79999 | case DUK_OP_BLSR_CR: { |
| 80000 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); |
| 80001 | break; |
| 80002 | } |
| 80003 | case DUK_OP_BLSR_RC: { |
| 80004 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); |
| 80005 | break; |
| 80006 | } |
| 80007 | case DUK_OP_BLSR_CC: { |
| 80008 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR); |
| 80009 | break; |
| 80010 | } |
| 80011 | case DUK_OP_BASR_RR: { |
| 80012 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); |
| 80013 | break; |
| 80014 | } |
| 80015 | case DUK_OP_BASR_CR: { |
| 80016 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); |
| 80017 | break; |
| 80018 | } |
| 80019 | case DUK_OP_BASR_RC: { |
| 80020 | duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); |
| 80021 | break; |
| 80022 | } |
| 80023 | case DUK_OP_BASR_CC: { |
| 80024 | duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR); |
| 80025 | break; |
| 80026 | } |
| 80027 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80028 | |
| 80029 | /* For INSTOF and IN, B is always a register. */ |
| 80030 | #define DUK__INSTOF_BODY(barg,carg) { \ |
| 80031 | duk_bool_t tmp; \ |
| 80032 | tmp = duk_js_instanceof(thr, (barg), (carg)); \ |
| 80033 | DUK_ASSERT(tmp == 0 || tmp == 1); \ |
| 80034 | DUK__REPLACE_BOOL_A_BREAK(tmp); \ |
| 80035 | } |
| 80036 | #define DUK__IN_BODY(barg,carg) { \ |
| 80037 | duk_bool_t tmp; \ |
| 80038 | tmp = duk_js_in(thr, (barg), (carg)); \ |
| 80039 | DUK_ASSERT(tmp == 0 || tmp == 1); \ |
| 80040 | DUK__REPLACE_BOOL_A_BREAK(tmp); \ |
| 80041 | } |
| 80042 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 80043 | case DUK_OP_INSTOF_RR: |
| 80044 | case DUK_OP_INSTOF_CR: |
| 80045 | case DUK_OP_INSTOF_RC: |
| 80046 | case DUK_OP_INSTOF_CC: |
| 80047 | DUK__INSTOF_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 80048 | case DUK_OP_IN_RR: |
| 80049 | case DUK_OP_IN_CR: |
| 80050 | case DUK_OP_IN_RC: |
| 80051 | case DUK_OP_IN_CC: |
| 80052 | DUK__IN_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 80053 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80054 | case DUK_OP_INSTOF_RR: |
| 80055 | DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 80056 | case DUK_OP_INSTOF_CR: |
| 80057 | DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 80058 | case DUK_OP_INSTOF_RC: |
| 80059 | DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 80060 | case DUK_OP_INSTOF_CC: |
| 80061 | DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 80062 | case DUK_OP_IN_RR: |
| 80063 | DUK__IN_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 80064 | case DUK_OP_IN_CR: |
| 80065 | DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 80066 | case DUK_OP_IN_RC: |
| 80067 | DUK__IN_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 80068 | case DUK_OP_IN_CC: |
| 80069 | DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 80070 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80071 | |
| 80072 | /* Pre/post inc/dec for register variables, important for loops. */ |
| 80073 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 80074 | case DUK_OP_PREINCR: |
| 80075 | case DUK_OP_PREDECR: |
| 80076 | case DUK_OP_POSTINCR: |
| 80077 | case DUK_OP_POSTDECR: { |
| 80078 | duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), op); |
| 80079 | break; |
| 80080 | } |
| 80081 | case DUK_OP_PREINCV: |
| 80082 | case DUK_OP_PREDECV: |
| 80083 | case DUK_OP_POSTINCV: |
| 80084 | case DUK_OP_POSTDECV: { |
| 80085 | duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), op, DUK__STRICT()); |
| 80086 | break; |
| 80087 | } |
| 80088 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80089 | case DUK_OP_PREINCR: { |
| 80090 | duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREINCR); |
| 80091 | break; |
| 80092 | } |
| 80093 | case DUK_OP_PREDECR: { |
| 80094 | duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREDECR); |
| 80095 | break; |
| 80096 | } |
| 80097 | case DUK_OP_POSTINCR: { |
| 80098 | duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTINCR); |
| 80099 | break; |
| 80100 | } |
| 80101 | case DUK_OP_POSTDECR: { |
| 80102 | duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTDECR); |
| 80103 | break; |
| 80104 | } |
| 80105 | case DUK_OP_PREINCV: { |
| 80106 | duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREINCV, DUK__STRICT()); |
| 80107 | break; |
| 80108 | } |
| 80109 | case DUK_OP_PREDECV: { |
| 80110 | duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREDECV, DUK__STRICT()); |
| 80111 | break; |
| 80112 | } |
| 80113 | case DUK_OP_POSTINCV: { |
| 80114 | duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTINCV, DUK__STRICT()); |
| 80115 | break; |
| 80116 | } |
| 80117 | case DUK_OP_POSTDECV: { |
| 80118 | duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTDECV, DUK__STRICT()); |
| 80119 | break; |
| 80120 | } |
| 80121 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80122 | |
| 80123 | /* XXX: Move to separate helper, optimize for perf/size separately. */ |
| 80124 | /* Preinc/predec for object properties. */ |
| 80125 | case DUK_OP_PREINCP_RR: |
| 80126 | case DUK_OP_PREINCP_CR: |
| 80127 | case DUK_OP_PREINCP_RC: |
| 80128 | case DUK_OP_PREINCP_CC: |
| 80129 | case DUK_OP_PREDECP_RR: |
| 80130 | case DUK_OP_PREDECP_CR: |
| 80131 | case DUK_OP_PREDECP_RC: |
| 80132 | case DUK_OP_PREDECP_CC: |
| 80133 | case DUK_OP_POSTINCP_RR: |
| 80134 | case DUK_OP_POSTINCP_CR: |
| 80135 | case DUK_OP_POSTINCP_RC: |
| 80136 | case DUK_OP_POSTINCP_CC: |
| 80137 | case DUK_OP_POSTDECP_RR: |
| 80138 | case DUK_OP_POSTDECP_CR: |
| 80139 | case DUK_OP_POSTDECP_RC: |
| 80140 | case DUK_OP_POSTDECP_CC: { |
| 80141 | duk_tval *tv_obj; |
| 80142 | duk_tval *tv_key; |
| 80143 | duk_tval *tv_val; |
| 80144 | duk_bool_t rc; |
| 80145 | duk_double_t x, y, z; |
| 80146 | #if !defined(DUK_USE_EXEC_PREFER_SIZE) |
| 80147 | duk_tval *tv_dst; |
| 80148 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80149 | |
| 80150 | /* A -> target reg |
| 80151 | * B -> object reg/const (may be const e.g. in "'foo'[1]") |
| 80152 | * C -> key reg/const |
| 80153 | */ |
| 80154 | |
| 80155 | /* Opcode bits 0-1 are used to distinguish reg/const variants. |
| 80156 | * Opcode bits 2-3 are used to distinguish inc/dec variants: |
| 80157 | * Bit 2 = inc(0)/dec(1), bit 3 = pre(0)/post(1). |
| 80158 | */ |
| 80159 | DUK_ASSERT((DUK_OP_PREINCP_RR & 0x0c) == 0x00); |
| 80160 | DUK_ASSERT((DUK_OP_PREDECP_RR & 0x0c) == 0x04); |
| 80161 | DUK_ASSERT((DUK_OP_POSTINCP_RR & 0x0c) == 0x08); |
| 80162 | DUK_ASSERT((DUK_OP_POSTDECP_RR & 0x0c) == 0x0c); |
| 80163 | |
| 80164 | tv_obj = DUK__REGCONSTP_B(ins); |
| 80165 | tv_key = DUK__REGCONSTP_C(ins); |
| 80166 | rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */ |
| 80167 | DUK_UNREF(rc); /* ignore */ |
| 80168 | tv_obj = NULL; /* invalidated */ |
| 80169 | tv_key = NULL; /* invalidated */ |
| 80170 | |
| 80171 | /* XXX: Fastint fast path would be useful here. Also fastints |
| 80172 | * now lose their fastint status in current handling which is |
| 80173 | * not intuitive. |
| 80174 | */ |
| 80175 | |
| 80176 | x = duk_to_number_m1(thr); |
| 80177 | duk_pop_unsafe(thr); |
| 80178 | if (ins & DUK_BC_INCDECP_FLAG_DEC) { |
| 80179 | y = x - 1.0; |
| 80180 | } else { |
| 80181 | y = x + 1.0; |
| 80182 | } |
| 80183 | |
| 80184 | duk_push_number(thr, y); |
| 80185 | tv_val = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 80186 | DUK_ASSERT(tv_val != NULL); |
| 80187 | tv_obj = DUK__REGCONSTP_B(ins); |
| 80188 | tv_key = DUK__REGCONSTP_C(ins); |
| 80189 | rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT()); |
| 80190 | DUK_UNREF(rc); /* ignore */ |
| 80191 | tv_obj = NULL; /* invalidated */ |
| 80192 | tv_key = NULL; /* invalidated */ |
| 80193 | duk_pop_unsafe(thr); |
| 80194 | |
| 80195 | z = (ins & DUK_BC_INCDECP_FLAG_POST) ? x : y; |
| 80196 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 80197 | duk_push_number(thr, z); |
| 80198 | DUK__REPLACE_TOP_A_BREAK(); |
| 80199 | #else |
| 80200 | tv_dst = DUK__REGP_A(ins); |
| 80201 | DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); |
| 80202 | break; |
| 80203 | #endif |
| 80204 | } |
| 80205 | |
| 80206 | /* XXX: GETPROP where object is 'this', GETPROPT? |
| 80207 | * Occurs relatively often in object oriented code. |
| 80208 | */ |
| 80209 | |
| 80210 | #define DUK__GETPROP_BODY(barg,carg) { \ |
| 80211 | /* A -> target reg \ |
| 80212 | * B -> object reg/const (may be const e.g. in "'foo'[1]") \ |
| 80213 | * C -> key reg/const \ |
| 80214 | */ \ |
| 80215 | (void) duk_hobject_getprop(thr, (barg), (carg)); \ |
| 80216 | DUK__REPLACE_TOP_A_BREAK(); \ |
| 80217 | } |
| 80218 | #define DUK__GETPROPC_BODY(barg,carg) { \ |
| 80219 | /* Same as GETPROP but callability check for property-based calls. */ \ |
| 80220 | duk_tval *tv__targ; \ |
| 80221 | (void) duk_hobject_getprop(thr, (barg), (carg)); \ |
| 80222 | DUK_GC_TORTURE(thr->heap); \ |
| 80223 | tv__targ = DUK_GET_TVAL_NEGIDX(thr, -1); \ |
| 80224 | if (DUK_UNLIKELY(!duk_is_callable_tval(thr, tv__targ))) { \ |
| 80225 | /* Here we intentionally re-evaluate the macro \ |
| 80226 | * arguments to deal with potentially changed \ |
| 80227 | * valstack base pointer! \ |
| 80228 | */ \ |
| 80229 | duk_call_setup_propcall_error(thr, (barg), (carg)); \ |
| 80230 | } \ |
| 80231 | DUK__REPLACE_TOP_A_BREAK(); \ |
| 80232 | } |
| 80233 | #define DUK__PUTPROP_BODY(aarg,barg,carg) { \ |
| 80234 | /* A -> object reg \ |
| 80235 | * B -> key reg/const \ |
| 80236 | * C -> value reg/const \ |
| 80237 | * \ |
| 80238 | * Note: intentional difference to register arrangement \ |
| 80239 | * of e.g. GETPROP; 'A' must contain a register-only value. \ |
| 80240 | */ \ |
| 80241 | (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT()); \ |
| 80242 | break; \ |
| 80243 | } |
| 80244 | #define DUK__DELPROP_BODY(barg,carg) { \ |
| 80245 | /* A -> result reg \ |
| 80246 | * B -> object reg \ |
| 80247 | * C -> key reg/const \ |
| 80248 | */ \ |
| 80249 | duk_bool_t rc; \ |
| 80250 | rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT()); \ |
| 80251 | DUK_ASSERT(rc == 0 || rc == 1); \ |
| 80252 | DUK__REPLACE_BOOL_A_BREAK(rc); \ |
| 80253 | } |
| 80254 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 80255 | case DUK_OP_GETPROP_RR: |
| 80256 | case DUK_OP_GETPROP_CR: |
| 80257 | case DUK_OP_GETPROP_RC: |
| 80258 | case DUK_OP_GETPROP_CC: |
| 80259 | DUK__GETPROP_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 80260 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 80261 | case DUK_OP_GETPROPC_RR: |
| 80262 | case DUK_OP_GETPROPC_CR: |
| 80263 | case DUK_OP_GETPROPC_RC: |
| 80264 | case DUK_OP_GETPROPC_CC: |
| 80265 | DUK__GETPROPC_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 80266 | #endif |
| 80267 | case DUK_OP_PUTPROP_RR: |
| 80268 | case DUK_OP_PUTPROP_CR: |
| 80269 | case DUK_OP_PUTPROP_RC: |
| 80270 | case DUK_OP_PUTPROP_CC: |
| 80271 | DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins)); |
| 80272 | case DUK_OP_DELPROP_RR: |
| 80273 | case DUK_OP_DELPROP_RC: /* B is always reg */ |
| 80274 | DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGCONSTP_C(ins)); |
| 80275 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80276 | case DUK_OP_GETPROP_RR: |
| 80277 | DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 80278 | case DUK_OP_GETPROP_CR: |
| 80279 | DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 80280 | case DUK_OP_GETPROP_RC: |
| 80281 | DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 80282 | case DUK_OP_GETPROP_CC: |
| 80283 | DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 80284 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 80285 | case DUK_OP_GETPROPC_RR: |
| 80286 | DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 80287 | case DUK_OP_GETPROPC_CR: |
| 80288 | DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 80289 | case DUK_OP_GETPROPC_RC: |
| 80290 | DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 80291 | case DUK_OP_GETPROPC_CC: |
| 80292 | DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 80293 | #endif |
| 80294 | case DUK_OP_PUTPROP_RR: |
| 80295 | DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 80296 | case DUK_OP_PUTPROP_CR: |
| 80297 | DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__REGP_C(ins)); |
| 80298 | case DUK_OP_PUTPROP_RC: |
| 80299 | DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 80300 | case DUK_OP_PUTPROP_CC: |
| 80301 | DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__CONSTP_C(ins)); |
| 80302 | case DUK_OP_DELPROP_RR: /* B is always reg */ |
| 80303 | DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins)); |
| 80304 | case DUK_OP_DELPROP_RC: |
| 80305 | DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins)); |
| 80306 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80307 | |
| 80308 | /* No fast path for DECLVAR now, it's quite a rare instruction. */ |
| 80309 | case DUK_OP_DECLVAR_RR: |
| 80310 | case DUK_OP_DECLVAR_CR: |
| 80311 | case DUK_OP_DECLVAR_RC: |
| 80312 | case DUK_OP_DECLVAR_CC: { |
| 80313 | duk_activation *act; |
| 80314 | duk_small_uint_fast_t a = DUK_DEC_A(ins); |
| 80315 | duk_tval *tv1; |
| 80316 | duk_hstring *name; |
| 80317 | duk_small_uint_t prop_flags; |
| 80318 | duk_bool_t is_func_decl; |
| 80319 | |
| 80320 | tv1 = DUK__REGCONSTP_B(ins); |
| 80321 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); |
| 80322 | name = DUK_TVAL_GET_STRING(tv1); |
| 80323 | DUK_ASSERT(name != NULL); |
| 80324 | |
| 80325 | is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0); |
| 80326 | |
| 80327 | /* XXX: declvar takes an duk_tval pointer, which is awkward and |
| 80328 | * should be reworked. |
| 80329 | */ |
| 80330 | |
| 80331 | /* Compiler is responsible for selecting property flags (configurability, |
| 80332 | * writability, etc). |
| 80333 | */ |
| 80334 | prop_flags = a & DUK_PROPDESC_FLAGS_MASK; |
| 80335 | |
| 80336 | if (is_func_decl) { |
| 80337 | duk_push_tval(thr, DUK__REGCONSTP_C(ins)); |
| 80338 | } else { |
| 80339 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ |
| 80340 | thr->valstack_top++; |
| 80341 | } |
| 80342 | tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 80343 | |
| 80344 | act = thr->callstack_curr; |
| 80345 | if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) { |
| 80346 | if (is_func_decl) { |
| 80347 | /* Already declared, update value. */ |
| 80348 | tv1 = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 80349 | duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); |
| 80350 | } else { |
| 80351 | /* Already declared but no initializer value |
| 80352 | * (e.g. 'var xyz;'), no-op. |
| 80353 | */ |
| 80354 | } |
| 80355 | } |
| 80356 | |
| 80357 | duk_pop_unsafe(thr); |
| 80358 | break; |
| 80359 | } |
| 80360 | |
| 80361 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 80362 | /* The compiler should never emit DUK_OP_REGEXP if there is no |
| 80363 | * regexp support. |
| 80364 | */ |
| 80365 | case DUK_OP_REGEXP_RR: |
| 80366 | case DUK_OP_REGEXP_CR: |
| 80367 | case DUK_OP_REGEXP_RC: |
| 80368 | case DUK_OP_REGEXP_CC: { |
| 80369 | /* A -> target register |
| 80370 | * B -> bytecode (also contains flags) |
| 80371 | * C -> escaped source |
| 80372 | */ |
| 80373 | |
| 80374 | duk_push_tval(thr, DUK__REGCONSTP_C(ins)); |
| 80375 | duk_push_tval(thr, DUK__REGCONSTP_B(ins)); /* -> [ ... escaped_source bytecode ] */ |
| 80376 | duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */ |
| 80377 | DUK__REPLACE_TOP_A_BREAK(); |
| 80378 | } |
| 80379 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 80380 | |
| 80381 | /* XXX: 'c' is unused, use whole BC, etc. */ |
| 80382 | case DUK_OP_CSVAR_RR: |
| 80383 | case DUK_OP_CSVAR_CR: |
| 80384 | case DUK_OP_CSVAR_RC: |
| 80385 | case DUK_OP_CSVAR_CC: { |
| 80386 | /* The speciality of calling through a variable binding is that the |
| 80387 | * 'this' value may be provided by the variable lookup: E5 Section 6.b.i. |
| 80388 | * |
| 80389 | * The only (standard) case where the 'this' binding is non-null is when |
| 80390 | * (1) the variable is found in an object environment record, and |
| 80391 | * (2) that object environment record is a 'with' block. |
| 80392 | */ |
| 80393 | |
| 80394 | duk_activation *act; |
| 80395 | duk_uint_fast_t idx; |
| 80396 | duk_tval *tv1; |
| 80397 | duk_hstring *name; |
| 80398 | |
| 80399 | /* A -> target registers (A, A + 1) for call setup |
| 80400 | * B -> identifier name, usually constant but can be a register due to shuffling |
| 80401 | */ |
| 80402 | |
| 80403 | tv1 = DUK__REGCONSTP_B(ins); |
| 80404 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); |
| 80405 | name = DUK_TVAL_GET_STRING(tv1); |
| 80406 | DUK_ASSERT(name != NULL); |
| 80407 | act = thr->callstack_curr; |
| 80408 | (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ |
| 80409 | |
| 80410 | idx = (duk_uint_fast_t) DUK_DEC_A(ins); |
| 80411 | |
| 80412 | /* Could add direct value stack handling. */ |
| 80413 | duk_replace(thr, (duk_idx_t) (idx + 1)); /* 'this' binding */ |
| 80414 | duk_replace(thr, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */ |
| 80415 | break; |
| 80416 | } |
| 80417 | |
| 80418 | case DUK_OP_CLOSURE: { |
| 80419 | duk_activation *act; |
| 80420 | duk_hcompfunc *fun_act; |
| 80421 | duk_small_uint_fast_t bc = DUK_DEC_BC(ins); |
| 80422 | duk_hobject *fun_temp; |
| 80423 | |
| 80424 | /* A -> target reg |
| 80425 | * BC -> inner function index |
| 80426 | */ |
| 80427 | |
| 80428 | DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)" , |
| 80429 | (long) DUK_DEC_A(ins), (long) DUK_DEC_BC(ins), (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN()))); |
| 80430 | |
| 80431 | DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */ |
| 80432 | DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())); |
| 80433 | |
| 80434 | act = thr->callstack_curr; |
| 80435 | fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act); |
| 80436 | fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc]; |
| 80437 | DUK_ASSERT(fun_temp != NULL); |
| 80438 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(fun_temp)); |
| 80439 | |
| 80440 | DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O" , |
| 80441 | (void *) fun_temp, (duk_heaphdr *) fun_temp)); |
| 80442 | |
| 80443 | if (act->lex_env == NULL) { |
| 80444 | DUK_ASSERT(act->var_env == NULL); |
| 80445 | duk_js_init_activation_environment_records_delayed(thr, act); |
| 80446 | act = thr->callstack_curr; |
| 80447 | } |
| 80448 | DUK_ASSERT(act->lex_env != NULL); |
| 80449 | DUK_ASSERT(act->var_env != NULL); |
| 80450 | |
| 80451 | /* functions always have a NEWENV flag, i.e. they get a |
| 80452 | * new variable declaration environment, so only lex_env |
| 80453 | * matters here. |
| 80454 | */ |
| 80455 | duk_js_push_closure(thr, |
| 80456 | (duk_hcompfunc *) fun_temp, |
| 80457 | act->var_env, |
| 80458 | act->lex_env, |
| 80459 | 1 /*add_auto_proto*/); |
| 80460 | DUK__REPLACE_TOP_A_BREAK(); |
| 80461 | } |
| 80462 | |
| 80463 | case DUK_OP_GETVAR: { |
| 80464 | duk_activation *act; |
| 80465 | duk_tval *tv1; |
| 80466 | duk_hstring *name; |
| 80467 | |
| 80468 | tv1 = DUK__CONSTP_BC(ins); |
| 80469 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); |
| 80470 | name = DUK_TVAL_GET_STRING(tv1); |
| 80471 | DUK_ASSERT(name != NULL); |
| 80472 | act = thr->callstack_curr; |
| 80473 | DUK_ASSERT(act != NULL); |
| 80474 | (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */ |
| 80475 | duk_pop_unsafe(thr); /* 'this' binding is not needed here */ |
| 80476 | DUK__REPLACE_TOP_A_BREAK(); |
| 80477 | } |
| 80478 | |
| 80479 | case DUK_OP_PUTVAR: { |
| 80480 | duk_activation *act; |
| 80481 | duk_tval *tv1; |
| 80482 | duk_hstring *name; |
| 80483 | |
| 80484 | tv1 = DUK__CONSTP_BC(ins); |
| 80485 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); |
| 80486 | name = DUK_TVAL_GET_STRING(tv1); |
| 80487 | DUK_ASSERT(name != NULL); |
| 80488 | |
| 80489 | /* XXX: putvar takes a duk_tval pointer, which is awkward and |
| 80490 | * should be reworked. |
| 80491 | */ |
| 80492 | |
| 80493 | tv1 = DUK__REGP_A(ins); /* val */ |
| 80494 | act = thr->callstack_curr; |
| 80495 | duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT()); |
| 80496 | break; |
| 80497 | } |
| 80498 | |
| 80499 | case DUK_OP_DELVAR: { |
| 80500 | duk_activation *act; |
| 80501 | duk_tval *tv1; |
| 80502 | duk_hstring *name; |
| 80503 | duk_bool_t rc; |
| 80504 | |
| 80505 | tv1 = DUK__CONSTP_BC(ins); |
| 80506 | DUK_ASSERT(DUK_TVAL_IS_STRING(tv1)); |
| 80507 | name = DUK_TVAL_GET_STRING(tv1); |
| 80508 | DUK_ASSERT(name != NULL); |
| 80509 | act = thr->callstack_curr; |
| 80510 | rc = duk_js_delvar_activation(thr, act, name); |
| 80511 | DUK__REPLACE_BOOL_A_BREAK(rc); |
| 80512 | } |
| 80513 | |
| 80514 | case DUK_OP_JUMP: { |
| 80515 | /* Note: without explicit cast to signed, MSVC will |
| 80516 | * apparently generate a large positive jump when the |
| 80517 | * bias-corrected value would normally be negative. |
| 80518 | */ |
| 80519 | curr_pc += (duk_int_fast_t) DUK_DEC_ABC(ins) - (duk_int_fast_t) DUK_BC_JUMP_BIAS; |
| 80520 | break; |
| 80521 | } |
| 80522 | |
| 80523 | #define DUK__RETURN_SHARED() do { \ |
| 80524 | duk_small_uint_t ret_result; \ |
| 80525 | /* duk__handle_return() is guaranteed never to throw, except \ |
| 80526 | * for potential out-of-memory situations which will then \ |
| 80527 | * propagate out of the executor longjmp handler. \ |
| 80528 | */ \ |
| 80529 | DUK_ASSERT(thr->ptr_curr_pc == NULL); \ |
| 80530 | ret_result = duk__handle_return(thr, entry_act); \ |
| 80531 | if (ret_result == DUK__RETHAND_RESTART) { \ |
| 80532 | goto restart_execution; \ |
| 80533 | } \ |
| 80534 | DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); \ |
| 80535 | return; \ |
| 80536 | } while (0) |
| 80537 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 80538 | case DUK_OP_RETREG: |
| 80539 | case DUK_OP_RETCONST: |
| 80540 | case DUK_OP_RETCONSTN: |
| 80541 | case DUK_OP_RETUNDEF: { |
| 80542 | /* BC -> return value reg/const */ |
| 80543 | |
| 80544 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80545 | |
| 80546 | if (op == DUK_OP_RETREG) { |
| 80547 | duk_push_tval(thr, DUK__REGP_BC(ins)); |
| 80548 | } else if (op == DUK_OP_RETUNDEF) { |
| 80549 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */ |
| 80550 | thr->valstack_top++; |
| 80551 | } else { |
| 80552 | DUK_ASSERT(op == DUK_OP_RETCONST || op == DUK_OP_RETCONSTN); |
| 80553 | duk_push_tval(thr, DUK__CONSTP_BC(ins)); |
| 80554 | } |
| 80555 | |
| 80556 | DUK__RETURN_SHARED(); |
| 80557 | } |
| 80558 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80559 | case DUK_OP_RETREG: { |
| 80560 | duk_tval *tv; |
| 80561 | |
| 80562 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80563 | tv = DUK__REGP_BC(ins); |
| 80564 | DUK_TVAL_SET_TVAL(thr->valstack_top, tv); |
| 80565 | DUK_TVAL_INCREF(thr, tv); |
| 80566 | thr->valstack_top++; |
| 80567 | DUK__RETURN_SHARED(); |
| 80568 | } |
| 80569 | /* This will be unused without refcounting. */ |
| 80570 | case DUK_OP_RETCONST: { |
| 80571 | duk_tval *tv; |
| 80572 | |
| 80573 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80574 | tv = DUK__CONSTP_BC(ins); |
| 80575 | DUK_TVAL_SET_TVAL(thr->valstack_top, tv); |
| 80576 | DUK_TVAL_INCREF(thr, tv); |
| 80577 | thr->valstack_top++; |
| 80578 | DUK__RETURN_SHARED(); |
| 80579 | } |
| 80580 | case DUK_OP_RETCONSTN: { |
| 80581 | duk_tval *tv; |
| 80582 | |
| 80583 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80584 | tv = DUK__CONSTP_BC(ins); |
| 80585 | DUK_TVAL_SET_TVAL(thr->valstack_top, tv); |
| 80586 | #if defined(DUK_USE_REFERENCE_COUNTING) |
| 80587 | /* Without refcounting only RETCONSTN is used. */ |
| 80588 | DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */ |
| 80589 | #endif |
| 80590 | thr->valstack_top++; |
| 80591 | DUK__RETURN_SHARED(); |
| 80592 | } |
| 80593 | case DUK_OP_RETUNDEF: { |
| 80594 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80595 | thr->valstack_top++; /* value at valstack top is already undefined by valstack policy */ |
| 80596 | DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); |
| 80597 | DUK__RETURN_SHARED(); |
| 80598 | } |
| 80599 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 80600 | |
| 80601 | case DUK_OP_LABEL: { |
| 80602 | duk_activation *act; |
| 80603 | duk_catcher *cat; |
| 80604 | duk_small_uint_fast_t bc = DUK_DEC_BC(ins); |
| 80605 | |
| 80606 | /* Allocate catcher and populate it (must be atomic). */ |
| 80607 | |
| 80608 | cat = duk_hthread_catcher_alloc(thr); |
| 80609 | DUK_ASSERT(cat != NULL); |
| 80610 | |
| 80611 | cat->flags = (duk_uint32_t) (DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT)); |
| 80612 | cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */ |
| 80613 | cat->idx_base = 0; /* unused for label */ |
| 80614 | cat->h_varname = NULL; |
| 80615 | |
| 80616 | act = thr->callstack_curr; |
| 80617 | DUK_ASSERT(act != NULL); |
| 80618 | cat->parent = act->cat; |
| 80619 | act->cat = cat; |
| 80620 | |
| 80621 | DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, pc_base=%ld, " |
| 80622 | "idx_base=%ld, h_varname=%!O, label_id=%ld" , |
| 80623 | (long) cat->flags, (long) cat->pc_base, |
| 80624 | (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat))); |
| 80625 | |
| 80626 | curr_pc += 2; /* skip jump slots */ |
| 80627 | break; |
| 80628 | } |
| 80629 | |
| 80630 | case DUK_OP_ENDLABEL: { |
| 80631 | duk_activation *act; |
| 80632 | #if (defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)) || defined(DUK_USE_ASSERTIONS) |
| 80633 | duk_small_uint_fast_t bc = DUK_DEC_BC(ins); |
| 80634 | #endif |
| 80635 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 80636 | DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld" , (long) bc)); |
| 80637 | #endif |
| 80638 | |
| 80639 | act = thr->callstack_curr; |
| 80640 | DUK_ASSERT(act->cat != NULL); |
| 80641 | DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_LABEL); |
| 80642 | DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(act->cat) == bc); |
| 80643 | duk_hthread_catcher_unwind_nolexenv_norz(thr, act); |
| 80644 | |
| 80645 | /* no need to unwind callstack */ |
| 80646 | break; |
| 80647 | } |
| 80648 | |
| 80649 | case DUK_OP_BREAK: { |
| 80650 | duk_small_uint_fast_t bc = DUK_DEC_BC(ins); |
| 80651 | |
| 80652 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80653 | duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK); |
| 80654 | goto restart_execution; |
| 80655 | } |
| 80656 | |
| 80657 | case DUK_OP_CONTINUE: { |
| 80658 | duk_small_uint_fast_t bc = DUK_DEC_BC(ins); |
| 80659 | |
| 80660 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80661 | duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE); |
| 80662 | goto restart_execution; |
| 80663 | } |
| 80664 | |
| 80665 | /* XXX: move to helper, too large to be inline here */ |
| 80666 | case DUK_OP_TRYCATCH: { |
| 80667 | duk__handle_op_trycatch(thr, ins, curr_pc); |
| 80668 | curr_pc += 2; /* skip jump slots */ |
| 80669 | break; |
| 80670 | } |
| 80671 | |
| 80672 | case DUK_OP_ENDTRY: { |
| 80673 | curr_pc = duk__handle_op_endtry(thr, ins); |
| 80674 | break; |
| 80675 | } |
| 80676 | |
| 80677 | case DUK_OP_ENDCATCH: { |
| 80678 | duk__handle_op_endcatch(thr, ins); |
| 80679 | break; |
| 80680 | } |
| 80681 | |
| 80682 | case DUK_OP_ENDFIN: { |
| 80683 | /* Sync and NULL early. */ |
| 80684 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80685 | |
| 80686 | if (duk__handle_op_endfin(thr, ins, entry_act) != 0) { |
| 80687 | return; |
| 80688 | } |
| 80689 | |
| 80690 | /* Must restart because we NULLed out curr_pc. */ |
| 80691 | goto restart_execution; |
| 80692 | } |
| 80693 | |
| 80694 | case DUK_OP_THROW: { |
| 80695 | duk_small_uint_fast_t bc = DUK_DEC_BC(ins); |
| 80696 | |
| 80697 | /* Note: errors are augmented when they are created, not |
| 80698 | * when they are thrown. So, don't augment here, it would |
| 80699 | * break re-throwing for instance. |
| 80700 | */ |
| 80701 | |
| 80702 | /* Sync so that augmentation sees up-to-date activations, NULL |
| 80703 | * thr->ptr_curr_pc so that it's not used if side effects occur |
| 80704 | * in augmentation or longjmp handling. |
| 80705 | */ |
| 80706 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 80707 | |
| 80708 | duk_dup(thr, (duk_idx_t) bc); |
| 80709 | DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)" , |
| 80710 | (duk_tval *) duk_get_tval(thr, -1))); |
| 80711 | #if defined(DUK_USE_AUGMENT_ERROR_THROW) |
| 80712 | duk_err_augment_error_throw(thr); |
| 80713 | DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)" , |
| 80714 | (duk_tval *) duk_get_tval(thr, -1))); |
| 80715 | #endif |
| 80716 | |
| 80717 | duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1)); |
| 80718 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 80719 | duk_err_check_debugger_integration(thr); |
| 80720 | #endif |
| 80721 | |
| 80722 | DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */ |
| 80723 | duk_err_longjmp(thr); |
| 80724 | DUK_UNREACHABLE(); |
| 80725 | break; |
| 80726 | } |
| 80727 | |
| 80728 | case DUK_OP_CSREG: { |
| 80729 | /* |
| 80730 | * Assuming a register binds to a variable declared within this |
| 80731 | * function (a declarative binding), the 'this' for the call |
| 80732 | * setup is always 'undefined'. E5 Section 10.2.1.1.6. |
| 80733 | */ |
| 80734 | |
| 80735 | duk_small_uint_fast_t a = DUK_DEC_A(ins); |
| 80736 | duk_small_uint_fast_t bc = DUK_DEC_BC(ins); |
| 80737 | |
| 80738 | /* A -> register containing target function (not type checked here) |
| 80739 | * BC -> target registers (BC, BC + 1) for call setup |
| 80740 | */ |
| 80741 | |
| 80742 | #if defined(DUK_USE_PREFER_SIZE) |
| 80743 | duk_dup(thr, (duk_idx_t) a); |
| 80744 | duk_replace(thr, (duk_idx_t) bc); |
| 80745 | duk_to_undefined(thr, (duk_idx_t) (bc + 1)); |
| 80746 | #else |
| 80747 | duk_tval *tv1; |
| 80748 | duk_tval *tv2; |
| 80749 | duk_tval *tv3; |
| 80750 | duk_tval tv_tmp1; |
| 80751 | duk_tval tv_tmp2; |
| 80752 | |
| 80753 | tv1 = DUK__REGP(bc); |
| 80754 | tv2 = tv1 + 1; |
| 80755 | DUK_TVAL_SET_TVAL(&tv_tmp1, tv1); |
| 80756 | DUK_TVAL_SET_TVAL(&tv_tmp2, tv2); |
| 80757 | tv3 = DUK__REGP(a); |
| 80758 | DUK_TVAL_SET_TVAL(tv1, tv3); |
| 80759 | DUK_TVAL_INCREF(thr, tv1); /* no side effects */ |
| 80760 | DUK_TVAL_SET_UNDEFINED(tv2); /* no need for incref */ |
| 80761 | DUK_TVAL_DECREF(thr, &tv_tmp1); |
| 80762 | DUK_TVAL_DECREF(thr, &tv_tmp2); |
| 80763 | #endif |
| 80764 | break; |
| 80765 | } |
| 80766 | |
| 80767 | |
| 80768 | /* XXX: in some cases it's faster NOT to reuse the value |
| 80769 | * stack but rather copy the arguments on top of the stack |
| 80770 | * (mainly when the calling value stack is large and the value |
| 80771 | * stack resize would be large). |
| 80772 | */ |
| 80773 | |
| 80774 | case DUK_OP_CALL0: |
| 80775 | case DUK_OP_CALL1: |
| 80776 | case DUK_OP_CALL2: |
| 80777 | case DUK_OP_CALL3: |
| 80778 | case DUK_OP_CALL4: |
| 80779 | case DUK_OP_CALL5: |
| 80780 | case DUK_OP_CALL6: |
| 80781 | case DUK_OP_CALL7: { |
| 80782 | /* Opcode packs 4 flag bits: 1 for indirect, 3 map |
| 80783 | * 1:1 to three lowest call handling flags. |
| 80784 | * |
| 80785 | * A -> nargs or register with nargs (indirect) |
| 80786 | * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN) |
| 80787 | */ |
| 80788 | |
| 80789 | duk_idx_t nargs; |
| 80790 | duk_idx_t idx; |
| 80791 | duk_small_uint_t call_flags; |
| 80792 | #if !defined(DUK_USE_EXEC_FUN_LOCAL) |
| 80793 | duk_hcompfunc *fun; |
| 80794 | #endif |
| 80795 | |
| 80796 | DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0); |
| 80797 | DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) == 0); |
| 80798 | |
| 80799 | nargs = (duk_idx_t) DUK_DEC_A(ins); |
| 80800 | call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA; |
| 80801 | idx = (duk_idx_t) DUK_DEC_BC(ins); |
| 80802 | |
| 80803 | if (duk__executor_handle_call(thr, idx, nargs, call_flags)) { |
| 80804 | /* curr_pc synced by duk_handle_call_unprotected() */ |
| 80805 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 80806 | goto restart_execution; |
| 80807 | } |
| 80808 | DUK_ASSERT(thr->ptr_curr_pc != NULL); |
| 80809 | |
| 80810 | /* duk_js_call.c is required to restore the stack reserve |
| 80811 | * so we only need to reset the top. |
| 80812 | */ |
| 80813 | #if !defined(DUK_USE_EXEC_FUN_LOCAL) |
| 80814 | fun = DUK__FUN(); |
| 80815 | #endif |
| 80816 | duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs); |
| 80817 | |
| 80818 | /* No need to reinit setjmp() catchpoint, as call handling |
| 80819 | * will store and restore our state. |
| 80820 | * |
| 80821 | * When debugger is enabled, we need to recheck the activation |
| 80822 | * status after returning. This is now handled by call handling |
| 80823 | * and heap->dbg_force_restart. |
| 80824 | */ |
| 80825 | break; |
| 80826 | } |
| 80827 | |
| 80828 | case DUK_OP_CALL8: |
| 80829 | case DUK_OP_CALL9: |
| 80830 | case DUK_OP_CALL10: |
| 80831 | case DUK_OP_CALL11: |
| 80832 | case DUK_OP_CALL12: |
| 80833 | case DUK_OP_CALL13: |
| 80834 | case DUK_OP_CALL14: |
| 80835 | case DUK_OP_CALL15: { |
| 80836 | /* Indirect variant. */ |
| 80837 | duk_uint_fast_t nargs; |
| 80838 | duk_idx_t idx; |
| 80839 | duk_small_uint_t call_flags; |
| 80840 | #if !defined(DUK_USE_EXEC_FUN_LOCAL) |
| 80841 | duk_hcompfunc *fun; |
| 80842 | #endif |
| 80843 | |
| 80844 | DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0); |
| 80845 | DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) != 0); |
| 80846 | |
| 80847 | nargs = (duk_uint_fast_t) DUK_DEC_A(ins); |
| 80848 | DUK__LOOKUP_INDIRECT(nargs); |
| 80849 | call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA; |
| 80850 | idx = (duk_idx_t) DUK_DEC_BC(ins); |
| 80851 | |
| 80852 | if (duk__executor_handle_call(thr, idx, (duk_idx_t) nargs, call_flags)) { |
| 80853 | DUK_ASSERT(thr->ptr_curr_pc == NULL); |
| 80854 | goto restart_execution; |
| 80855 | } |
| 80856 | DUK_ASSERT(thr->ptr_curr_pc != NULL); |
| 80857 | |
| 80858 | #if !defined(DUK_USE_EXEC_FUN_LOCAL) |
| 80859 | fun = DUK__FUN(); |
| 80860 | #endif |
| 80861 | duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs); |
| 80862 | break; |
| 80863 | } |
| 80864 | |
| 80865 | case DUK_OP_NEWOBJ: { |
| 80866 | duk_push_object(thr); |
| 80867 | #if defined(DUK_USE_ASSERTIONS) |
| 80868 | { |
| 80869 | duk_hobject *h; |
| 80870 | h = duk_require_hobject(thr, -1); |
| 80871 | DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0); |
| 80872 | DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0); |
| 80873 | DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0); |
| 80874 | DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0); |
| 80875 | } |
| 80876 | #endif |
| 80877 | #if !defined(DUK_USE_PREFER_SIZE) |
| 80878 | /* XXX: could do a direct props realloc, but need hash size */ |
| 80879 | duk_hobject_resize_entrypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins)); |
| 80880 | #endif |
| 80881 | DUK__REPLACE_TOP_BC_BREAK(); |
| 80882 | } |
| 80883 | |
| 80884 | case DUK_OP_NEWARR: { |
| 80885 | duk_push_array(thr); |
| 80886 | #if defined(DUK_USE_ASSERTIONS) |
| 80887 | { |
| 80888 | duk_hobject *h; |
| 80889 | h = duk_require_hobject(thr, -1); |
| 80890 | DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0); |
| 80891 | DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0); |
| 80892 | DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0); |
| 80893 | DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0); |
| 80894 | DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(h)); |
| 80895 | } |
| 80896 | #endif |
| 80897 | #if !defined(DUK_USE_PREFER_SIZE) |
| 80898 | duk_hobject_realloc_props(thr, |
| 80899 | duk_known_hobject(thr, -1), |
| 80900 | 0 /*new_e_size*/, |
| 80901 | DUK_DEC_A(ins) /*new_a_size*/, |
| 80902 | 0 /*new_h_size*/, |
| 80903 | 0 /*abandon_array*/); |
| 80904 | #if 0 |
| 80905 | duk_hobject_resize_arraypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins)); |
| 80906 | #endif |
| 80907 | #endif |
| 80908 | DUK__REPLACE_TOP_BC_BREAK(); |
| 80909 | } |
| 80910 | |
| 80911 | case DUK_OP_MPUTOBJ: |
| 80912 | case DUK_OP_MPUTOBJI: { |
| 80913 | duk_idx_t obj_idx; |
| 80914 | duk_uint_fast_t idx, idx_end; |
| 80915 | duk_small_uint_fast_t count; |
| 80916 | |
| 80917 | /* A -> register of target object |
| 80918 | * B -> first register of key/value pair list |
| 80919 | * or register containing first register number if indirect |
| 80920 | * C -> number of key/value pairs * 2 |
| 80921 | * (= number of value stack indices used starting from 'B') |
| 80922 | */ |
| 80923 | |
| 80924 | obj_idx = DUK_DEC_A(ins); |
| 80925 | DUK_ASSERT(duk_is_object(thr, obj_idx)); |
| 80926 | |
| 80927 | idx = (duk_uint_fast_t) DUK_DEC_B(ins); |
| 80928 | if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) { |
| 80929 | DUK__LOOKUP_INDIRECT(idx); |
| 80930 | } |
| 80931 | |
| 80932 | count = (duk_small_uint_fast_t) DUK_DEC_C(ins); |
| 80933 | DUK_ASSERT(count > 0); /* compiler guarantees */ |
| 80934 | idx_end = idx + count; |
| 80935 | |
| 80936 | #if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK) |
| 80937 | if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(thr))) { |
| 80938 | /* XXX: use duk_is_valid_index() instead? */ |
| 80939 | /* XXX: improve check; check against nregs, not against top */ |
| 80940 | DUK__INTERNAL_ERROR("MPUTOBJ out of bounds" ); |
| 80941 | } |
| 80942 | #endif |
| 80943 | |
| 80944 | /* Use 'force' flag to duk_def_prop() to ensure that any |
| 80945 | * inherited properties don't prevent the operation. |
| 80946 | * With ES2015 duplicate properties are allowed, so that we |
| 80947 | * must overwrite any previous data or accessor property. |
| 80948 | * |
| 80949 | * With ES2015 computed property names the literal keys |
| 80950 | * may be arbitrary values and need to be ToPropertyKey() |
| 80951 | * coerced at runtime. |
| 80952 | */ |
| 80953 | do { |
| 80954 | /* XXX: faster initialization (direct access or better primitives) */ |
| 80955 | duk_dup(thr, (duk_idx_t) idx); |
| 80956 | duk_dup(thr, (duk_idx_t) (idx + 1)); |
| 80957 | duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_VALUE | |
| 80958 | DUK_DEFPROP_FORCE | |
| 80959 | DUK_DEFPROP_SET_WRITABLE | |
| 80960 | DUK_DEFPROP_SET_ENUMERABLE | |
| 80961 | DUK_DEFPROP_SET_CONFIGURABLE); |
| 80962 | idx += 2; |
| 80963 | } while (idx < idx_end); |
| 80964 | break; |
| 80965 | } |
| 80966 | |
| 80967 | case DUK_OP_INITSET: |
| 80968 | case DUK_OP_INITGET: { |
| 80969 | duk__handle_op_initset_initget(thr, ins); |
| 80970 | break; |
| 80971 | } |
| 80972 | |
| 80973 | case DUK_OP_MPUTARR: |
| 80974 | case DUK_OP_MPUTARRI: { |
| 80975 | duk_idx_t obj_idx; |
| 80976 | duk_uint_fast_t idx, idx_end; |
| 80977 | duk_small_uint_fast_t count; |
| 80978 | duk_tval *tv1; |
| 80979 | duk_uint32_t arr_idx; |
| 80980 | |
| 80981 | /* A -> register of target object |
| 80982 | * B -> first register of value data (start_index, value1, value2, ..., valueN) |
| 80983 | * or register containing first register number if indirect |
| 80984 | * C -> number of key/value pairs (N) |
| 80985 | */ |
| 80986 | |
| 80987 | obj_idx = DUK_DEC_A(ins); |
| 80988 | DUK_ASSERT(duk_is_object(thr, obj_idx)); |
| 80989 | |
| 80990 | idx = (duk_uint_fast_t) DUK_DEC_B(ins); |
| 80991 | if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) { |
| 80992 | DUK__LOOKUP_INDIRECT(idx); |
| 80993 | } |
| 80994 | |
| 80995 | count = (duk_small_uint_fast_t) DUK_DEC_C(ins); |
| 80996 | DUK_ASSERT(count > 0 + 1); /* compiler guarantees */ |
| 80997 | idx_end = idx + count; |
| 80998 | |
| 80999 | #if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK) |
| 81000 | if (idx_end > (duk_uint_fast_t) duk_get_top(thr)) { |
| 81001 | /* XXX: use duk_is_valid_index() instead? */ |
| 81002 | /* XXX: improve check; check against nregs, not against top */ |
| 81003 | DUK__INTERNAL_ERROR("MPUTARR out of bounds" ); |
| 81004 | } |
| 81005 | #endif |
| 81006 | |
| 81007 | tv1 = DUK__REGP(idx); |
| 81008 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); |
| 81009 | #if defined(DUK_USE_FASTINT) |
| 81010 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); |
| 81011 | arr_idx = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1); |
| 81012 | #else |
| 81013 | arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1); |
| 81014 | #endif |
| 81015 | idx++; |
| 81016 | |
| 81017 | do { |
| 81018 | /* duk_xdef_prop() will define an own property without any array |
| 81019 | * special behaviors. We'll need to set the array length explicitly |
| 81020 | * in the end. For arrays with elisions, the compiler will emit an |
| 81021 | * explicit SETALEN which will update the length. |
| 81022 | */ |
| 81023 | |
| 81024 | /* XXX: because we're dealing with 'own' properties of a fresh array, |
| 81025 | * the array initializer should just ensure that the array has a large |
| 81026 | * enough array part and write the values directly into array part, |
| 81027 | * and finally set 'length' manually in the end (as already happens now). |
| 81028 | */ |
| 81029 | |
| 81030 | duk_dup(thr, (duk_idx_t) idx); |
| 81031 | duk_xdef_prop_index_wec(thr, obj_idx, arr_idx); |
| 81032 | |
| 81033 | idx++; |
| 81034 | arr_idx++; |
| 81035 | } while (idx < idx_end); |
| 81036 | |
| 81037 | /* XXX: E5.1 Section 11.1.4 coerces the final length through |
| 81038 | * ToUint32() which is odd but happens now as a side effect of |
| 81039 | * 'arr_idx' type. |
| 81040 | */ |
| 81041 | duk_set_length(thr, obj_idx, (duk_size_t) (duk_uarridx_t) arr_idx); |
| 81042 | break; |
| 81043 | } |
| 81044 | |
| 81045 | case DUK_OP_SETALEN: { |
| 81046 | duk_tval *tv1; |
| 81047 | duk_hobject *h; |
| 81048 | duk_uint32_t len; |
| 81049 | |
| 81050 | tv1 = DUK__REGP_A(ins); |
| 81051 | DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1)); |
| 81052 | h = DUK_TVAL_GET_OBJECT(tv1); |
| 81053 | DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(h)); |
| 81054 | |
| 81055 | tv1 = DUK__REGP_BC(ins); |
| 81056 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1)); |
| 81057 | #if defined(DUK_USE_FASTINT) |
| 81058 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1)); |
| 81059 | len = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1); |
| 81060 | #else |
| 81061 | len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1); |
| 81062 | #endif |
| 81063 | ((duk_harray *) h)->length = len; |
| 81064 | break; |
| 81065 | } |
| 81066 | |
| 81067 | case DUK_OP_INITENUM: { |
| 81068 | duk__handle_op_initenum(thr, ins); |
| 81069 | break; |
| 81070 | } |
| 81071 | |
| 81072 | case DUK_OP_NEXTENUM: { |
| 81073 | curr_pc += duk__handle_op_nextenum(thr, ins); |
| 81074 | break; |
| 81075 | } |
| 81076 | |
| 81077 | case DUK_OP_INVLHS: { |
| 81078 | DUK_ERROR_REFERENCE(thr, DUK_STR_INVALID_LVALUE); |
| 81079 | DUK_WO_NORETURN(return;); |
| 81080 | break; |
| 81081 | } |
| 81082 | |
| 81083 | case DUK_OP_DEBUGGER: { |
| 81084 | /* Opcode only emitted by compiler when debugger |
| 81085 | * support is enabled. Ignore it silently without |
| 81086 | * debugger support, in case it has been loaded |
| 81087 | * from precompiled bytecode. |
| 81088 | */ |
| 81089 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 81090 | if (duk_debug_is_attached(thr->heap)) { |
| 81091 | DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution" )); |
| 81092 | DUK__SYNC_AND_NULL_CURR_PC(); |
| 81093 | duk_debug_halt_execution(thr, 1 /*use_prev_pc*/); |
| 81094 | DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution" )); |
| 81095 | goto restart_execution; |
| 81096 | } else { |
| 81097 | DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached" )); |
| 81098 | } |
| 81099 | #else |
| 81100 | DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support" )); |
| 81101 | #endif |
| 81102 | break; |
| 81103 | } |
| 81104 | |
| 81105 | case DUK_OP_NOP: { |
| 81106 | /* Nop, ignored, but ABC fields may carry a value e.g. |
| 81107 | * for indirect opcode handling. |
| 81108 | */ |
| 81109 | break; |
| 81110 | } |
| 81111 | |
| 81112 | case DUK_OP_INVALID: { |
| 81113 | DUK_ERROR_FMT1(thr, DUK_ERR_ERROR, "INVALID opcode (%ld)" , (long) DUK_DEC_ABC(ins)); |
| 81114 | DUK_WO_NORETURN(return;); |
| 81115 | break; |
| 81116 | } |
| 81117 | |
| 81118 | #if defined(DUK_USE_ES6) |
| 81119 | case DUK_OP_NEWTARGET: { |
| 81120 | duk_push_new_target(thr); |
| 81121 | DUK__REPLACE_TOP_BC_BREAK(); |
| 81122 | } |
| 81123 | #endif /* DUK_USE_ES6 */ |
| 81124 | |
| 81125 | #if !defined(DUK_USE_EXEC_PREFER_SIZE) |
| 81126 | #if !defined(DUK_USE_ES7_EXP_OPERATOR) |
| 81127 | case DUK_OP_EXP_RR: |
| 81128 | case DUK_OP_EXP_CR: |
| 81129 | case DUK_OP_EXP_RC: |
| 81130 | case DUK_OP_EXP_CC: |
| 81131 | #endif |
| 81132 | #if !defined(DUK_USE_ES6) |
| 81133 | case DUK_OP_NEWTARGET: |
| 81134 | #endif |
| 81135 | #if !defined(DUK_USE_VERBOSE_ERRORS) |
| 81136 | case DUK_OP_GETPROPC_RR: |
| 81137 | case DUK_OP_GETPROPC_CR: |
| 81138 | case DUK_OP_GETPROPC_RC: |
| 81139 | case DUK_OP_GETPROPC_CC: |
| 81140 | #endif |
| 81141 | case DUK_OP_UNUSED207: |
| 81142 | case DUK_OP_UNUSED212: |
| 81143 | case DUK_OP_UNUSED213: |
| 81144 | case DUK_OP_UNUSED214: |
| 81145 | case DUK_OP_UNUSED215: |
| 81146 | case DUK_OP_UNUSED216: |
| 81147 | case DUK_OP_UNUSED217: |
| 81148 | case DUK_OP_UNUSED218: |
| 81149 | case DUK_OP_UNUSED219: |
| 81150 | case DUK_OP_UNUSED220: |
| 81151 | case DUK_OP_UNUSED221: |
| 81152 | case DUK_OP_UNUSED222: |
| 81153 | case DUK_OP_UNUSED223: |
| 81154 | case DUK_OP_UNUSED224: |
| 81155 | case DUK_OP_UNUSED225: |
| 81156 | case DUK_OP_UNUSED226: |
| 81157 | case DUK_OP_UNUSED227: |
| 81158 | case DUK_OP_UNUSED228: |
| 81159 | case DUK_OP_UNUSED229: |
| 81160 | case DUK_OP_UNUSED230: |
| 81161 | case DUK_OP_UNUSED231: |
| 81162 | case DUK_OP_UNUSED232: |
| 81163 | case DUK_OP_UNUSED233: |
| 81164 | case DUK_OP_UNUSED234: |
| 81165 | case DUK_OP_UNUSED235: |
| 81166 | case DUK_OP_UNUSED236: |
| 81167 | case DUK_OP_UNUSED237: |
| 81168 | case DUK_OP_UNUSED238: |
| 81169 | case DUK_OP_UNUSED239: |
| 81170 | case DUK_OP_UNUSED240: |
| 81171 | case DUK_OP_UNUSED241: |
| 81172 | case DUK_OP_UNUSED242: |
| 81173 | case DUK_OP_UNUSED243: |
| 81174 | case DUK_OP_UNUSED244: |
| 81175 | case DUK_OP_UNUSED245: |
| 81176 | case DUK_OP_UNUSED246: |
| 81177 | case DUK_OP_UNUSED247: |
| 81178 | case DUK_OP_UNUSED248: |
| 81179 | case DUK_OP_UNUSED249: |
| 81180 | case DUK_OP_UNUSED250: |
| 81181 | case DUK_OP_UNUSED251: |
| 81182 | case DUK_OP_UNUSED252: |
| 81183 | case DUK_OP_UNUSED253: |
| 81184 | case DUK_OP_UNUSED254: |
| 81185 | case DUK_OP_UNUSED255: |
| 81186 | /* Force all case clauses to map to an actual handler |
| 81187 | * so that the compiler can emit a jump without a bounds |
| 81188 | * check: the switch argument is a duk_uint8_t so that |
| 81189 | * the compiler may be able to figure it out. This is |
| 81190 | * a small detail and obviously compiler dependent. |
| 81191 | */ |
| 81192 | /* default: clause omitted on purpose */ |
| 81193 | #else /* DUK_USE_EXEC_PREFER_SIZE */ |
| 81194 | default: |
| 81195 | #endif /* DUK_USE_EXEC_PREFER_SIZE */ |
| 81196 | { |
| 81197 | /* Default case catches invalid/unsupported opcodes. */ |
| 81198 | DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I" , (long) op, ins)); |
| 81199 | DUK__INTERNAL_ERROR("invalid opcode" ); |
| 81200 | break; |
| 81201 | } |
| 81202 | |
| 81203 | } /* end switch */ |
| 81204 | |
| 81205 | continue; |
| 81206 | |
| 81207 | /* Some shared exit paths for opcode handling below. These |
| 81208 | * are mostly useful to reduce code footprint when multiple |
| 81209 | * opcodes have a similar epilogue (like replacing stack top |
| 81210 | * with index 'a'). |
| 81211 | */ |
| 81212 | |
| 81213 | #if defined(DUK_USE_EXEC_PREFER_SIZE) |
| 81214 | replace_top_a: |
| 81215 | DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); |
| 81216 | continue; |
| 81217 | replace_top_bc: |
| 81218 | DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); |
| 81219 | continue; |
| 81220 | #endif |
| 81221 | } |
| 81222 | DUK_WO_NORETURN(return;); |
| 81223 | |
| 81224 | #if !defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS) |
| 81225 | internal_error: |
| 81226 | DUK_ERROR_INTERNAL(thr); |
| 81227 | DUK_WO_NORETURN(return;); |
| 81228 | #endif |
| 81229 | } |
| 81230 | |
| 81231 | /* automatic undefs */ |
| 81232 | #undef DUK__BYTEOFF_A |
| 81233 | #undef DUK__BYTEOFF_B |
| 81234 | #undef DUK__BYTEOFF_BC |
| 81235 | #undef DUK__BYTEOFF_C |
| 81236 | #undef DUK__COMPARE_BODY |
| 81237 | #undef DUK__CONST |
| 81238 | #undef DUK__CONSTP |
| 81239 | #undef DUK__CONSTP_A |
| 81240 | #undef DUK__CONSTP_B |
| 81241 | #undef DUK__CONSTP_BC |
| 81242 | #undef DUK__CONSTP_C |
| 81243 | #undef DUK__DELPROP_BODY |
| 81244 | #undef DUK__EQ_BODY |
| 81245 | #undef DUK__FUN |
| 81246 | #undef DUK__GETPROPC_BODY |
| 81247 | #undef DUK__GETPROP_BODY |
| 81248 | #undef DUK__GE_BODY |
| 81249 | #undef DUK__GT_BODY |
| 81250 | #undef DUK__INSTOF_BODY |
| 81251 | #undef DUK__INTERNAL_ERROR |
| 81252 | #undef DUK__INT_NOACTION |
| 81253 | #undef DUK__INT_RESTART |
| 81254 | #undef DUK__IN_BODY |
| 81255 | #undef DUK__LE_BODY |
| 81256 | #undef DUK__LONGJMP_RESTART |
| 81257 | #undef DUK__LONGJMP_RETHROW |
| 81258 | #undef DUK__LOOKUP_INDIRECT |
| 81259 | #undef DUK__LT_BODY |
| 81260 | #undef DUK__MASK_A |
| 81261 | #undef DUK__MASK_B |
| 81262 | #undef DUK__MASK_BC |
| 81263 | #undef DUK__MASK_C |
| 81264 | #undef DUK__NEQ_BODY |
| 81265 | #undef DUK__PUTPROP_BODY |
| 81266 | #undef DUK__RCBIT_B |
| 81267 | #undef DUK__RCBIT_C |
| 81268 | #undef DUK__REG |
| 81269 | #undef DUK__REGCONSTP_B |
| 81270 | #undef DUK__REGCONSTP_C |
| 81271 | #undef DUK__REGP |
| 81272 | #undef DUK__REGP_A |
| 81273 | #undef DUK__REGP_B |
| 81274 | #undef DUK__REGP_BC |
| 81275 | #undef DUK__REGP_C |
| 81276 | #undef DUK__REPLACE_BOOL_A_BREAK |
| 81277 | #undef DUK__REPLACE_TOP_A_BREAK |
| 81278 | #undef DUK__REPLACE_TOP_BC_BREAK |
| 81279 | #undef DUK__REPLACE_TO_TVPTR |
| 81280 | #undef DUK__RETHAND_FINISHED |
| 81281 | #undef DUK__RETHAND_RESTART |
| 81282 | #undef DUK__RETURN_SHARED |
| 81283 | #undef DUK__SEQ_BODY |
| 81284 | #undef DUK__SHIFT_A |
| 81285 | #undef DUK__SHIFT_B |
| 81286 | #undef DUK__SHIFT_BC |
| 81287 | #undef DUK__SHIFT_C |
| 81288 | #undef DUK__SNEQ_BODY |
| 81289 | #undef DUK__STRICT |
| 81290 | #undef DUK__SYNC_AND_NULL_CURR_PC |
| 81291 | #undef DUK__SYNC_CURR_PC |
| 81292 | #undef DUK__TVAL_SHIFT |
| 81293 | #line 1 "duk_js_ops.c" |
| 81294 | /* |
| 81295 | * ECMAScript specification algorithm and conversion helpers. |
| 81296 | * |
| 81297 | * These helpers encapsulate the primitive ECMAScript operation semantics, |
| 81298 | * and are used by the bytecode executor and the API (among other places). |
| 81299 | * Some primitives are only implemented as part of the API and have no |
| 81300 | * "internal" helper. This is the case when an internal helper would not |
| 81301 | * really be useful; e.g. the operation is rare, uses value stack heavily, |
| 81302 | * etc. |
| 81303 | * |
| 81304 | * The operation arguments depend on what is required to implement |
| 81305 | * the operation: |
| 81306 | * |
| 81307 | * - If an operation is simple and stateless, and has no side |
| 81308 | * effects, it won't take an duk_hthread argument and its |
| 81309 | * arguments may be duk_tval pointers (which are safe as long |
| 81310 | * as no side effects take place). |
| 81311 | * |
| 81312 | * - If complex coercions are required (e.g. a "ToNumber" coercion) |
| 81313 | * or errors may be thrown, the operation takes an duk_hthread |
| 81314 | * argument. This also implies that the operation may have |
| 81315 | * arbitrary side effects, invalidating any duk_tval pointers. |
| 81316 | * |
| 81317 | * - For operations with potential side effects, arguments can be |
| 81318 | * taken in several ways: |
| 81319 | * |
| 81320 | * a) as duk_tval pointers, which makes sense if the "common case" |
| 81321 | * can be resolved without side effects (e.g. coercion); the |
| 81322 | * arguments are pushed to the valstack for coercion if |
| 81323 | * necessary |
| 81324 | * |
| 81325 | * b) as duk_tval values |
| 81326 | * |
| 81327 | * c) implicitly on value stack top |
| 81328 | * |
| 81329 | * d) as indices to the value stack |
| 81330 | * |
| 81331 | * Future work: |
| 81332 | * |
| 81333 | * - Argument styles may not be the most sensible in every case now. |
| 81334 | * |
| 81335 | * - In-place coercions might be useful for several operations, if |
| 81336 | * in-place coercion is OK for the bytecode executor and the API. |
| 81337 | */ |
| 81338 | |
| 81339 | /* #include duk_internal.h -> already included */ |
| 81340 | |
| 81341 | /* |
| 81342 | * ToPrimitive() (E5 Section 9.1) |
| 81343 | * |
| 81344 | * ==> implemented in the API. |
| 81345 | */ |
| 81346 | |
| 81347 | /* |
| 81348 | * ToBoolean() (E5 Section 9.2) |
| 81349 | */ |
| 81350 | |
| 81351 | DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) { |
| 81352 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 81353 | case DUK_TAG_UNDEFINED: |
| 81354 | case DUK_TAG_NULL: |
| 81355 | return 0; |
| 81356 | case DUK_TAG_BOOLEAN: |
| 81357 | DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || DUK_TVAL_GET_BOOLEAN(tv) == 1); |
| 81358 | return DUK_TVAL_GET_BOOLEAN(tv); |
| 81359 | case DUK_TAG_STRING: { |
| 81360 | /* Symbols ToBoolean() coerce to true, regardless of their |
| 81361 | * description. This happens with no explicit check because |
| 81362 | * of the symbol representation byte prefix. |
| 81363 | */ |
| 81364 | duk_hstring *h = DUK_TVAL_GET_STRING(tv); |
| 81365 | DUK_ASSERT(h != NULL); |
| 81366 | return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0); |
| 81367 | } |
| 81368 | case DUK_TAG_OBJECT: { |
| 81369 | return 1; |
| 81370 | } |
| 81371 | case DUK_TAG_BUFFER: { |
| 81372 | /* Mimic Uint8Array semantics: objects coerce true, regardless |
| 81373 | * of buffer length (zero or not) or context. |
| 81374 | */ |
| 81375 | return 1; |
| 81376 | } |
| 81377 | case DUK_TAG_POINTER: { |
| 81378 | void *p = DUK_TVAL_GET_POINTER(tv); |
| 81379 | return (p != NULL ? 1 : 0); |
| 81380 | } |
| 81381 | case DUK_TAG_LIGHTFUNC: { |
| 81382 | return 1; |
| 81383 | } |
| 81384 | #if defined(DUK_USE_FASTINT) |
| 81385 | case DUK_TAG_FASTINT: |
| 81386 | if (DUK_TVAL_GET_FASTINT(tv) != 0) { |
| 81387 | return 1; |
| 81388 | } else { |
| 81389 | return 0; |
| 81390 | } |
| 81391 | #endif |
| 81392 | default: { |
| 81393 | /* number */ |
| 81394 | duk_double_t d; |
| 81395 | #if defined(DUK_USE_PREFER_SIZE) |
| 81396 | int c; |
| 81397 | #endif |
| 81398 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 81399 | DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); |
| 81400 | d = DUK_TVAL_GET_DOUBLE(tv); |
| 81401 | #if defined(DUK_USE_PREFER_SIZE) |
| 81402 | c = DUK_FPCLASSIFY((double) d); |
| 81403 | if (c == DUK_FP_ZERO || c == DUK_FP_NAN) { |
| 81404 | return 0; |
| 81405 | } else { |
| 81406 | return 1; |
| 81407 | } |
| 81408 | #else |
| 81409 | DUK_ASSERT(duk_double_is_nan_or_zero(d) == 0 || duk_double_is_nan_or_zero(d) == 1); |
| 81410 | return duk_double_is_nan_or_zero(d) ^ 1; |
| 81411 | #endif |
| 81412 | } |
| 81413 | } |
| 81414 | DUK_UNREACHABLE(); |
| 81415 | DUK_WO_UNREACHABLE(return 0;); |
| 81416 | } |
| 81417 | |
| 81418 | /* |
| 81419 | * ToNumber() (E5 Section 9.3) |
| 81420 | * |
| 81421 | * Value to convert must be on stack top, and is popped before exit. |
| 81422 | * |
| 81423 | * See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf |
| 81424 | * http://www.cs.indiana.edu/~burger/fp/index.html |
| 81425 | * |
| 81426 | * Notes on the conversion: |
| 81427 | * |
| 81428 | * - There are specific requirements on the accuracy of the conversion |
| 81429 | * through a "Mathematical Value" (MV), so this conversion is not |
| 81430 | * trivial. |
| 81431 | * |
| 81432 | * - Quick rejects (e.g. based on first char) are difficult because |
| 81433 | * the grammar allows leading and trailing white space. |
| 81434 | * |
| 81435 | * - Quick reject based on string length is difficult even after |
| 81436 | * accounting for white space; there may be arbitrarily many |
| 81437 | * decimal digits. |
| 81438 | * |
| 81439 | * - Standard grammar allows decimal values ("123"), hex values |
| 81440 | * ("0x123") and infinities |
| 81441 | * |
| 81442 | * - Unlike source code literals, ToNumber() coerces empty strings |
| 81443 | * and strings with only whitespace to zero (not NaN). However, |
| 81444 | * while '' coerces to 0, '+' and '-' coerce to NaN. |
| 81445 | */ |
| 81446 | |
| 81447 | /* E5 Section 9.3.1 */ |
| 81448 | DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) { |
| 81449 | duk_small_uint_t s2n_flags; |
| 81450 | duk_double_t d; |
| 81451 | |
| 81452 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 81453 | |
| 81454 | /* Quite lenient, e.g. allow empty as zero, but don't allow trailing |
| 81455 | * garbage. |
| 81456 | */ |
| 81457 | s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | |
| 81458 | DUK_S2N_FLAG_ALLOW_EXP | |
| 81459 | DUK_S2N_FLAG_ALLOW_PLUS | |
| 81460 | DUK_S2N_FLAG_ALLOW_MINUS | |
| 81461 | DUK_S2N_FLAG_ALLOW_INF | |
| 81462 | DUK_S2N_FLAG_ALLOW_FRAC | |
| 81463 | DUK_S2N_FLAG_ALLOW_NAKED_FRAC | |
| 81464 | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | |
| 81465 | DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO | |
| 81466 | DUK_S2N_FLAG_ALLOW_LEADING_ZERO | |
| 81467 | DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT | |
| 81468 | DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT | |
| 81469 | DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT; |
| 81470 | |
| 81471 | duk_numconv_parse(thr, 10 /*radix*/, s2n_flags); |
| 81472 | |
| 81473 | #if defined(DUK_USE_PREFER_SIZE) |
| 81474 | d = duk_get_number(thr, -1); |
| 81475 | duk_pop_unsafe(thr); |
| 81476 | #else |
| 81477 | thr->valstack_top--; |
| 81478 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(thr->valstack_top)); |
| 81479 | DUK_ASSERT(DUK_TVAL_IS_DOUBLE(thr->valstack_top)); /* no fastint conversion in numconv now */ |
| 81480 | DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(thr->valstack_top)); |
| 81481 | d = DUK_TVAL_GET_DOUBLE(thr->valstack_top); /* assumes not a fastint */ |
| 81482 | DUK_TVAL_SET_UNDEFINED(thr->valstack_top); |
| 81483 | #endif |
| 81484 | |
| 81485 | return d; |
| 81486 | } |
| 81487 | |
| 81488 | DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) { |
| 81489 | DUK_ASSERT(thr != NULL); |
| 81490 | DUK_ASSERT(tv != NULL); |
| 81491 | |
| 81492 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 81493 | case DUK_TAG_UNDEFINED: { |
| 81494 | /* return a specific NaN (although not strictly necessary) */ |
| 81495 | duk_double_union du; |
| 81496 | DUK_DBLUNION_SET_NAN(&du); |
| 81497 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 81498 | return du.d; |
| 81499 | } |
| 81500 | case DUK_TAG_NULL: { |
| 81501 | /* +0.0 */ |
| 81502 | return 0.0; |
| 81503 | } |
| 81504 | case DUK_TAG_BOOLEAN: { |
| 81505 | if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) { |
| 81506 | return 1.0; |
| 81507 | } |
| 81508 | return 0.0; |
| 81509 | } |
| 81510 | case DUK_TAG_STRING: { |
| 81511 | /* For Symbols ToNumber() is always a TypeError. */ |
| 81512 | duk_hstring *h = DUK_TVAL_GET_STRING(tv); |
| 81513 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) { |
| 81514 | DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL); |
| 81515 | DUK_WO_NORETURN(return 0.0;); |
| 81516 | } |
| 81517 | duk_push_hstring(thr, h); |
| 81518 | return duk__tonumber_string_raw(thr); |
| 81519 | } |
| 81520 | case DUK_TAG_BUFFER: /* plain buffer treated like object */ |
| 81521 | case DUK_TAG_OBJECT: { |
| 81522 | duk_double_t d; |
| 81523 | duk_push_tval(thr, tv); |
| 81524 | duk_to_primitive(thr, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */ |
| 81525 | |
| 81526 | /* recursive call for a primitive value (guaranteed not to cause second |
| 81527 | * recursion). |
| 81528 | */ |
| 81529 | DUK_ASSERT(duk_get_tval(thr, -1) != NULL); |
| 81530 | d = duk_js_tonumber(thr, duk_get_tval(thr, -1)); |
| 81531 | |
| 81532 | duk_pop_unsafe(thr); |
| 81533 | return d; |
| 81534 | } |
| 81535 | case DUK_TAG_POINTER: { |
| 81536 | /* Coerce like boolean */ |
| 81537 | void *p = DUK_TVAL_GET_POINTER(tv); |
| 81538 | return (p != NULL ? 1.0 : 0.0); |
| 81539 | } |
| 81540 | case DUK_TAG_LIGHTFUNC: { |
| 81541 | /* +(function(){}) -> NaN */ |
| 81542 | return DUK_DOUBLE_NAN; |
| 81543 | } |
| 81544 | #if defined(DUK_USE_FASTINT) |
| 81545 | case DUK_TAG_FASTINT: |
| 81546 | return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); |
| 81547 | #endif |
| 81548 | default: { |
| 81549 | /* number */ |
| 81550 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv)); |
| 81551 | DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); |
| 81552 | return DUK_TVAL_GET_DOUBLE(tv); |
| 81553 | } |
| 81554 | } |
| 81555 | |
| 81556 | DUK_UNREACHABLE(); |
| 81557 | DUK_WO_UNREACHABLE(return 0.0;); |
| 81558 | } |
| 81559 | |
| 81560 | /* |
| 81561 | * ToInteger() (E5 Section 9.4) |
| 81562 | */ |
| 81563 | |
| 81564 | /* exposed, used by e.g. duk_bi_date.c */ |
| 81565 | DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) { |
| 81566 | #if defined(DUK_USE_PREFER_SIZE) |
| 81567 | duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 81568 | |
| 81569 | if (DUK_UNLIKELY(c == DUK_FP_NAN)) { |
| 81570 | return 0.0; |
| 81571 | } else if (DUK_UNLIKELY(c == DUK_FP_INFINITE)) { |
| 81572 | return x; |
| 81573 | } else { |
| 81574 | /* Finite, including neg/pos zero. Neg zero sign must be |
| 81575 | * preserved. |
| 81576 | */ |
| 81577 | return duk_double_trunc_towards_zero(x); |
| 81578 | } |
| 81579 | #else /* DUK_USE_PREFER_SIZE */ |
| 81580 | /* NaN and Infinity have the same exponent so it's a cheap |
| 81581 | * initial check for the rare path. |
| 81582 | */ |
| 81583 | if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x) != 0U)) { |
| 81584 | if (duk_double_is_nan(x)) { |
| 81585 | return 0.0; |
| 81586 | } else { |
| 81587 | return x; |
| 81588 | } |
| 81589 | } else { |
| 81590 | return duk_double_trunc_towards_zero(x); |
| 81591 | } |
| 81592 | #endif /* DUK_USE_PREFER_SIZE */ |
| 81593 | } |
| 81594 | |
| 81595 | DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) { |
| 81596 | /* XXX: fastint */ |
| 81597 | duk_double_t d = duk_js_tonumber(thr, tv); /* invalidates tv */ |
| 81598 | return duk_js_tointeger_number(d); |
| 81599 | } |
| 81600 | |
| 81601 | /* |
| 81602 | * ToInt32(), ToUint32(), ToUint16() (E5 Sections 9.5, 9.6, 9.7) |
| 81603 | */ |
| 81604 | |
| 81605 | /* combined algorithm matching E5 Sections 9.5 and 9.6 */ |
| 81606 | DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) { |
| 81607 | #if defined (DUK_USE_PREFER_SIZE) |
| 81608 | duk_small_int_t c; |
| 81609 | #endif |
| 81610 | |
| 81611 | #if defined (DUK_USE_PREFER_SIZE) |
| 81612 | c = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 81613 | if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) { |
| 81614 | return 0.0; |
| 81615 | } |
| 81616 | #else |
| 81617 | if (duk_double_is_nan_zero_inf(x)) { |
| 81618 | return 0.0; |
| 81619 | } |
| 81620 | #endif |
| 81621 | |
| 81622 | /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */ |
| 81623 | x = duk_double_trunc_towards_zero(x); |
| 81624 | |
| 81625 | /* NOTE: fmod(x) result sign is same as sign of x, which |
| 81626 | * differs from what Javascript wants (see Section 9.6). |
| 81627 | */ |
| 81628 | |
| 81629 | x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */ |
| 81630 | |
| 81631 | if (x < 0.0) { |
| 81632 | x += DUK_DOUBLE_2TO32; |
| 81633 | } |
| 81634 | DUK_ASSERT(x >= 0 && x < DUK_DOUBLE_2TO32); /* -> x in [0, 2**32[ */ |
| 81635 | |
| 81636 | if (is_toint32) { |
| 81637 | if (x >= DUK_DOUBLE_2TO31) { |
| 81638 | /* x in [2**31, 2**32[ */ |
| 81639 | |
| 81640 | x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */ |
| 81641 | } |
| 81642 | } |
| 81643 | |
| 81644 | return x; |
| 81645 | } |
| 81646 | |
| 81647 | DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) { |
| 81648 | duk_double_t d; |
| 81649 | |
| 81650 | #if defined(DUK_USE_FASTINT) |
| 81651 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 81652 | return DUK_TVAL_GET_FASTINT_I32(tv); |
| 81653 | } |
| 81654 | #endif |
| 81655 | |
| 81656 | d = duk_js_tonumber(thr, tv); /* invalidates tv */ |
| 81657 | d = duk__toint32_touint32_helper(d, 1); |
| 81658 | DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL); |
| 81659 | DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */ |
| 81660 | DUK_ASSERT(duk_double_equals(d, (duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */ |
| 81661 | return (duk_int32_t) d; |
| 81662 | } |
| 81663 | |
| 81664 | |
| 81665 | DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) { |
| 81666 | duk_double_t d; |
| 81667 | |
| 81668 | #if defined(DUK_USE_FASTINT) |
| 81669 | if (DUK_TVAL_IS_FASTINT(tv)) { |
| 81670 | return DUK_TVAL_GET_FASTINT_U32(tv); |
| 81671 | } |
| 81672 | #endif |
| 81673 | |
| 81674 | d = duk_js_tonumber(thr, tv); /* invalidates tv */ |
| 81675 | d = duk__toint32_touint32_helper(d, 0); |
| 81676 | DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL); |
| 81677 | DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); /* [0x00000000, 0xffffffff] */ |
| 81678 | DUK_ASSERT(duk_double_equals(d, (duk_double_t) ((duk_uint32_t) d))); /* whole, won't clip */ |
| 81679 | return (duk_uint32_t) d; |
| 81680 | |
| 81681 | } |
| 81682 | |
| 81683 | DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) { |
| 81684 | /* should be a safe way to compute this */ |
| 81685 | return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU); |
| 81686 | } |
| 81687 | |
| 81688 | /* |
| 81689 | * ToString() (E5 Section 9.8) |
| 81690 | * ToObject() (E5 Section 9.9) |
| 81691 | * CheckObjectCoercible() (E5 Section 9.10) |
| 81692 | * IsCallable() (E5 Section 9.11) |
| 81693 | * |
| 81694 | * ==> implemented in the API. |
| 81695 | */ |
| 81696 | |
| 81697 | /* |
| 81698 | * Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4, |
| 81699 | * 9.12). These have much in common so they can share some helpers. |
| 81700 | * |
| 81701 | * Future work notes: |
| 81702 | * |
| 81703 | * - Current implementation (and spec definition) has recursion; this should |
| 81704 | * be fixed if possible. |
| 81705 | * |
| 81706 | * - String-to-number coercion should be possible without going through the |
| 81707 | * value stack (and be more compact) if a shared helper is invoked. |
| 81708 | */ |
| 81709 | |
| 81710 | /* Note that this is the same operation for strict and loose equality: |
| 81711 | * - E5 Section 11.9.3, step 1.c (loose) |
| 81712 | * - E5 Section 11.9.6, step 4 (strict) |
| 81713 | */ |
| 81714 | |
| 81715 | DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) { |
| 81716 | #if defined(DUK_USE_PARANOID_MATH) |
| 81717 | /* Straightforward algorithm, makes fewer compiler assumptions. */ |
| 81718 | duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 81719 | duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y); |
| 81720 | if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) { |
| 81721 | return 0; |
| 81722 | } |
| 81723 | if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) { |
| 81724 | return 1; |
| 81725 | } |
| 81726 | if (x == y) { |
| 81727 | return 1; |
| 81728 | } |
| 81729 | return 0; |
| 81730 | #else /* DUK_USE_PARANOID_MATH */ |
| 81731 | /* Better equivalent algorithm. If the compiler is compliant, C and |
| 81732 | * ECMAScript semantics are identical for this particular comparison. |
| 81733 | * In particular, NaNs must never compare equal and zeroes must compare |
| 81734 | * equal regardless of sign. Could also use a macro, but this inlines |
| 81735 | * already nicely (no difference on gcc, for instance). |
| 81736 | */ |
| 81737 | if (duk_double_equals(x, y)) { |
| 81738 | /* IEEE requires that NaNs compare false */ |
| 81739 | DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN); |
| 81740 | DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN); |
| 81741 | return 1; |
| 81742 | } else { |
| 81743 | /* IEEE requires that zeros compare the same regardless |
| 81744 | * of their signed, so if both x and y are zeroes, they |
| 81745 | * are caught above. |
| 81746 | */ |
| 81747 | DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO)); |
| 81748 | return 0; |
| 81749 | } |
| 81750 | #endif /* DUK_USE_PARANOID_MATH */ |
| 81751 | } |
| 81752 | |
| 81753 | DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) { |
| 81754 | #if defined(DUK_USE_PARANOID_MATH) |
| 81755 | duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 81756 | duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y); |
| 81757 | |
| 81758 | if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) { |
| 81759 | /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */ |
| 81760 | return 1; |
| 81761 | } |
| 81762 | if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) { |
| 81763 | /* Note: cannot assume that a non-zero return value of signbit() would |
| 81764 | * always be the same -- hence cannot (portably) use something like: |
| 81765 | * |
| 81766 | * signbit(x) == signbit(y) |
| 81767 | */ |
| 81768 | duk_small_int_t sx = DUK_SIGNBIT(x) ? 1 : 0; |
| 81769 | duk_small_int_t sy = DUK_SIGNBIT(y) ? 1 : 0; |
| 81770 | return (sx == sy); |
| 81771 | } |
| 81772 | |
| 81773 | /* normal comparison; known: |
| 81774 | * - both x and y are not NaNs (but one of them can be) |
| 81775 | * - both x and y are not zero (but one of them can be) |
| 81776 | * - x and y may be denormal or infinite |
| 81777 | */ |
| 81778 | |
| 81779 | return (x == y); |
| 81780 | #else /* DUK_USE_PARANOID_MATH */ |
| 81781 | duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 81782 | duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y); |
| 81783 | |
| 81784 | if (duk_double_equals(x, y)) { |
| 81785 | /* IEEE requires that NaNs compare false */ |
| 81786 | DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN); |
| 81787 | DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN); |
| 81788 | |
| 81789 | /* Using classification has smaller footprint than direct comparison. */ |
| 81790 | if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) { |
| 81791 | /* Note: cannot assume that a non-zero return value of signbit() would |
| 81792 | * always be the same -- hence cannot (portably) use something like: |
| 81793 | * |
| 81794 | * signbit(x) == signbit(y) |
| 81795 | */ |
| 81796 | return duk_double_same_sign(x, y); |
| 81797 | } |
| 81798 | return 1; |
| 81799 | } else { |
| 81800 | /* IEEE requires that zeros compare the same regardless |
| 81801 | * of their sign, so if both x and y are zeroes, they |
| 81802 | * are caught above. |
| 81803 | */ |
| 81804 | DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO)); |
| 81805 | |
| 81806 | /* Difference to non-strict/strict comparison is that NaNs compare |
| 81807 | * equal and signed zero signs matter. |
| 81808 | */ |
| 81809 | if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) { |
| 81810 | /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */ |
| 81811 | return 1; |
| 81812 | } |
| 81813 | return 0; |
| 81814 | } |
| 81815 | #endif /* DUK_USE_PARANOID_MATH */ |
| 81816 | } |
| 81817 | |
| 81818 | DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) { |
| 81819 | duk_uint_t type_mask_x; |
| 81820 | duk_uint_t type_mask_y; |
| 81821 | |
| 81822 | /* If flags != 0 (strict or SameValue), thr can be NULL. For loose |
| 81823 | * equals comparison it must be != NULL. |
| 81824 | */ |
| 81825 | DUK_ASSERT(flags != 0 || thr != NULL); |
| 81826 | |
| 81827 | /* |
| 81828 | * Same type? |
| 81829 | * |
| 81830 | * Note: since number values have no explicit tag in the 8-byte |
| 81831 | * representation, need the awkward if + switch. |
| 81832 | */ |
| 81833 | |
| 81834 | #if defined(DUK_USE_FASTINT) |
| 81835 | if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) { |
| 81836 | if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) { |
| 81837 | return 1; |
| 81838 | } else { |
| 81839 | return 0; |
| 81840 | } |
| 81841 | } |
| 81842 | else |
| 81843 | #endif |
| 81844 | if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) { |
| 81845 | duk_double_t d1, d2; |
| 81846 | |
| 81847 | /* Catches both doubles and cases where only one argument is |
| 81848 | * a fastint so can't assume a double. |
| 81849 | */ |
| 81850 | d1 = DUK_TVAL_GET_NUMBER(tv_x); |
| 81851 | d2 = DUK_TVAL_GET_NUMBER(tv_y); |
| 81852 | if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) { |
| 81853 | /* SameValue */ |
| 81854 | return duk__js_samevalue_number(d1, d2); |
| 81855 | } else { |
| 81856 | /* equals and strict equals */ |
| 81857 | return duk__js_equals_number(d1, d2); |
| 81858 | } |
| 81859 | } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) { |
| 81860 | switch (DUK_TVAL_GET_TAG(tv_x)) { |
| 81861 | case DUK_TAG_UNDEFINED: |
| 81862 | case DUK_TAG_NULL: { |
| 81863 | return 1; |
| 81864 | } |
| 81865 | case DUK_TAG_BOOLEAN: { |
| 81866 | return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y); |
| 81867 | } |
| 81868 | case DUK_TAG_POINTER: { |
| 81869 | return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y); |
| 81870 | } |
| 81871 | case DUK_TAG_STRING: |
| 81872 | case DUK_TAG_OBJECT: { |
| 81873 | /* Heap pointer comparison suffices for strings and objects. |
| 81874 | * Symbols compare equal if they have the same internal |
| 81875 | * representation; again heap pointer comparison suffices. |
| 81876 | */ |
| 81877 | return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y); |
| 81878 | } |
| 81879 | case DUK_TAG_BUFFER: { |
| 81880 | /* In Duktape 2.x plain buffers mimic Uint8Array objects |
| 81881 | * so always compare by heap pointer. In Duktape 1.x |
| 81882 | * strict comparison would compare heap pointers and |
| 81883 | * non-strict would compare contents. |
| 81884 | */ |
| 81885 | return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y); |
| 81886 | } |
| 81887 | case DUK_TAG_LIGHTFUNC: { |
| 81888 | /* At least 'magic' has a significant impact on function |
| 81889 | * identity. |
| 81890 | */ |
| 81891 | duk_small_uint_t lf_flags_x; |
| 81892 | duk_small_uint_t lf_flags_y; |
| 81893 | duk_c_function func_x; |
| 81894 | duk_c_function func_y; |
| 81895 | |
| 81896 | DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x); |
| 81897 | DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y); |
| 81898 | return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0; |
| 81899 | } |
| 81900 | #if defined(DUK_USE_FASTINT) |
| 81901 | case DUK_TAG_FASTINT: |
| 81902 | #endif |
| 81903 | default: { |
| 81904 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x)); |
| 81905 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y)); |
| 81906 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x)); |
| 81907 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y)); |
| 81908 | DUK_UNREACHABLE(); |
| 81909 | DUK_WO_UNREACHABLE(return 0;); |
| 81910 | } |
| 81911 | } |
| 81912 | } |
| 81913 | |
| 81914 | if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) { |
| 81915 | return 0; |
| 81916 | } |
| 81917 | |
| 81918 | DUK_ASSERT(flags == 0); /* non-strict equality from here on */ |
| 81919 | |
| 81920 | /* |
| 81921 | * Types are different; various cases for non-strict comparison |
| 81922 | * |
| 81923 | * Since comparison is symmetric, we use a "swap trick" to reduce |
| 81924 | * code size. |
| 81925 | */ |
| 81926 | |
| 81927 | type_mask_x = duk_get_type_mask_tval(tv_x); |
| 81928 | type_mask_y = duk_get_type_mask_tval(tv_y); |
| 81929 | |
| 81930 | /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */ |
| 81931 | if ((type_mask_x & (DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) && |
| 81932 | (type_mask_y & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED))) { |
| 81933 | return 1; |
| 81934 | } |
| 81935 | |
| 81936 | /* Number/string -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */ |
| 81937 | if ((type_mask_x & DUK_TYPE_MASK_NUMBER) && (type_mask_y & DUK_TYPE_MASK_STRING)) { |
| 81938 | if (!DUK_TVAL_STRING_IS_SYMBOL(tv_y)) { |
| 81939 | duk_double_t d1, d2; |
| 81940 | d1 = DUK_TVAL_GET_NUMBER(tv_x); |
| 81941 | d2 = duk_to_number_tval(thr, tv_y); |
| 81942 | return duk__js_equals_number(d1, d2); |
| 81943 | } |
| 81944 | } |
| 81945 | if ((type_mask_x & DUK_TYPE_MASK_STRING) && (type_mask_y & DUK_TYPE_MASK_NUMBER)) { |
| 81946 | if (!DUK_TVAL_STRING_IS_SYMBOL(tv_x)) { |
| 81947 | duk_double_t d1, d2; |
| 81948 | d1 = DUK_TVAL_GET_NUMBER(tv_y); |
| 81949 | d2 = duk_to_number_tval(thr, tv_x); |
| 81950 | return duk__js_equals_number(d1, d2); |
| 81951 | } |
| 81952 | } |
| 81953 | |
| 81954 | /* Boolean/any -> coerce boolean to number and try again. If boolean is |
| 81955 | * compared to a pointer, the final comparison after coercion now always |
| 81956 | * yields false (as pointer vs. number compares to false), but this is |
| 81957 | * not special cased. |
| 81958 | * |
| 81959 | * ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. |
| 81960 | */ |
| 81961 | if (type_mask_x & DUK_TYPE_MASK_BOOLEAN) { |
| 81962 | DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1); |
| 81963 | duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_x)); |
| 81964 | duk_push_tval(thr, tv_y); |
| 81965 | goto recursive_call; |
| 81966 | } |
| 81967 | if (type_mask_y & DUK_TYPE_MASK_BOOLEAN) { |
| 81968 | DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1); |
| 81969 | duk_push_tval(thr, tv_x); |
| 81970 | duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_y)); |
| 81971 | goto recursive_call; |
| 81972 | } |
| 81973 | |
| 81974 | /* String-number-symbol/object -> coerce object to primitive (apparently without hint), then try again. */ |
| 81975 | if ((type_mask_x & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER)) && |
| 81976 | (type_mask_y & DUK_TYPE_MASK_OBJECT)) { |
| 81977 | /* No symbol check needed because symbols and strings are accepted. */ |
| 81978 | duk_push_tval(thr, tv_x); |
| 81979 | duk_push_tval(thr, tv_y); |
| 81980 | duk_to_primitive(thr, -1, DUK_HINT_NONE); /* apparently no hint? */ |
| 81981 | goto recursive_call; |
| 81982 | } |
| 81983 | if ((type_mask_x & DUK_TYPE_MASK_OBJECT) && |
| 81984 | (type_mask_y & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER))) { |
| 81985 | /* No symbol check needed because symbols and strings are accepted. */ |
| 81986 | duk_push_tval(thr, tv_x); |
| 81987 | duk_push_tval(thr, tv_y); |
| 81988 | duk_to_primitive(thr, -2, DUK_HINT_NONE); /* apparently no hint? */ |
| 81989 | goto recursive_call; |
| 81990 | } |
| 81991 | |
| 81992 | /* Nothing worked -> not equal. */ |
| 81993 | return 0; |
| 81994 | |
| 81995 | recursive_call: |
| 81996 | /* Shared code path to call the helper again with arguments on stack top. */ |
| 81997 | { |
| 81998 | duk_bool_t rc; |
| 81999 | rc = duk_js_equals_helper(thr, |
| 82000 | DUK_GET_TVAL_NEGIDX(thr, -2), |
| 82001 | DUK_GET_TVAL_NEGIDX(thr, -1), |
| 82002 | 0 /*flags:nonstrict*/); |
| 82003 | duk_pop_2_unsafe(thr); |
| 82004 | return rc; |
| 82005 | } |
| 82006 | } |
| 82007 | |
| 82008 | /* |
| 82009 | * Comparisons (x >= y, x > y, x <= y, x < y) |
| 82010 | * |
| 82011 | * E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first |
| 82012 | * flags to get the rest. |
| 82013 | */ |
| 82014 | |
| 82015 | /* XXX: this should probably just operate on the stack top, because it |
| 82016 | * needs to push stuff on the stack anyway... |
| 82017 | */ |
| 82018 | |
| 82019 | DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2) { |
| 82020 | duk_size_t prefix_len; |
| 82021 | duk_small_int_t rc; |
| 82022 | |
| 82023 | prefix_len = (len1 <= len2 ? len1 : len2); |
| 82024 | |
| 82025 | /* duk_memcmp() is guaranteed to return zero (equal) for zero length |
| 82026 | * inputs. |
| 82027 | */ |
| 82028 | rc = duk_memcmp_unsafe((const void *) buf1, |
| 82029 | (const void *) buf2, |
| 82030 | (size_t) prefix_len); |
| 82031 | |
| 82032 | if (rc < 0) { |
| 82033 | return -1; |
| 82034 | } else if (rc > 0) { |
| 82035 | return 1; |
| 82036 | } |
| 82037 | |
| 82038 | /* prefix matches, lengths matter now */ |
| 82039 | if (len1 < len2) { |
| 82040 | /* e.g. "x" < "xx" */ |
| 82041 | return -1; |
| 82042 | } else if (len1 > len2) { |
| 82043 | return 1; |
| 82044 | } |
| 82045 | |
| 82046 | return 0; |
| 82047 | } |
| 82048 | |
| 82049 | DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) { |
| 82050 | /* |
| 82051 | * String comparison (E5 Section 11.8.5, step 4), which |
| 82052 | * needs to compare codepoint by codepoint. |
| 82053 | * |
| 82054 | * However, UTF-8 allows us to use strcmp directly: the shared |
| 82055 | * prefix will be encoded identically (UTF-8 has unique encoding) |
| 82056 | * and the first differing character can be compared with a simple |
| 82057 | * unsigned byte comparison (which strcmp does). |
| 82058 | * |
| 82059 | * This will not work properly for non-xutf-8 strings, but this |
| 82060 | * is not an issue for compliance. |
| 82061 | */ |
| 82062 | |
| 82063 | DUK_ASSERT(h1 != NULL); |
| 82064 | DUK_ASSERT(h2 != NULL); |
| 82065 | |
| 82066 | return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1), |
| 82067 | (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2), |
| 82068 | (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1), |
| 82069 | (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2)); |
| 82070 | } |
| 82071 | |
| 82072 | #if 0 /* unused */ |
| 82073 | DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) { |
| 82074 | /* Similar to String comparison. */ |
| 82075 | |
| 82076 | DUK_ASSERT(h1 != NULL); |
| 82077 | DUK_ASSERT(h2 != NULL); |
| 82078 | DUK_UNREF(heap); |
| 82079 | |
| 82080 | return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1), |
| 82081 | (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2), |
| 82082 | (duk_size_t) DUK_HBUFFER_GET_SIZE(h1), |
| 82083 | (duk_size_t) DUK_HBUFFER_GET_SIZE(h2)); |
| 82084 | } |
| 82085 | #endif |
| 82086 | |
| 82087 | #if defined(DUK_USE_FASTINT) |
| 82088 | DUK_LOCAL duk_bool_t duk__compare_fastint(duk_bool_t retval, duk_int64_t v1, duk_int64_t v2) { |
| 82089 | DUK_ASSERT(retval == 0 || retval == 1); |
| 82090 | if (v1 < v2) { |
| 82091 | return retval ^ 1; |
| 82092 | } else { |
| 82093 | return retval; |
| 82094 | } |
| 82095 | } |
| 82096 | #endif |
| 82097 | |
| 82098 | #if defined(DUK_USE_PARANOID_MATH) |
| 82099 | DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) { |
| 82100 | duk_small_int_t c1, s1, c2, s2; |
| 82101 | |
| 82102 | DUK_ASSERT(retval == 0 || retval == 1); |
| 82103 | c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1); |
| 82104 | s1 = (duk_small_int_t) DUK_SIGNBIT(d1); |
| 82105 | c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2); |
| 82106 | s2 = (duk_small_int_t) DUK_SIGNBIT(d2); |
| 82107 | |
| 82108 | if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) { |
| 82109 | return 0; /* Always false, regardless of negation. */ |
| 82110 | } |
| 82111 | |
| 82112 | if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) { |
| 82113 | /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0, |
| 82114 | * steps e, f, and g. |
| 82115 | */ |
| 82116 | return retval; /* false */ |
| 82117 | } |
| 82118 | |
| 82119 | if (d1 == d2) { |
| 82120 | return retval; /* false */ |
| 82121 | } |
| 82122 | |
| 82123 | if (c1 == DUK_FP_INFINITE && s1 == 0) { |
| 82124 | /* x == +Infinity */ |
| 82125 | return retval; /* false */ |
| 82126 | } |
| 82127 | |
| 82128 | if (c2 == DUK_FP_INFINITE && s2 == 0) { |
| 82129 | /* y == +Infinity */ |
| 82130 | return retval ^ 1; /* true */ |
| 82131 | } |
| 82132 | |
| 82133 | if (c2 == DUK_FP_INFINITE && s2 != 0) { |
| 82134 | /* y == -Infinity */ |
| 82135 | return retval; /* false */ |
| 82136 | } |
| 82137 | |
| 82138 | if (c1 == DUK_FP_INFINITE && s1 != 0) { |
| 82139 | /* x == -Infinity */ |
| 82140 | return retval ^ 1; /* true */ |
| 82141 | } |
| 82142 | |
| 82143 | if (d1 < d2) { |
| 82144 | return retval ^ 1; /* true */ |
| 82145 | } |
| 82146 | |
| 82147 | return retval; /* false */ |
| 82148 | } |
| 82149 | #else /* DUK_USE_PARANOID_MATH */ |
| 82150 | DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) { |
| 82151 | /* This comparison tree relies doesn't match the exact steps in |
| 82152 | * E5 Section 11.8.5 but should produce the same results. The |
| 82153 | * steps rely on exact IEEE semantics for NaNs, etc. |
| 82154 | */ |
| 82155 | |
| 82156 | DUK_ASSERT(retval == 0 || retval == 1); |
| 82157 | if (d1 < d2) { |
| 82158 | /* In no case should both (d1 < d2) and (d2 < d1) be true. |
| 82159 | * It's possible that neither is true though, and that's |
| 82160 | * handled below. |
| 82161 | */ |
| 82162 | DUK_ASSERT(!(d2 < d1)); |
| 82163 | |
| 82164 | /* - d1 < d2, both d1/d2 are normals (not Infinity, not NaN) |
| 82165 | * - d2 is +Infinity, d1 != +Infinity and NaN |
| 82166 | * - d1 is -Infinity, d2 != -Infinity and NaN |
| 82167 | */ |
| 82168 | return retval ^ 1; |
| 82169 | } else { |
| 82170 | if (d2 < d1) { |
| 82171 | /* - !(d1 < d2), both d1/d2 are normals (not Infinity, not NaN) |
| 82172 | * - d1 is +Infinity, d2 != +Infinity and NaN |
| 82173 | * - d2 is -Infinity, d1 != -Infinity and NaN |
| 82174 | */ |
| 82175 | return retval; |
| 82176 | } else { |
| 82177 | /* - d1 and/or d2 is NaN |
| 82178 | * - d1 and d2 are both +/- 0 |
| 82179 | * - d1 == d2 (including infinities) |
| 82180 | */ |
| 82181 | if (duk_double_is_nan(d1) || duk_double_is_nan(d2)) { |
| 82182 | /* Note: undefined from Section 11.8.5 always |
| 82183 | * results in false return (see e.g. Section |
| 82184 | * 11.8.3) - hence special treatment here. |
| 82185 | */ |
| 82186 | return 0; /* zero regardless of negation */ |
| 82187 | } else { |
| 82188 | return retval; |
| 82189 | } |
| 82190 | } |
| 82191 | } |
| 82192 | } |
| 82193 | #endif /* DUK_USE_PARANOID_MATH */ |
| 82194 | |
| 82195 | DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) { |
| 82196 | duk_double_t d1, d2; |
| 82197 | duk_small_int_t rc; |
| 82198 | duk_bool_t retval; |
| 82199 | |
| 82200 | DUK_ASSERT(DUK_COMPARE_FLAG_NEGATE == 1); /* Rely on this flag being lowest. */ |
| 82201 | retval = flags & DUK_COMPARE_FLAG_NEGATE; |
| 82202 | DUK_ASSERT(retval == 0 || retval == 1); |
| 82203 | |
| 82204 | /* Fast path for fastints */ |
| 82205 | #if defined(DUK_USE_FASTINT) |
| 82206 | if (DUK_LIKELY(DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y))) { |
| 82207 | return duk__compare_fastint(retval, |
| 82208 | DUK_TVAL_GET_FASTINT(tv_x), |
| 82209 | DUK_TVAL_GET_FASTINT(tv_y)); |
| 82210 | } |
| 82211 | #endif /* DUK_USE_FASTINT */ |
| 82212 | |
| 82213 | /* Fast path for numbers (one of which may be a fastint) */ |
| 82214 | #if !defined(DUK_USE_PREFER_SIZE) |
| 82215 | if (DUK_LIKELY(DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y))) { |
| 82216 | return duk__compare_number(retval, |
| 82217 | DUK_TVAL_GET_NUMBER(tv_x), |
| 82218 | DUK_TVAL_GET_NUMBER(tv_y)); |
| 82219 | } |
| 82220 | #endif |
| 82221 | |
| 82222 | /* Slow path */ |
| 82223 | |
| 82224 | duk_push_tval(thr, tv_x); |
| 82225 | duk_push_tval(thr, tv_y); |
| 82226 | |
| 82227 | if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) { |
| 82228 | duk_to_primitive(thr, -2, DUK_HINT_NUMBER); |
| 82229 | duk_to_primitive(thr, -1, DUK_HINT_NUMBER); |
| 82230 | } else { |
| 82231 | duk_to_primitive(thr, -1, DUK_HINT_NUMBER); |
| 82232 | duk_to_primitive(thr, -2, DUK_HINT_NUMBER); |
| 82233 | } |
| 82234 | |
| 82235 | /* Note: reuse variables */ |
| 82236 | tv_x = DUK_GET_TVAL_NEGIDX(thr, -2); |
| 82237 | tv_y = DUK_GET_TVAL_NEGIDX(thr, -1); |
| 82238 | |
| 82239 | if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) { |
| 82240 | duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x); |
| 82241 | duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y); |
| 82242 | DUK_ASSERT(h1 != NULL); |
| 82243 | DUK_ASSERT(h2 != NULL); |
| 82244 | |
| 82245 | if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) { |
| 82246 | rc = duk_js_string_compare(h1, h2); |
| 82247 | duk_pop_2_unsafe(thr); |
| 82248 | if (rc < 0) { |
| 82249 | return retval ^ 1; |
| 82250 | } else { |
| 82251 | return retval; |
| 82252 | } |
| 82253 | } |
| 82254 | |
| 82255 | /* One or both are Symbols: fall through to handle in the |
| 82256 | * generic path. Concretely, ToNumber() will fail. |
| 82257 | */ |
| 82258 | } |
| 82259 | |
| 82260 | /* Ordering should not matter (E5 Section 11.8.5, step 3.a). */ |
| 82261 | #if 0 |
| 82262 | if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) { |
| 82263 | d1 = duk_to_number_m2(thr); |
| 82264 | d2 = duk_to_number_m1(thr); |
| 82265 | } else { |
| 82266 | d2 = duk_to_number_m1(thr); |
| 82267 | d1 = duk_to_number_m2(thr); |
| 82268 | } |
| 82269 | #endif |
| 82270 | d1 = duk_to_number_m2(thr); |
| 82271 | d2 = duk_to_number_m1(thr); |
| 82272 | |
| 82273 | /* We want to duk_pop_2_unsafe(thr); because the values are numbers |
| 82274 | * no decref check is needed. |
| 82275 | */ |
| 82276 | #if defined(DUK_USE_PREFER_SIZE) |
| 82277 | duk_pop_2_nodecref_unsafe(thr); |
| 82278 | #else |
| 82279 | DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -2))); |
| 82280 | DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -1))); |
| 82281 | DUK_ASSERT(duk_get_top(thr) >= 2); |
| 82282 | thr->valstack_top -= 2; |
| 82283 | tv_x = thr->valstack_top; |
| 82284 | tv_y = tv_x + 1; |
| 82285 | DUK_TVAL_SET_UNDEFINED(tv_x); /* Value stack policy */ |
| 82286 | DUK_TVAL_SET_UNDEFINED(tv_y); |
| 82287 | #endif |
| 82288 | |
| 82289 | return duk__compare_number(retval, d1, d2); |
| 82290 | } |
| 82291 | |
| 82292 | /* |
| 82293 | * instanceof |
| 82294 | */ |
| 82295 | |
| 82296 | /* |
| 82297 | * ES2015 Section 7.3.19 describes the OrdinaryHasInstance() algorithm |
| 82298 | * which covers both bound and non-bound functions; in effect the algorithm |
| 82299 | * includes E5 Sections 11.8.6, 15.3.5.3, and 15.3.4.5.3. |
| 82300 | * |
| 82301 | * ES2015 Section 12.9.4 describes the instanceof operator which first |
| 82302 | * checks @@hasInstance well-known symbol and falls back to |
| 82303 | * OrdinaryHasInstance(). |
| 82304 | * |
| 82305 | * Limited Proxy support: don't support 'getPrototypeOf' trap but |
| 82306 | * continue lookup in Proxy target if the value is a Proxy. |
| 82307 | */ |
| 82308 | |
| 82309 | DUK_LOCAL duk_bool_t duk__js_instanceof_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_bool_t skip_sym_check) { |
| 82310 | duk_hobject *func; |
| 82311 | duk_hobject *val; |
| 82312 | duk_hobject *proto; |
| 82313 | duk_tval *tv; |
| 82314 | duk_bool_t skip_first; |
| 82315 | duk_uint_t sanity; |
| 82316 | |
| 82317 | /* |
| 82318 | * Get the values onto the stack first. It would be possible to cover |
| 82319 | * some normal cases without resorting to the value stack. |
| 82320 | * |
| 82321 | * The right hand side could be a light function (as they generally |
| 82322 | * behave like objects). Light functions never have a 'prototype' |
| 82323 | * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError. |
| 82324 | * Using duk_require_hobject() is thus correct (except for error msg). |
| 82325 | */ |
| 82326 | |
| 82327 | duk_push_tval(thr, tv_x); |
| 82328 | duk_push_tval(thr, tv_y); |
| 82329 | func = duk_require_hobject(thr, -1); |
| 82330 | DUK_ASSERT(func != NULL); |
| 82331 | |
| 82332 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 82333 | /* |
| 82334 | * @@hasInstance check, ES2015 Section 12.9.4, Steps 2-4. |
| 82335 | */ |
| 82336 | if (!skip_sym_check) { |
| 82337 | if (duk_get_method_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)) { |
| 82338 | /* [ ... lhs rhs func ] */ |
| 82339 | duk_insert(thr, -3); /* -> [ ... func lhs rhs ] */ |
| 82340 | duk_swap_top(thr, -2); /* -> [ ... func rhs(this) lhs ] */ |
| 82341 | duk_call_method(thr, 1); |
| 82342 | return duk_to_boolean_top_pop(thr); |
| 82343 | } |
| 82344 | } |
| 82345 | #else |
| 82346 | DUK_UNREF(skip_sym_check); |
| 82347 | #endif |
| 82348 | |
| 82349 | /* |
| 82350 | * For bound objects, [[HasInstance]] just calls the target function |
| 82351 | * [[HasInstance]]. If that is again a bound object, repeat until |
| 82352 | * we find a non-bound Function object. |
| 82353 | * |
| 82354 | * The bound function chain is now "collapsed" so there can be only |
| 82355 | * one bound function in the chain. |
| 82356 | */ |
| 82357 | |
| 82358 | if (!DUK_HOBJECT_IS_CALLABLE(func)) { |
| 82359 | /* |
| 82360 | * Note: of native ECMAScript objects, only Function instances |
| 82361 | * have a [[HasInstance]] internal property. Custom objects might |
| 82362 | * also have it, but not in current implementation. |
| 82363 | * |
| 82364 | * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF? |
| 82365 | */ |
| 82366 | goto error_invalid_rval; |
| 82367 | } |
| 82368 | |
| 82369 | if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) { |
| 82370 | duk_push_tval(thr, &((duk_hboundfunc *) (void *) func)->target); |
| 82371 | duk_replace(thr, -2); |
| 82372 | func = duk_require_hobject(thr, -1); /* lightfunc throws */ |
| 82373 | |
| 82374 | /* Rely on Function.prototype.bind() never creating bound |
| 82375 | * functions whose target is not proper. |
| 82376 | */ |
| 82377 | DUK_ASSERT(func != NULL); |
| 82378 | DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func)); |
| 82379 | } |
| 82380 | |
| 82381 | /* |
| 82382 | * 'func' is now a non-bound object which supports [[HasInstance]] |
| 82383 | * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on |
| 82384 | * to execute E5 Section 15.3.5.3. |
| 82385 | */ |
| 82386 | |
| 82387 | DUK_ASSERT(func != NULL); |
| 82388 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); |
| 82389 | DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func)); |
| 82390 | |
| 82391 | /* [ ... lval rval(func) ] */ |
| 82392 | |
| 82393 | /* For lightfuncs, buffers, and pointers start the comparison directly |
| 82394 | * from the virtual prototype object. |
| 82395 | */ |
| 82396 | skip_first = 0; |
| 82397 | tv = DUK_GET_TVAL_NEGIDX(thr, -2); |
| 82398 | switch (DUK_TVAL_GET_TAG(tv)) { |
| 82399 | case DUK_TAG_LIGHTFUNC: |
| 82400 | val = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]; |
| 82401 | DUK_ASSERT(val != NULL); |
| 82402 | break; |
| 82403 | case DUK_TAG_BUFFER: |
| 82404 | val = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE]; |
| 82405 | DUK_ASSERT(val != NULL); |
| 82406 | break; |
| 82407 | case DUK_TAG_POINTER: |
| 82408 | val = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE]; |
| 82409 | DUK_ASSERT(val != NULL); |
| 82410 | break; |
| 82411 | case DUK_TAG_OBJECT: |
| 82412 | skip_first = 1; /* Ignore object itself on first round. */ |
| 82413 | val = DUK_TVAL_GET_OBJECT(tv); |
| 82414 | DUK_ASSERT(val != NULL); |
| 82415 | break; |
| 82416 | default: |
| 82417 | goto pop2_and_false; |
| 82418 | } |
| 82419 | DUK_ASSERT(val != NULL); /* Loop doesn't actually rely on this. */ |
| 82420 | |
| 82421 | /* Look up .prototype of rval. Leave it on the value stack in case it |
| 82422 | * has been virtualized (e.g. getter, Proxy trap). |
| 82423 | */ |
| 82424 | duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */ |
| 82425 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 82426 | proto = duk_get_hobject(thr, -1); |
| 82427 | if (proto == NULL) { |
| 82428 | goto error_invalid_rval_noproto; |
| 82429 | } |
| 82430 | #else |
| 82431 | proto = duk_require_hobject(thr, -1); |
| 82432 | #endif |
| 82433 | |
| 82434 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 82435 | do { |
| 82436 | /* |
| 82437 | * Note: prototype chain is followed BEFORE first comparison. This |
| 82438 | * means that the instanceof lval is never itself compared to the |
| 82439 | * rval.prototype property. This is apparently intentional, see E5 |
| 82440 | * Section 15.3.5.3, step 4.a. |
| 82441 | * |
| 82442 | * Also note: |
| 82443 | * |
| 82444 | * js> (function() {}) instanceof Function |
| 82445 | * true |
| 82446 | * js> Function instanceof Function |
| 82447 | * true |
| 82448 | * |
| 82449 | * For the latter, h_proto will be Function.prototype, which is the |
| 82450 | * built-in Function prototype. Because Function.[[Prototype]] is |
| 82451 | * also the built-in Function prototype, the result is true. |
| 82452 | */ |
| 82453 | |
| 82454 | if (!val) { |
| 82455 | goto pop3_and_false; |
| 82456 | } |
| 82457 | |
| 82458 | DUK_ASSERT(val != NULL); |
| 82459 | #if defined(DUK_USE_ES6_PROXY) |
| 82460 | val = duk_hobject_resolve_proxy_target(val); |
| 82461 | #endif |
| 82462 | |
| 82463 | if (skip_first) { |
| 82464 | skip_first = 0; |
| 82465 | } else if (val == proto) { |
| 82466 | goto pop3_and_true; |
| 82467 | } |
| 82468 | |
| 82469 | DUK_ASSERT(val != NULL); |
| 82470 | val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val); |
| 82471 | } while (--sanity > 0); |
| 82472 | |
| 82473 | DUK_ASSERT(sanity == 0); |
| 82474 | DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); |
| 82475 | DUK_WO_NORETURN(return 0;); |
| 82476 | |
| 82477 | pop2_and_false: |
| 82478 | duk_pop_2_unsafe(thr); |
| 82479 | return 0; |
| 82480 | |
| 82481 | pop3_and_false: |
| 82482 | duk_pop_3_unsafe(thr); |
| 82483 | return 0; |
| 82484 | |
| 82485 | pop3_and_true: |
| 82486 | duk_pop_3_unsafe(thr); |
| 82487 | return 1; |
| 82488 | |
| 82489 | error_invalid_rval: |
| 82490 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL); |
| 82491 | DUK_WO_NORETURN(return 0;); |
| 82492 | |
| 82493 | #if defined(DUK_USE_VERBOSE_ERRORS) |
| 82494 | error_invalid_rval_noproto: |
| 82495 | DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO); |
| 82496 | DUK_WO_NORETURN(return 0;); |
| 82497 | #endif |
| 82498 | } |
| 82499 | |
| 82500 | #if defined(DUK_USE_SYMBOL_BUILTIN) |
| 82501 | DUK_INTERNAL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { |
| 82502 | return duk__js_instanceof_helper(thr, tv_x, tv_y, 1 /*skip_sym_check*/); |
| 82503 | } |
| 82504 | #endif |
| 82505 | |
| 82506 | DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { |
| 82507 | return duk__js_instanceof_helper(thr, tv_x, tv_y, 0 /*skip_sym_check*/); |
| 82508 | } |
| 82509 | |
| 82510 | /* |
| 82511 | * in |
| 82512 | */ |
| 82513 | |
| 82514 | /* |
| 82515 | * E5 Sections 11.8.7, 8.12.6. |
| 82516 | * |
| 82517 | * Basically just a property existence check using [[HasProperty]]. |
| 82518 | */ |
| 82519 | |
| 82520 | DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) { |
| 82521 | duk_bool_t retval; |
| 82522 | |
| 82523 | /* |
| 82524 | * Get the values onto the stack first. It would be possible to cover |
| 82525 | * some normal cases without resorting to the value stack (e.g. if |
| 82526 | * lval is already a string). |
| 82527 | */ |
| 82528 | |
| 82529 | /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj' |
| 82530 | * must be string coerced before the internal HasProperty() algorithm is |
| 82531 | * invoked. A fast path skipping coercion could be safely implemented for |
| 82532 | * numbers (as number-to-string coercion has no side effects). For ES2015 |
| 82533 | * proxy behavior, the trap 'key' argument must be in a string coerced |
| 82534 | * form (which is a shame). |
| 82535 | */ |
| 82536 | |
| 82537 | /* TypeError if rval is not an object or object like (e.g. lightfunc |
| 82538 | * or plain buffer). |
| 82539 | */ |
| 82540 | duk_push_tval(thr, tv_x); |
| 82541 | duk_push_tval(thr, tv_y); |
| 82542 | duk_require_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER); |
| 82543 | |
| 82544 | (void) duk_to_property_key_hstring(thr, -2); |
| 82545 | |
| 82546 | retval = duk_hobject_hasprop(thr, |
| 82547 | DUK_GET_TVAL_NEGIDX(thr, -1), |
| 82548 | DUK_GET_TVAL_NEGIDX(thr, -2)); |
| 82549 | |
| 82550 | duk_pop_2_unsafe(thr); |
| 82551 | return retval; |
| 82552 | } |
| 82553 | |
| 82554 | /* |
| 82555 | * typeof |
| 82556 | * |
| 82557 | * E5 Section 11.4.3. |
| 82558 | * |
| 82559 | * Very straightforward. The only question is what to return for our |
| 82560 | * non-standard tag / object types. |
| 82561 | * |
| 82562 | * There is an unfortunate string constant define naming problem with |
| 82563 | * typeof return values for e.g. "Object" and "object"; careful with |
| 82564 | * the built-in string defines. The LC_XXX defines are used for the |
| 82565 | * lowercase variants now. |
| 82566 | */ |
| 82567 | |
| 82568 | DUK_INTERNAL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x) { |
| 82569 | duk_small_uint_t stridx = 0; |
| 82570 | |
| 82571 | switch (DUK_TVAL_GET_TAG(tv_x)) { |
| 82572 | case DUK_TAG_UNDEFINED: { |
| 82573 | stridx = DUK_STRIDX_LC_UNDEFINED; |
| 82574 | break; |
| 82575 | } |
| 82576 | case DUK_TAG_NULL: { |
| 82577 | /* Note: not a typo, "object" is returned for a null value. */ |
| 82578 | stridx = DUK_STRIDX_LC_OBJECT; |
| 82579 | break; |
| 82580 | } |
| 82581 | case DUK_TAG_BOOLEAN: { |
| 82582 | stridx = DUK_STRIDX_LC_BOOLEAN; |
| 82583 | break; |
| 82584 | } |
| 82585 | case DUK_TAG_POINTER: { |
| 82586 | /* Implementation specific. */ |
| 82587 | stridx = DUK_STRIDX_LC_POINTER; |
| 82588 | break; |
| 82589 | } |
| 82590 | case DUK_TAG_STRING: { |
| 82591 | duk_hstring *str; |
| 82592 | |
| 82593 | /* All internal keys are identified as Symbols. */ |
| 82594 | str = DUK_TVAL_GET_STRING(tv_x); |
| 82595 | DUK_ASSERT(str != NULL); |
| 82596 | if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) { |
| 82597 | stridx = DUK_STRIDX_LC_SYMBOL; |
| 82598 | } else { |
| 82599 | stridx = DUK_STRIDX_LC_STRING; |
| 82600 | } |
| 82601 | break; |
| 82602 | } |
| 82603 | case DUK_TAG_OBJECT: { |
| 82604 | duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x); |
| 82605 | DUK_ASSERT(obj != NULL); |
| 82606 | if (DUK_HOBJECT_IS_CALLABLE(obj)) { |
| 82607 | stridx = DUK_STRIDX_LC_FUNCTION; |
| 82608 | } else { |
| 82609 | stridx = DUK_STRIDX_LC_OBJECT; |
| 82610 | } |
| 82611 | break; |
| 82612 | } |
| 82613 | case DUK_TAG_BUFFER: { |
| 82614 | /* Implementation specific. In Duktape 1.x this would be |
| 82615 | * 'buffer', in Duktape 2.x changed to 'object' because plain |
| 82616 | * buffers now mimic Uint8Array objects. |
| 82617 | */ |
| 82618 | stridx = DUK_STRIDX_LC_OBJECT; |
| 82619 | break; |
| 82620 | } |
| 82621 | case DUK_TAG_LIGHTFUNC: { |
| 82622 | stridx = DUK_STRIDX_LC_FUNCTION; |
| 82623 | break; |
| 82624 | } |
| 82625 | #if defined(DUK_USE_FASTINT) |
| 82626 | case DUK_TAG_FASTINT: |
| 82627 | #endif |
| 82628 | default: { |
| 82629 | /* number */ |
| 82630 | DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x)); |
| 82631 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x)); |
| 82632 | stridx = DUK_STRIDX_LC_NUMBER; |
| 82633 | break; |
| 82634 | } |
| 82635 | } |
| 82636 | |
| 82637 | DUK_ASSERT_STRIDX_VALID(stridx); |
| 82638 | return stridx; |
| 82639 | } |
| 82640 | |
| 82641 | /* |
| 82642 | * IsArray() |
| 82643 | */ |
| 82644 | |
| 82645 | DUK_INTERNAL duk_bool_t duk_js_isarray_hobject(duk_hobject *h) { |
| 82646 | DUK_ASSERT(h != NULL); |
| 82647 | #if defined(DUK_USE_ES6_PROXY) |
| 82648 | h = duk_hobject_resolve_proxy_target(h); |
| 82649 | #endif |
| 82650 | return (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0); |
| 82651 | } |
| 82652 | |
| 82653 | DUK_INTERNAL duk_bool_t duk_js_isarray(duk_tval *tv) { |
| 82654 | DUK_ASSERT(tv != NULL); |
| 82655 | if (DUK_TVAL_IS_OBJECT(tv)) { |
| 82656 | return duk_js_isarray_hobject(DUK_TVAL_GET_OBJECT(tv)); |
| 82657 | } |
| 82658 | return 0; |
| 82659 | } |
| 82660 | |
| 82661 | /* |
| 82662 | * Array index and length |
| 82663 | * |
| 82664 | * Array index: E5 Section 15.4 |
| 82665 | * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write) |
| 82666 | */ |
| 82667 | |
| 82668 | /* Compure array index from string context, or return a "not array index" |
| 82669 | * indicator. |
| 82670 | */ |
| 82671 | DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) { |
| 82672 | duk_uarridx_t res; |
| 82673 | |
| 82674 | /* Only strings with byte length 1-10 can be 32-bit array indices. |
| 82675 | * Leading zeroes (except '0' alone), plus/minus signs are not allowed. |
| 82676 | * We could do a lot of prechecks here, but since most strings won't |
| 82677 | * start with any digits, it's simpler to just parse the number and |
| 82678 | * fail quickly. |
| 82679 | */ |
| 82680 | |
| 82681 | res = 0; |
| 82682 | if (blen == 0) { |
| 82683 | goto parse_fail; |
| 82684 | } |
| 82685 | do { |
| 82686 | duk_uarridx_t dig; |
| 82687 | dig = (duk_uarridx_t) (*str++) - DUK_ASC_0; |
| 82688 | |
| 82689 | if (dig <= 9U) { |
| 82690 | /* Careful overflow handling. When multiplying by 10: |
| 82691 | * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding |
| 82692 | * 0...9 is safe. |
| 82693 | * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding |
| 82694 | * 0...5 is safe, 6...9 overflows. |
| 82695 | * - 0x1999999a x 10 = 0x100000004: always overflow. |
| 82696 | */ |
| 82697 | if (DUK_UNLIKELY(res >= 0x19999999UL)) { |
| 82698 | if (res >= 0x1999999aUL) { |
| 82699 | /* Always overflow. */ |
| 82700 | goto parse_fail; |
| 82701 | } |
| 82702 | DUK_ASSERT(res == 0x19999999UL); |
| 82703 | if (dig >= 6U) { |
| 82704 | goto parse_fail; |
| 82705 | } |
| 82706 | res = 0xfffffffaUL + dig; |
| 82707 | DUK_ASSERT(res >= 0xfffffffaUL); |
| 82708 | DUK_ASSERT_DISABLE(res <= 0xffffffffUL); /* range */ |
| 82709 | } else { |
| 82710 | res = res * 10U + dig; |
| 82711 | if (DUK_UNLIKELY(res == 0)) { |
| 82712 | /* If 'res' is 0, previous 'res' must |
| 82713 | * have been 0 and we scanned in a zero. |
| 82714 | * This is only allowed if blen == 1, |
| 82715 | * i.e. the exact string '0'. |
| 82716 | */ |
| 82717 | if (blen == (duk_uint32_t) 1) { |
| 82718 | return 0; |
| 82719 | } |
| 82720 | goto parse_fail; |
| 82721 | } |
| 82722 | } |
| 82723 | } else { |
| 82724 | /* Because 'dig' is unsigned, catches both values |
| 82725 | * above '9' and below '0'. |
| 82726 | */ |
| 82727 | goto parse_fail; |
| 82728 | } |
| 82729 | } while (--blen > 0); |
| 82730 | |
| 82731 | return res; |
| 82732 | |
| 82733 | parse_fail: |
| 82734 | return DUK_HSTRING_NO_ARRAY_INDEX; |
| 82735 | } |
| 82736 | |
| 82737 | #if !defined(DUK_USE_HSTRING_ARRIDX) |
| 82738 | /* Get array index for a string which is known to be an array index. This helper |
| 82739 | * is needed when duk_hstring doesn't concretely store the array index, but strings |
| 82740 | * are flagged as array indices at intern time. |
| 82741 | */ |
| 82742 | DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) { |
| 82743 | const duk_uint8_t *p; |
| 82744 | duk_uarridx_t res; |
| 82745 | duk_uint8_t t; |
| 82746 | |
| 82747 | DUK_ASSERT(h != NULL); |
| 82748 | DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h)); |
| 82749 | |
| 82750 | p = DUK_HSTRING_GET_DATA(h); |
| 82751 | res = 0; |
| 82752 | for (;;) { |
| 82753 | t = *p++; |
| 82754 | if (DUK_UNLIKELY(t == 0)) { |
| 82755 | /* Scanning to NUL is always safe for interned strings. */ |
| 82756 | break; |
| 82757 | } |
| 82758 | DUK_ASSERT(t >= (duk_uint8_t) DUK_ASC_0 && t <= (duk_uint8_t) DUK_ASC_9); |
| 82759 | res = res * 10U + (duk_uarridx_t) t - (duk_uarridx_t) DUK_ASC_0; |
| 82760 | } |
| 82761 | return res; |
| 82762 | } |
| 82763 | |
| 82764 | DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) { |
| 82765 | DUK_ASSERT(h != NULL); |
| 82766 | if (!DUK_HSTRING_HAS_ARRIDX(h)) { |
| 82767 | return DUK_HSTRING_NO_ARRAY_INDEX; |
| 82768 | } |
| 82769 | return duk_js_to_arrayindex_hstring_fast_known(h); |
| 82770 | } |
| 82771 | #endif /* DUK_USE_HSTRING_ARRIDX */ |
| 82772 | #line 1 "duk_js_var.c" |
| 82773 | /* |
| 82774 | * Identifier access and function closure handling. |
| 82775 | * |
| 82776 | * Provides the primitives for slow path identifier accesses: GETVAR, |
| 82777 | * PUTVAR, DELVAR, etc. The fast path, direct register accesses, should |
| 82778 | * be used for most identifier accesses. Consequently, these slow path |
| 82779 | * primitives should be optimized for maximum compactness. |
| 82780 | * |
| 82781 | * ECMAScript environment records (declarative and object) are represented |
| 82782 | * as internal objects with control keys. Environment records have a |
| 82783 | * parent record ("outer environment reference") which is represented by |
| 82784 | * the implicit prototype for technical reasons (in other words, it is a |
| 82785 | * convenient field). The prototype chain is not followed in the ordinary |
| 82786 | * sense for variable lookups. |
| 82787 | * |
| 82788 | * See identifier-handling.rst for more details on the identifier algorithms |
| 82789 | * and the internal representation. See function-objects.rst for details on |
| 82790 | * what function templates and instances are expected to look like. |
| 82791 | * |
| 82792 | * Care must be taken to avoid duk_tval pointer invalidation caused by |
| 82793 | * e.g. value stack or object resizing. |
| 82794 | * |
| 82795 | * TODO: properties for function instances could be initialized much more |
| 82796 | * efficiently by creating a property allocation for a certain size and |
| 82797 | * filling in keys and values directly (and INCREFing both with "bulk incref" |
| 82798 | * primitives. |
| 82799 | * |
| 82800 | * XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit |
| 82801 | * awkward (especially because they follow the prototype chain); rework |
| 82802 | * if "raw" own property helpers are added. |
| 82803 | */ |
| 82804 | |
| 82805 | /* #include duk_internal.h -> already included */ |
| 82806 | |
| 82807 | /* |
| 82808 | * Local result type for duk__get_identifier_reference() lookup. |
| 82809 | */ |
| 82810 | |
| 82811 | typedef struct { |
| 82812 | duk_hobject *env; |
| 82813 | duk_hobject *holder; /* for object-bound identifiers */ |
| 82814 | duk_tval *value; /* for register-bound and declarative env identifiers */ |
| 82815 | duk_uint_t attrs; /* property attributes for identifier (relevant if value != NULL) */ |
| 82816 | duk_bool_t has_this; /* for object-bound identifiers: provide 'this' binding */ |
| 82817 | } duk__id_lookup_result; |
| 82818 | |
| 82819 | /* |
| 82820 | * Create a new function object based on a "template function" which contains |
| 82821 | * compiled bytecode, constants, etc, but lacks a lexical environment. |
| 82822 | * |
| 82823 | * ECMAScript requires that each created closure is a separate object, with |
| 82824 | * its own set of editable properties. However, structured property values |
| 82825 | * (such as the formal arguments list and the variable map) are shared. |
| 82826 | * Also the bytecode, constants, and inner functions are shared. |
| 82827 | * |
| 82828 | * See E5 Section 13.2 for detailed requirements on the function objects; |
| 82829 | * there are no similar requirements for function "templates" which are an |
| 82830 | * implementation dependent internal feature. Also see function-objects.rst |
| 82831 | * for a discussion on the function instance properties provided by this |
| 82832 | * implementation. |
| 82833 | * |
| 82834 | * Notes: |
| 82835 | * |
| 82836 | * * Order of internal properties should match frequency of use, since the |
| 82837 | * properties will be linearly scanned on lookup (functions usually don't |
| 82838 | * have enough properties to warrant a hash part). |
| 82839 | * |
| 82840 | * * The created closure is independent of its template; they do share the |
| 82841 | * same 'data' buffer object, but the template object itself can be freed |
| 82842 | * even if the closure object remains reachable. |
| 82843 | */ |
| 82844 | |
| 82845 | DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompfunc *f) { |
| 82846 | duk_tval *tv, *tv_end; |
| 82847 | duk_hobject **funcs, **funcs_end; |
| 82848 | |
| 82849 | DUK_UNREF(thr); |
| 82850 | |
| 82851 | /* If function creation fails due to out-of-memory, the data buffer |
| 82852 | * pointer may be NULL in some cases. That's actually possible for |
| 82853 | * GC code, but shouldn't be possible here because the incomplete |
| 82854 | * function will be unwound from the value stack and never instantiated. |
| 82855 | */ |
| 82856 | DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL); |
| 82857 | |
| 82858 | tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f); |
| 82859 | tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, f); |
| 82860 | while (tv < tv_end) { |
| 82861 | DUK_TVAL_INCREF(thr, tv); |
| 82862 | tv++; |
| 82863 | } |
| 82864 | |
| 82865 | funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, f); |
| 82866 | funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f); |
| 82867 | while (funcs < funcs_end) { |
| 82868 | DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs); |
| 82869 | funcs++; |
| 82870 | } |
| 82871 | } |
| 82872 | |
| 82873 | /* Push a new closure on the stack. |
| 82874 | * |
| 82875 | * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration |
| 82876 | * is created when the function is called, only outer_lex_env matters |
| 82877 | * (outer_var_env is ignored and may or may not be same as outer_lex_env). |
| 82878 | */ |
| 82879 | |
| 82880 | DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = { |
| 82881 | /* order: most frequent to least frequent */ |
| 82882 | DUK_STRIDX_INT_VARMAP, |
| 82883 | DUK_STRIDX_INT_FORMALS, |
| 82884 | #if defined(DUK_USE_PC2LINE) |
| 82885 | DUK_STRIDX_INT_PC2LINE, |
| 82886 | #endif |
| 82887 | #if defined(DUK_USE_FUNC_FILENAME_PROPERTY) |
| 82888 | DUK_STRIDX_FILE_NAME, |
| 82889 | #endif |
| 82890 | #if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY) |
| 82891 | DUK_STRIDX_INT_SOURCE |
| 82892 | #endif |
| 82893 | }; |
| 82894 | |
| 82895 | DUK_INTERNAL |
| 82896 | void duk_js_push_closure(duk_hthread *thr, |
| 82897 | duk_hcompfunc *fun_temp, |
| 82898 | duk_hobject *outer_var_env, |
| 82899 | duk_hobject *outer_lex_env, |
| 82900 | duk_bool_t add_auto_proto) { |
| 82901 | duk_hcompfunc *fun_clos; |
| 82902 | duk_harray *formals; |
| 82903 | duk_small_uint_t i; |
| 82904 | duk_uint_t len_value; |
| 82905 | |
| 82906 | DUK_ASSERT(fun_temp != NULL); |
| 82907 | DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp) != NULL); |
| 82908 | DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp) != NULL); |
| 82909 | DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp) != NULL); |
| 82910 | DUK_ASSERT(outer_var_env != NULL); |
| 82911 | DUK_ASSERT(outer_lex_env != NULL); |
| 82912 | DUK_UNREF(len_value); |
| 82913 | |
| 82914 | DUK_STATS_INC(thr->heap, stats_envrec_pushclosure); |
| 82915 | |
| 82916 | fun_clos = duk_push_hcompfunc(thr); |
| 82917 | DUK_ASSERT(fun_clos != NULL); |
| 82918 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) fun_clos) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 82919 | |
| 82920 | duk_push_hobject(thr, &fun_temp->obj); /* -> [ ... closure template ] */ |
| 82921 | |
| 82922 | DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun_clos)); |
| 82923 | DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) == NULL); |
| 82924 | DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) == NULL); |
| 82925 | DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) == NULL); |
| 82926 | |
| 82927 | DUK_HCOMPFUNC_SET_DATA(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp)); |
| 82928 | DUK_HCOMPFUNC_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp)); |
| 82929 | DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp)); |
| 82930 | |
| 82931 | /* Note: all references inside 'data' need to get their refcounts |
| 82932 | * upped too. This is the case because refcounts are decreased |
| 82933 | * through every function referencing 'data' independently. |
| 82934 | */ |
| 82935 | |
| 82936 | DUK_HBUFFER_INCREF(thr, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos)); |
| 82937 | duk__inc_data_inner_refcounts(thr, fun_temp); |
| 82938 | |
| 82939 | fun_clos->nregs = fun_temp->nregs; |
| 82940 | fun_clos->nargs = fun_temp->nargs; |
| 82941 | #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| 82942 | fun_clos->start_line = fun_temp->start_line; |
| 82943 | fun_clos->end_line = fun_temp->end_line; |
| 82944 | #endif |
| 82945 | |
| 82946 | DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) != NULL); |
| 82947 | DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) != NULL); |
| 82948 | DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) != NULL); |
| 82949 | |
| 82950 | /* XXX: Could also copy from template, but there's no way to have any |
| 82951 | * other value here now (used code has no access to the template). |
| 82952 | * Prototype is set by duk_push_hcompfunc(). |
| 82953 | */ |
| 82954 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 82955 | #if 0 |
| 82956 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 82957 | #endif |
| 82958 | |
| 82959 | /* Copy duk_hobject flags as is from the template using a mask. |
| 82960 | * Leave out duk_heaphdr owned flags just in case (e.g. if there's |
| 82961 | * some GC flag or similar). Some flags can then be adjusted |
| 82962 | * separately if necessary. |
| 82963 | */ |
| 82964 | |
| 82965 | /* DUK_HEAPHDR_SET_FLAGS() masks changes to non-duk_heaphdr flags only. */ |
| 82966 | DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) fun_clos, DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp)); |
| 82967 | DUK_DD(DUK_DDPRINT("fun_temp heaphdr flags: 0x%08lx, fun_clos heaphdr flags: 0x%08lx" , |
| 82968 | (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp), |
| 82969 | (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_clos))); |
| 82970 | |
| 82971 | DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj)); |
| 82972 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj)); |
| 82973 | DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj)); |
| 82974 | DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj)); |
| 82975 | DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj)); |
| 82976 | /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */ |
| 82977 | /* DUK_HOBJECT_FLAG_NEWENV: handled below */ |
| 82978 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj)); |
| 82979 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj)); |
| 82980 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj)); |
| 82981 | |
| 82982 | if (!DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj)) { |
| 82983 | /* If the template is not constructable don't add an automatic |
| 82984 | * .prototype property. This is the case for e.g. ES2015 object |
| 82985 | * literal getters/setters and method definitions. |
| 82986 | */ |
| 82987 | add_auto_proto = 0; |
| 82988 | } |
| 82989 | |
| 82990 | /* |
| 82991 | * Setup environment record properties based on the template and |
| 82992 | * its flags. |
| 82993 | * |
| 82994 | * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment |
| 82995 | * records represent identifiers "outside" the function; the |
| 82996 | * "inner" environment records are created on demand. Otherwise, |
| 82997 | * the environment records are those that will be directly used |
| 82998 | * (e.g. for declarations). |
| 82999 | * |
| 83000 | * _Lexenv is always set; _Varenv defaults to _Lexenv if missing, |
| 83001 | * so _Varenv is only set if _Lexenv != _Varenv. |
| 83002 | * |
| 83003 | * This is relatively complex, see doc/identifier-handling.rst. |
| 83004 | */ |
| 83005 | |
| 83006 | if (DUK_HOBJECT_HAS_NEWENV(&fun_clos->obj)) { |
| 83007 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 83008 | if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) { |
| 83009 | duk_hobject *proto; |
| 83010 | duk_hdecenv *new_env; |
| 83011 | |
| 83012 | /* |
| 83013 | * Named function expression, name needs to be bound |
| 83014 | * in an intermediate environment record. The "outer" |
| 83015 | * lexical/variable environment will thus be: |
| 83016 | * |
| 83017 | * a) { funcname: <func>, __prototype: outer_lex_env } |
| 83018 | * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing) |
| 83019 | */ |
| 83020 | |
| 83021 | if (outer_lex_env) { |
| 83022 | proto = outer_lex_env; |
| 83023 | } else { |
| 83024 | proto = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 83025 | } |
| 83026 | |
| 83027 | /* -> [ ... closure template env ] */ |
| 83028 | new_env = duk_hdecenv_alloc(thr, |
| 83029 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 83030 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); |
| 83031 | DUK_ASSERT(new_env != NULL); |
| 83032 | duk_push_hobject(thr, (duk_hobject *) new_env); |
| 83033 | |
| 83034 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL); |
| 83035 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, proto); |
| 83036 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto); |
| 83037 | |
| 83038 | DUK_ASSERT(new_env->thread == NULL); /* Closed. */ |
| 83039 | DUK_ASSERT(new_env->varmap == NULL); |
| 83040 | |
| 83041 | /* It's important that duk_xdef_prop() is a 'raw define' so that any |
| 83042 | * properties in an ancestor are never an issue (they should never be |
| 83043 | * e.g. non-writable, but just in case). |
| 83044 | * |
| 83045 | * Because template objects are not visible to user code, the case |
| 83046 | * where .name is missing shouldn't happen in practice. It it does, |
| 83047 | * the name 'undefined' gets bound and maps to the closure (which is |
| 83048 | * a bit odd, but safe). |
| 83049 | */ |
| 83050 | (void) duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME); |
| 83051 | /* -> [ ... closure template env funcname ] */ |
| 83052 | duk_dup_m4(thr); /* -> [ ... closure template env funcname closure ] */ |
| 83053 | duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */ |
| 83054 | /* env[funcname] = closure */ |
| 83055 | |
| 83056 | /* [ ... closure template env ] */ |
| 83057 | |
| 83058 | DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env); |
| 83059 | DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env); |
| 83060 | DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); |
| 83061 | DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env); |
| 83062 | duk_pop_unsafe(thr); |
| 83063 | |
| 83064 | /* [ ... closure template ] */ |
| 83065 | } |
| 83066 | else |
| 83067 | #endif /* DUK_USE_FUNC_NAME_PROPERTY */ |
| 83068 | { |
| 83069 | /* |
| 83070 | * Other cases (function declaration, anonymous function expression, |
| 83071 | * strict direct eval code). The "outer" environment will be whatever |
| 83072 | * the caller gave us. |
| 83073 | */ |
| 83074 | |
| 83075 | DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env); |
| 83076 | DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_lex_env); |
| 83077 | DUK_HOBJECT_INCREF(thr, outer_lex_env); |
| 83078 | DUK_HOBJECT_INCREF(thr, outer_lex_env); |
| 83079 | |
| 83080 | /* [ ... closure template ] */ |
| 83081 | } |
| 83082 | } else { |
| 83083 | /* |
| 83084 | * Function gets no new environment when called. This is the |
| 83085 | * case for global code, indirect eval code, and non-strict |
| 83086 | * direct eval code. There is no direct correspondence to the |
| 83087 | * E5 specification, as global/eval code is not exposed as a |
| 83088 | * function. |
| 83089 | */ |
| 83090 | |
| 83091 | DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)); |
| 83092 | |
| 83093 | DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env); |
| 83094 | DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_var_env); |
| 83095 | DUK_HOBJECT_INCREF(thr, outer_lex_env); /* NULLs not allowed; asserted on entry */ |
| 83096 | DUK_HOBJECT_INCREF(thr, outer_var_env); |
| 83097 | } |
| 83098 | DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipO, lexenv -> %!ipO" , |
| 83099 | (duk_heaphdr *) fun_clos->var_env, |
| 83100 | (duk_heaphdr *) fun_clos->lex_env)); |
| 83101 | |
| 83102 | /* Call handling assumes this for all callable closures. */ |
| 83103 | DUK_ASSERT(DUK_HCOMPFUNC_GET_LEXENV(thr->heap, fun_clos) != NULL); |
| 83104 | DUK_ASSERT(DUK_HCOMPFUNC_GET_VARENV(thr->heap, fun_clos) != NULL); |
| 83105 | |
| 83106 | /* |
| 83107 | * Copy some internal properties directly |
| 83108 | * |
| 83109 | * The properties will be non-writable and non-enumerable, but |
| 83110 | * configurable. |
| 83111 | * |
| 83112 | * Function templates are bare objects, so inheritance of internal |
| 83113 | * Symbols is not an issue here even when using ordinary property |
| 83114 | * reads. The function instance created is not bare, so internal |
| 83115 | * Symbols must be defined without inheritance checks. |
| 83116 | */ |
| 83117 | |
| 83118 | /* [ ... closure template ] */ |
| 83119 | |
| 83120 | DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT" , |
| 83121 | (duk_tval *) duk_get_tval(thr, -2), |
| 83122 | (duk_tval *) duk_get_tval(thr, -1))); |
| 83123 | |
| 83124 | for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) { |
| 83125 | duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i]; |
| 83126 | if (duk_xget_owndataprop_stridx_short(thr, -1, stridx)) { |
| 83127 | /* [ ... closure template val ] */ |
| 83128 | DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found" , (long) stridx)); |
| 83129 | duk_xdef_prop_stridx_short(thr, -3, stridx, DUK_PROPDESC_FLAGS_C); |
| 83130 | } else { |
| 83131 | DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found" , (long) stridx)); |
| 83132 | duk_pop_unsafe(thr); |
| 83133 | } |
| 83134 | } |
| 83135 | |
| 83136 | /* |
| 83137 | * "length" maps to number of formals (E5 Section 13.2) for function |
| 83138 | * declarations/expressions (non-bound functions). Note that 'nargs' |
| 83139 | * is NOT necessarily equal to the number of arguments. Use length |
| 83140 | * of _Formals; if missing, assume nargs matches .length. |
| 83141 | */ |
| 83142 | |
| 83143 | /* [ ... closure template ] */ |
| 83144 | |
| 83145 | formals = duk_hobject_get_formals(thr, (duk_hobject *) fun_temp); |
| 83146 | if (formals) { |
| 83147 | len_value = (duk_uint_t) formals->length; |
| 83148 | DUK_DD(DUK_DDPRINT("closure length from _Formals -> %ld" , (long) len_value)); |
| 83149 | } else { |
| 83150 | len_value = fun_temp->nargs; |
| 83151 | DUK_DD(DUK_DDPRINT("closure length defaulted from nargs -> %ld" , (long) len_value)); |
| 83152 | } |
| 83153 | |
| 83154 | duk_push_uint(thr, len_value); /* [ ... closure template len_value ] */ |
| 83155 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); |
| 83156 | |
| 83157 | /* |
| 83158 | * "prototype" is, by default, a fresh object with the "constructor" |
| 83159 | * property. |
| 83160 | * |
| 83161 | * Note that this creates a circular reference for every function |
| 83162 | * instance (closure) which prevents refcount-based collection of |
| 83163 | * function instances. |
| 83164 | * |
| 83165 | * XXX: Try to avoid creating the default prototype object, because |
| 83166 | * many functions are not used as constructors and the default |
| 83167 | * prototype is unnecessary. Perhaps it could be created on-demand |
| 83168 | * when it is first accessed? |
| 83169 | */ |
| 83170 | |
| 83171 | /* [ ... closure template ] */ |
| 83172 | |
| 83173 | if (add_auto_proto) { |
| 83174 | duk_push_object(thr); /* -> [ ... closure template newobj ] */ |
| 83175 | duk_dup_m3(thr); /* -> [ ... closure template newobj closure ] */ |
| 83176 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */ |
| 83177 | duk_compact(thr, -1); /* compact the prototype */ |
| 83178 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */ |
| 83179 | } |
| 83180 | |
| 83181 | /* |
| 83182 | * "arguments" and "caller" must be mapped to throwers for strict |
| 83183 | * mode and bound functions (E5 Section 15.3.5). |
| 83184 | * |
| 83185 | * XXX: This is expensive to have for every strict function instance. |
| 83186 | * Try to implement as virtual properties or on-demand created properties. |
| 83187 | */ |
| 83188 | |
| 83189 | /* [ ... closure template ] */ |
| 83190 | |
| 83191 | if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) { |
| 83192 | duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_CALLER); |
| 83193 | duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_LC_ARGUMENTS); |
| 83194 | } else { |
| 83195 | #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY) |
| 83196 | DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value" )); |
| 83197 | duk_push_null(thr); |
| 83198 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE); |
| 83199 | #else |
| 83200 | DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used" )); |
| 83201 | #endif |
| 83202 | } |
| 83203 | |
| 83204 | /* |
| 83205 | * "name" used to be non-standard but is now defined by ES2015. |
| 83206 | * In ES2015/ES2016 the .name property is configurable. |
| 83207 | */ |
| 83208 | |
| 83209 | /* [ ... closure template ] */ |
| 83210 | |
| 83211 | #if defined(DUK_USE_FUNC_NAME_PROPERTY) |
| 83212 | /* XXX: Look for own property only; doesn't matter much because |
| 83213 | * templates are bare objects. |
| 83214 | */ |
| 83215 | if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME)) { |
| 83216 | /* [ ... closure template name ] */ |
| 83217 | DUK_ASSERT(duk_is_string(thr, -1)); |
| 83218 | DUK_DD(DUK_DDPRINT("setting function instance name to %!T" , duk_get_tval(thr, -1))); |
| 83219 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); /* -> [ ... closure template ] */ |
| 83220 | } else { |
| 83221 | /* Anonymous functions don't have a .name in ES2015, so don't set |
| 83222 | * it on the instance either. The instance will then inherit |
| 83223 | * it from Function.prototype.name. |
| 83224 | */ |
| 83225 | DUK_DD(DUK_DDPRINT("not setting function instance .name" )); |
| 83226 | duk_pop_unsafe(thr); |
| 83227 | } |
| 83228 | #endif |
| 83229 | |
| 83230 | /* |
| 83231 | * Compact the closure, in most cases no properties will be added later. |
| 83232 | * Also, without this the closures end up having unused property slots |
| 83233 | * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used). |
| 83234 | * A better future solution would be to allocate the closure directly |
| 83235 | * to correct size (and setup the properties directly without going |
| 83236 | * through the API). |
| 83237 | */ |
| 83238 | |
| 83239 | duk_compact(thr, -2); |
| 83240 | |
| 83241 | /* |
| 83242 | * Some assertions (E5 Section 13.2). |
| 83243 | */ |
| 83244 | |
| 83245 | DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION); |
| 83246 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]); |
| 83247 | DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj)); |
| 83248 | DUK_ASSERT(duk_has_prop_stridx(thr, -2, DUK_STRIDX_LENGTH) != 0); |
| 83249 | DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(thr, -2, DUK_STRIDX_PROTOTYPE) != 0); |
| 83250 | /* May be missing .name */ |
| 83251 | DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) || |
| 83252 | duk_has_prop_stridx(thr, -2, DUK_STRIDX_CALLER) != 0); |
| 83253 | DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) || |
| 83254 | duk_has_prop_stridx(thr, -2, DUK_STRIDX_LC_ARGUMENTS) != 0); |
| 83255 | |
| 83256 | /* |
| 83257 | * Finish |
| 83258 | */ |
| 83259 | |
| 83260 | /* [ ... closure template ] */ |
| 83261 | |
| 83262 | DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT" , |
| 83263 | (duk_tval *) duk_get_tval(thr, -1), |
| 83264 | (duk_tval *) duk_get_tval(thr, -2))); |
| 83265 | |
| 83266 | duk_pop_unsafe(thr); |
| 83267 | |
| 83268 | /* [ ... closure ] */ |
| 83269 | } |
| 83270 | |
| 83271 | /* |
| 83272 | * Delayed activation environment record initialization (for functions |
| 83273 | * with NEWENV). |
| 83274 | * |
| 83275 | * The non-delayed initialization is handled by duk_handle_call(). |
| 83276 | */ |
| 83277 | |
| 83278 | DUK_LOCAL void duk__preallocate_env_entries(duk_hthread *thr, duk_hobject *varmap, duk_hobject *env) { |
| 83279 | duk_uint_fast32_t i; |
| 83280 | |
| 83281 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { |
| 83282 | duk_hstring *key; |
| 83283 | |
| 83284 | key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); |
| 83285 | DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */ |
| 83286 | DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ |
| 83287 | |
| 83288 | /* Predefine as 'undefined' to reserve a property slot. |
| 83289 | * This makes the unwind process (where register values |
| 83290 | * are copied to the env object) safe against throwing. |
| 83291 | * |
| 83292 | * XXX: This could be made much faster by creating the |
| 83293 | * property table directly. |
| 83294 | */ |
| 83295 | duk_push_undefined(thr); |
| 83296 | DUK_DDD(DUK_DDDPRINT("preallocate env entry for key %!O" , key)); |
| 83297 | duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE); |
| 83298 | } |
| 83299 | } |
| 83300 | |
| 83301 | /* shared helper */ |
| 83302 | DUK_INTERNAL |
| 83303 | duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, |
| 83304 | duk_hobject *func, |
| 83305 | duk_size_t bottom_byteoff) { |
| 83306 | duk_hdecenv *env; |
| 83307 | duk_hobject *parent; |
| 83308 | duk_hcompfunc *f; |
| 83309 | |
| 83310 | DUK_ASSERT(thr != NULL); |
| 83311 | DUK_ASSERT(func != NULL); |
| 83312 | |
| 83313 | DUK_STATS_INC(thr->heap, stats_envrec_create); |
| 83314 | |
| 83315 | f = (duk_hcompfunc *) func; |
| 83316 | parent = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f); |
| 83317 | if (!parent) { |
| 83318 | parent = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 83319 | } |
| 83320 | |
| 83321 | env = duk_hdecenv_alloc(thr, |
| 83322 | DUK_HOBJECT_FLAG_EXTENSIBLE | |
| 83323 | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV)); |
| 83324 | DUK_ASSERT(env != NULL); |
| 83325 | duk_push_hobject(thr, (duk_hobject *) env); |
| 83326 | |
| 83327 | DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL); |
| 83328 | DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent); |
| 83329 | DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent); /* parent env is the prototype */ |
| 83330 | |
| 83331 | /* open scope information, for compiled functions only */ |
| 83332 | |
| 83333 | DUK_ASSERT(env->thread == NULL); |
| 83334 | DUK_ASSERT(env->varmap == NULL); |
| 83335 | DUK_ASSERT(env->regbase_byteoff == 0); |
| 83336 | if (DUK_HOBJECT_IS_COMPFUNC(func)) { |
| 83337 | duk_hobject *varmap; |
| 83338 | |
| 83339 | varmap = duk_hobject_get_varmap(thr, func); |
| 83340 | if (varmap != NULL) { |
| 83341 | env->varmap = varmap; |
| 83342 | DUK_HOBJECT_INCREF(thr, varmap); |
| 83343 | env->thread = thr; |
| 83344 | DUK_HTHREAD_INCREF(thr, thr); |
| 83345 | env->regbase_byteoff = bottom_byteoff; |
| 83346 | |
| 83347 | /* Preallocate env property table to avoid potential |
| 83348 | * for out-of-memory on unwind when the env is closed. |
| 83349 | */ |
| 83350 | duk__preallocate_env_entries(thr, varmap, (duk_hobject *) env); |
| 83351 | } else { |
| 83352 | /* If function has no _Varmap, leave the environment closed. */ |
| 83353 | DUK_ASSERT(env->thread == NULL); |
| 83354 | DUK_ASSERT(env->varmap == NULL); |
| 83355 | DUK_ASSERT(env->regbase_byteoff == 0); |
| 83356 | } |
| 83357 | } |
| 83358 | |
| 83359 | return (duk_hobject *) env; |
| 83360 | } |
| 83361 | |
| 83362 | DUK_INTERNAL |
| 83363 | void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, |
| 83364 | duk_activation *act) { |
| 83365 | duk_hobject *func; |
| 83366 | duk_hobject *env; |
| 83367 | |
| 83368 | DUK_ASSERT(thr != NULL); |
| 83369 | func = DUK_ACT_GET_FUNC(act); |
| 83370 | DUK_ASSERT(func != NULL); |
| 83371 | DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */ |
| 83372 | |
| 83373 | /* |
| 83374 | * Delayed initialization only occurs for 'NEWENV' functions. |
| 83375 | */ |
| 83376 | |
| 83377 | DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func)); |
| 83378 | DUK_ASSERT(act->lex_env == NULL); |
| 83379 | DUK_ASSERT(act->var_env == NULL); |
| 83380 | |
| 83381 | DUK_STATS_INC(thr->heap, stats_envrec_delayedcreate); |
| 83382 | |
| 83383 | env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff); |
| 83384 | DUK_ASSERT(env != NULL); |
| 83385 | /* 'act' is a stable pointer, so still OK. */ |
| 83386 | |
| 83387 | DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO" , (duk_heaphdr *) env)); |
| 83388 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 83389 | { |
| 83390 | duk_hobject *p = env; |
| 83391 | while (p) { |
| 83392 | DUK_DDD(DUK_DDDPRINT(" -> %!ipO" , (duk_heaphdr *) p)); |
| 83393 | p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p); |
| 83394 | } |
| 83395 | } |
| 83396 | #endif |
| 83397 | |
| 83398 | act->lex_env = env; |
| 83399 | act->var_env = env; |
| 83400 | DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */ |
| 83401 | DUK_HOBJECT_INCREF(thr, env); |
| 83402 | |
| 83403 | duk_pop_unsafe(thr); |
| 83404 | } |
| 83405 | |
| 83406 | /* |
| 83407 | * Closing environment records. |
| 83408 | * |
| 83409 | * The environment record MUST be closed with the thread where its activation |
| 83410 | * is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase |
| 83411 | * and varmap must still be valid. On entry, 'env' must be reachable. |
| 83412 | */ |
| 83413 | |
| 83414 | DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) { |
| 83415 | duk_uint_fast32_t i; |
| 83416 | duk_hobject *varmap; |
| 83417 | duk_hstring *key; |
| 83418 | duk_tval *tv; |
| 83419 | duk_uint_t regnum; |
| 83420 | |
| 83421 | DUK_ASSERT(thr != NULL); |
| 83422 | DUK_ASSERT(env != NULL); |
| 83423 | |
| 83424 | if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) { |
| 83425 | DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO" , (duk_heaphdr *) env)); |
| 83426 | return; |
| 83427 | } |
| 83428 | |
| 83429 | varmap = ((duk_hdecenv *) env)->varmap; |
| 83430 | if (varmap == NULL) { |
| 83431 | DUK_DDD(DUK_DDDPRINT("env already closed: %!iO" , (duk_heaphdr *) env)); |
| 83432 | |
| 83433 | return; |
| 83434 | } |
| 83435 | DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL); |
| 83436 | DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) env); |
| 83437 | |
| 83438 | DUK_DDD(DUK_DDDPRINT("closing env: %!iO" , (duk_heaphdr *) env)); |
| 83439 | DUK_DDD(DUK_DDDPRINT("varmap: %!O" , (duk_heaphdr *) varmap)); |
| 83440 | |
| 83441 | /* Env must be closed in the same thread as where it runs. */ |
| 83442 | DUK_ASSERT(((duk_hdecenv *) env)->thread == thr); |
| 83443 | |
| 83444 | /* XXX: additional conditions when to close variables? we don't want to do it |
| 83445 | * unless the environment may have "escaped" (referenced in a function closure). |
| 83446 | * With delayed environments, the existence is probably good enough of a check. |
| 83447 | */ |
| 83448 | |
| 83449 | /* Note: we rely on the _Varmap having a bunch of nice properties, like: |
| 83450 | * - being compacted and unmodified during this process |
| 83451 | * - not containing an array part |
| 83452 | * - having correct value types |
| 83453 | */ |
| 83454 | |
| 83455 | DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs" , (long) DUK_HOBJECT_GET_ENEXT(varmap))); |
| 83456 | |
| 83457 | /* Copy over current variable values from value stack to the |
| 83458 | * environment record. The scope object is empty but may |
| 83459 | * inherit from another scope which has conflicting names. |
| 83460 | */ |
| 83461 | |
| 83462 | /* XXX: Do this using a once allocated entry area, no side effects. |
| 83463 | * Hash part would need special treatment however (maybe copy, and |
| 83464 | * then realloc with hash part if large enough). |
| 83465 | */ |
| 83466 | for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) { |
| 83467 | duk_size_t regbase_byteoff; |
| 83468 | |
| 83469 | key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i); |
| 83470 | DUK_ASSERT(key != NULL); /* assume keys are compact in _Varmap */ |
| 83471 | DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */ |
| 83472 | |
| 83473 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i); |
| 83474 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 83475 | DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ |
| 83476 | #if defined(DUK_USE_FASTINT) |
| 83477 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); |
| 83478 | regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv); |
| 83479 | #else |
| 83480 | regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv); |
| 83481 | #endif |
| 83482 | |
| 83483 | regbase_byteoff = ((duk_hdecenv *) env)->regbase_byteoff; |
| 83484 | DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum >= (duk_uint8_t *) thr->valstack); |
| 83485 | DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum < (duk_uint8_t *) thr->valstack_top); |
| 83486 | |
| 83487 | /* Write register value into env as named properties. |
| 83488 | * If property already exists, overwrites silently. |
| 83489 | * Property is writable, but not deletable (not configurable |
| 83490 | * in terms of property attributes). |
| 83491 | * |
| 83492 | * This property write must not throw because we're unwinding |
| 83493 | * and unwind code is not allowed to throw at present. The |
| 83494 | * call itself has no such guarantees, but we've preallocated |
| 83495 | * entries for each property when the env was created, so no |
| 83496 | * out-of-memory error should be possible. If this guarantee |
| 83497 | * is not provided, problems like GH-476 may happen. |
| 83498 | */ |
| 83499 | duk_push_tval(thr, (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum)); |
| 83500 | DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T" , |
| 83501 | (duk_heaphdr *) key, |
| 83502 | (long) regnum, |
| 83503 | (duk_tval *) duk_get_tval(thr, -1))); |
| 83504 | duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE); |
| 83505 | } |
| 83506 | |
| 83507 | /* NULL atomically to avoid inconsistent state + side effects. */ |
| 83508 | DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread); |
| 83509 | DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap); |
| 83510 | ((duk_hdecenv *) env)->thread = NULL; |
| 83511 | ((duk_hdecenv *) env)->varmap = NULL; |
| 83512 | |
| 83513 | DUK_DDD(DUK_DDDPRINT("env after closing: %!O" , (duk_heaphdr *) env)); |
| 83514 | } |
| 83515 | |
| 83516 | /* |
| 83517 | * GETIDREF: a GetIdentifierReference-like helper. |
| 83518 | * |
| 83519 | * Provides a parent traversing lookup and a single level lookup |
| 83520 | * (for HasBinding). |
| 83521 | * |
| 83522 | * Instead of returning the value, returns a bunch of values allowing |
| 83523 | * the caller to read, write, or delete the binding. Value pointers |
| 83524 | * are duk_tval pointers which can be mutated directly as long as |
| 83525 | * refcounts are properly updated. Note that any operation which may |
| 83526 | * reallocate valstacks or compact objects may invalidate the returned |
| 83527 | * duk_tval (but not object) pointers, so caller must be very careful. |
| 83528 | * |
| 83529 | * If starting environment record 'env' is given, 'act' is ignored. |
| 83530 | * However, if 'env' is NULL, the caller may identify, in 'act', an |
| 83531 | * activation which hasn't had its declarative environment initialized |
| 83532 | * yet. The activation registers are then looked up, and its parent |
| 83533 | * traversed normally. |
| 83534 | * |
| 83535 | * The 'out' structure values are only valid if the function returns |
| 83536 | * success (non-zero). |
| 83537 | */ |
| 83538 | |
| 83539 | /* lookup name from an open declarative record's registers */ |
| 83540 | DUK_LOCAL |
| 83541 | duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr, |
| 83542 | duk_hstring *name, |
| 83543 | duk_hdecenv *env, |
| 83544 | duk__id_lookup_result *out) { |
| 83545 | duk_tval *tv; |
| 83546 | duk_size_t reg_rel; |
| 83547 | |
| 83548 | DUK_ASSERT(thr != NULL); |
| 83549 | DUK_ASSERT(name != NULL); |
| 83550 | DUK_ASSERT(env != NULL); |
| 83551 | DUK_ASSERT(out != NULL); |
| 83552 | |
| 83553 | DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env)); |
| 83554 | DUK_HDECENV_ASSERT_VALID(env); |
| 83555 | |
| 83556 | if (env->thread == NULL) { |
| 83557 | /* already closed */ |
| 83558 | return 0; |
| 83559 | } |
| 83560 | DUK_ASSERT(env->varmap != NULL); |
| 83561 | |
| 83562 | tv = duk_hobject_find_entry_tval_ptr(thr->heap, env->varmap, name); |
| 83563 | if (DUK_UNLIKELY(tv == NULL)) { |
| 83564 | return 0; |
| 83565 | } |
| 83566 | |
| 83567 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 83568 | DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX); /* limits */ |
| 83569 | #if defined(DUK_USE_FASTINT) |
| 83570 | DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv)); |
| 83571 | reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv); |
| 83572 | #else |
| 83573 | reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); |
| 83574 | #endif |
| 83575 | DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */ |
| 83576 | |
| 83577 | tv = (duk_tval *) (void *) ((duk_uint8_t *) env->thread->valstack + env->regbase_byteoff + sizeof(duk_tval) * reg_rel); |
| 83578 | DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end); /* XXX: more accurate? */ |
| 83579 | |
| 83580 | out->value = tv; |
| 83581 | out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ |
| 83582 | out->env = (duk_hobject *) env; |
| 83583 | out->holder = NULL; |
| 83584 | out->has_this = 0; |
| 83585 | return 1; |
| 83586 | } |
| 83587 | |
| 83588 | /* lookup name from current activation record's functions' registers */ |
| 83589 | DUK_LOCAL |
| 83590 | duk_bool_t duk__getid_activation_regs(duk_hthread *thr, |
| 83591 | duk_hstring *name, |
| 83592 | duk_activation *act, |
| 83593 | duk__id_lookup_result *out) { |
| 83594 | duk_tval *tv; |
| 83595 | duk_hobject *func; |
| 83596 | duk_hobject *varmap; |
| 83597 | duk_size_t reg_rel; |
| 83598 | |
| 83599 | DUK_ASSERT(thr != NULL); |
| 83600 | DUK_ASSERT(name != NULL); |
| 83601 | DUK_ASSERT(act != NULL); |
| 83602 | DUK_ASSERT(out != NULL); |
| 83603 | |
| 83604 | func = DUK_ACT_GET_FUNC(act); |
| 83605 | DUK_ASSERT(func != NULL); |
| 83606 | DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func)); |
| 83607 | |
| 83608 | if (!DUK_HOBJECT_IS_COMPFUNC(func)) { |
| 83609 | return 0; |
| 83610 | } |
| 83611 | |
| 83612 | /* XXX: move varmap to duk_hcompfunc struct field? */ |
| 83613 | varmap = duk_hobject_get_varmap(thr, func); |
| 83614 | if (!varmap) { |
| 83615 | return 0; |
| 83616 | } |
| 83617 | |
| 83618 | tv = duk_hobject_find_entry_tval_ptr(thr->heap, varmap, name); |
| 83619 | if (!tv) { |
| 83620 | return 0; |
| 83621 | } |
| 83622 | DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); |
| 83623 | reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv); |
| 83624 | DUK_ASSERT_DISABLE(reg_rel >= 0); |
| 83625 | DUK_ASSERT(reg_rel < ((duk_hcompfunc *) func)->nregs); |
| 83626 | |
| 83627 | tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff); |
| 83628 | tv += reg_rel; |
| 83629 | |
| 83630 | out->value = tv; |
| 83631 | out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */ |
| 83632 | out->env = NULL; |
| 83633 | out->holder = NULL; |
| 83634 | out->has_this = 0; |
| 83635 | return 1; |
| 83636 | } |
| 83637 | |
| 83638 | DUK_LOCAL |
| 83639 | duk_bool_t duk__get_identifier_reference(duk_hthread *thr, |
| 83640 | duk_hobject *env, |
| 83641 | duk_hstring *name, |
| 83642 | duk_activation *act, |
| 83643 | duk_bool_t parents, |
| 83644 | duk__id_lookup_result *out) { |
| 83645 | duk_tval *tv; |
| 83646 | duk_uint_t sanity; |
| 83647 | |
| 83648 | DUK_ASSERT(thr != NULL); |
| 83649 | DUK_ASSERT(env != NULL || act != NULL); |
| 83650 | DUK_ASSERT(name != NULL); |
| 83651 | DUK_ASSERT(out != NULL); |
| 83652 | |
| 83653 | DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env)); |
| 83654 | DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env)); |
| 83655 | |
| 83656 | /* |
| 83657 | * Conceptually, we look for the identifier binding by starting from |
| 83658 | * 'env' and following to chain of environment records (represented |
| 83659 | * by the prototype chain). |
| 83660 | * |
| 83661 | * If 'env' is NULL, the current activation does not yet have an |
| 83662 | * allocated declarative environment record; this should be treated |
| 83663 | * exactly as if the environment record existed but had no bindings |
| 83664 | * other than register bindings. |
| 83665 | * |
| 83666 | * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared |
| 83667 | * the environment will always be initialized immediately; hence |
| 83668 | * a NULL 'env' should only happen with the flag set. This is the |
| 83669 | * case for: (1) function calls, and (2) strict, direct eval calls. |
| 83670 | */ |
| 83671 | |
| 83672 | if (env == NULL && act != NULL) { |
| 83673 | duk_hobject *func; |
| 83674 | duk_hcompfunc *f; |
| 83675 | |
| 83676 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> " |
| 83677 | "delayed env case, look up activation regs first" )); |
| 83678 | |
| 83679 | /* |
| 83680 | * Try registers |
| 83681 | */ |
| 83682 | |
| 83683 | if (duk__getid_activation_regs(thr, name, act, out)) { |
| 83684 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " |
| 83685 | "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " |
| 83686 | "(found from register bindings when env=NULL)" , |
| 83687 | (duk_heaphdr *) name, (duk_tval *) out->value, |
| 83688 | (long) out->attrs, (long) out->has_this, |
| 83689 | (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); |
| 83690 | return 1; |
| 83691 | } |
| 83692 | |
| 83693 | DUK_DDD(DUK_DDDPRINT("not found in current activation regs" )); |
| 83694 | |
| 83695 | /* |
| 83696 | * Not found in registers, proceed to the parent record. |
| 83697 | * Here we need to determine what the parent would be, |
| 83698 | * if 'env' was not NULL (i.e. same logic as when initializing |
| 83699 | * the record). |
| 83700 | * |
| 83701 | * Note that environment initialization is only deferred when |
| 83702 | * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for: |
| 83703 | * - Function code |
| 83704 | * - Strict eval code |
| 83705 | * |
| 83706 | * We only need to check _Lexenv here; _Varenv exists only if it |
| 83707 | * differs from _Lexenv (and thus _Lexenv will also be present). |
| 83708 | */ |
| 83709 | |
| 83710 | if (!parents) { |
| 83711 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal " |
| 83712 | "(not found from register bindings when env=NULL)" )); |
| 83713 | goto fail_not_found; |
| 83714 | } |
| 83715 | |
| 83716 | func = DUK_ACT_GET_FUNC(act); |
| 83717 | DUK_ASSERT(func != NULL); |
| 83718 | DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func)); |
| 83719 | f = (duk_hcompfunc *) func; |
| 83720 | |
| 83721 | env = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f); |
| 83722 | if (!env) { |
| 83723 | env = thr->builtins[DUK_BIDX_GLOBAL_ENV]; |
| 83724 | } |
| 83725 | |
| 83726 | DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO" , |
| 83727 | (duk_heaphdr *) env)); |
| 83728 | } |
| 83729 | |
| 83730 | /* |
| 83731 | * Prototype walking starting from 'env'. |
| 83732 | * |
| 83733 | * ('act' is not needed anywhere here.) |
| 83734 | */ |
| 83735 | |
| 83736 | sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY; |
| 83737 | while (env != NULL) { |
| 83738 | duk_small_uint_t cl; |
| 83739 | duk_uint_t attrs; |
| 83740 | |
| 83741 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO" , |
| 83742 | (duk_heaphdr *) name, |
| 83743 | (void *) env, |
| 83744 | (duk_heaphdr *) env)); |
| 83745 | |
| 83746 | DUK_ASSERT(env != NULL); |
| 83747 | DUK_ASSERT(DUK_HOBJECT_IS_ENV(env)); |
| 83748 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env)); |
| 83749 | |
| 83750 | cl = DUK_HOBJECT_GET_CLASS_NUMBER(env); |
| 83751 | DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV); |
| 83752 | if (cl == DUK_HOBJECT_CLASS_DECENV) { |
| 83753 | /* |
| 83754 | * Declarative environment record. |
| 83755 | * |
| 83756 | * Identifiers can never be stored in ancestors and are |
| 83757 | * always plain values, so we can use an internal helper |
| 83758 | * and access the value directly with an duk_tval ptr. |
| 83759 | * |
| 83760 | * A closed environment is only indicated by it missing |
| 83761 | * the "book-keeping" properties required for accessing |
| 83762 | * register-bound variables. |
| 83763 | */ |
| 83764 | |
| 83765 | DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) env); |
| 83766 | if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) { |
| 83767 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " |
| 83768 | "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " |
| 83769 | "(declarative environment record, scope open, found in regs)" , |
| 83770 | (duk_heaphdr *) name, (duk_tval *) out->value, |
| 83771 | (long) out->attrs, (long) out->has_this, |
| 83772 | (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); |
| 83773 | return 1; |
| 83774 | } |
| 83775 | |
| 83776 | tv = duk_hobject_find_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs); |
| 83777 | if (tv) { |
| 83778 | out->value = tv; |
| 83779 | out->attrs = attrs; |
| 83780 | out->env = env; |
| 83781 | out->holder = env; |
| 83782 | out->has_this = 0; |
| 83783 | |
| 83784 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " |
| 83785 | "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " |
| 83786 | "(declarative environment record, found in properties)" , |
| 83787 | (duk_heaphdr *) name, (duk_tval *) out->value, |
| 83788 | (long) out->attrs, (long) out->has_this, |
| 83789 | (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); |
| 83790 | return 1; |
| 83791 | } |
| 83792 | } else { |
| 83793 | /* |
| 83794 | * Object environment record. |
| 83795 | * |
| 83796 | * Binding (target) object is an external, uncontrolled object. |
| 83797 | * Identifier may be bound in an ancestor property, and may be |
| 83798 | * an accessor. Target can also be a Proxy which we must support |
| 83799 | * here. |
| 83800 | */ |
| 83801 | |
| 83802 | /* XXX: we could save space by using _Target OR _This. If _Target, assume |
| 83803 | * this binding is undefined. If _This, assumes this binding is _This, and |
| 83804 | * target is also _This. One property would then be enough. |
| 83805 | */ |
| 83806 | |
| 83807 | duk_hobject *target; |
| 83808 | duk_bool_t found; |
| 83809 | |
| 83810 | DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV); |
| 83811 | DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) env); |
| 83812 | |
| 83813 | target = ((duk_hobjenv *) env)->target; |
| 83814 | DUK_ASSERT(target != NULL); |
| 83815 | |
| 83816 | /* Target may be a Proxy or property may be an accessor, so we must |
| 83817 | * use an actual, Proxy-aware hasprop check here. |
| 83818 | * |
| 83819 | * out->holder is NOT set to the actual duk_hobject where the |
| 83820 | * property is found, but rather the object binding target object. |
| 83821 | */ |
| 83822 | |
| 83823 | #if defined(DUK_USE_ES6_PROXY) |
| 83824 | if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(target))) { |
| 83825 | duk_tval tv_name; |
| 83826 | duk_tval tv_target_tmp; |
| 83827 | |
| 83828 | DUK_ASSERT(name != NULL); |
| 83829 | DUK_TVAL_SET_STRING(&tv_name, name); |
| 83830 | DUK_TVAL_SET_OBJECT(&tv_target_tmp, target); |
| 83831 | |
| 83832 | found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name); |
| 83833 | } else |
| 83834 | #endif /* DUK_USE_ES6_PROXY */ |
| 83835 | { |
| 83836 | /* XXX: duk_hobject_hasprop() would be correct for |
| 83837 | * non-Proxy objects too, but it is about ~20-25% |
| 83838 | * slower at present so separate code paths for |
| 83839 | * Proxy and non-Proxy now. |
| 83840 | */ |
| 83841 | found = duk_hobject_hasprop_raw(thr, target, name); |
| 83842 | } |
| 83843 | |
| 83844 | if (found) { |
| 83845 | out->value = NULL; /* can't get value, may be accessor */ |
| 83846 | out->attrs = 0; /* irrelevant when out->value == NULL */ |
| 83847 | out->env = env; |
| 83848 | out->holder = target; |
| 83849 | out->has_this = ((duk_hobjenv *) env)->has_this; |
| 83850 | |
| 83851 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: " |
| 83852 | "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O " |
| 83853 | "(object environment record)" , |
| 83854 | (duk_heaphdr *) name, (duk_tval *) out->value, |
| 83855 | (long) out->attrs, (long) out->has_this, |
| 83856 | (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder)); |
| 83857 | return 1; |
| 83858 | } |
| 83859 | } |
| 83860 | |
| 83861 | if (!parents) { |
| 83862 | DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal " |
| 83863 | "(not found from first traversed env)" )); |
| 83864 | goto fail_not_found; |
| 83865 | } |
| 83866 | |
| 83867 | if (DUK_UNLIKELY(sanity-- == 0)) { |
| 83868 | DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT); |
| 83869 | DUK_WO_NORETURN(return 0;); |
| 83870 | } |
| 83871 | env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); |
| 83872 | } |
| 83873 | |
| 83874 | /* |
| 83875 | * Not found (even in global object) |
| 83876 | */ |
| 83877 | |
| 83878 | fail_not_found: |
| 83879 | return 0; |
| 83880 | } |
| 83881 | |
| 83882 | /* |
| 83883 | * HASVAR: check identifier binding from a given environment record |
| 83884 | * without traversing its parents. |
| 83885 | * |
| 83886 | * This primitive is not exposed to user code as such, but is used |
| 83887 | * internally for e.g. declaration binding instantiation. |
| 83888 | * |
| 83889 | * See E5 Sections: |
| 83890 | * 10.2.1.1.1 HasBinding(N) |
| 83891 | * 10.2.1.2.1 HasBinding(N) |
| 83892 | * |
| 83893 | * Note: strictness has no bearing on this check. Hence we don't take |
| 83894 | * a 'strict' parameter. |
| 83895 | */ |
| 83896 | |
| 83897 | #if 0 /*unused*/ |
| 83898 | DUK_INTERNAL |
| 83899 | duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, |
| 83900 | duk_hobject *env, |
| 83901 | duk_hstring *name) { |
| 83902 | duk__id_lookup_result ref; |
| 83903 | duk_bool_t parents; |
| 83904 | |
| 83905 | DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O " |
| 83906 | "(env -> %!dO)" , |
| 83907 | (void *) thr, (void *) env, (duk_heaphdr *) name, |
| 83908 | (duk_heaphdr *) env)); |
| 83909 | |
| 83910 | DUK_ASSERT(thr != NULL); |
| 83911 | DUK_ASSERT(env != NULL); |
| 83912 | DUK_ASSERT(name != NULL); |
| 83913 | |
| 83914 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); |
| 83915 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); |
| 83916 | |
| 83917 | DUK_ASSERT(DUK_HOBJECT_IS_ENV(env)); |
| 83918 | DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env)); |
| 83919 | |
| 83920 | /* lookup results is ignored */ |
| 83921 | parents = 0; |
| 83922 | return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref); |
| 83923 | } |
| 83924 | #endif |
| 83925 | |
| 83926 | /* |
| 83927 | * GETVAR |
| 83928 | * |
| 83929 | * See E5 Sections: |
| 83930 | * 11.1.2 Identifier Reference |
| 83931 | * 10.3.1 Identifier Resolution |
| 83932 | * 11.13.1 Simple Assignment [example of where the Reference is GetValue'd] |
| 83933 | * 8.7.1 GetValue (V) |
| 83934 | * 8.12.1 [[GetOwnProperty]] (P) |
| 83935 | * 8.12.2 [[GetProperty]] (P) |
| 83936 | * 8.12.3 [[Get]] (P) |
| 83937 | * |
| 83938 | * If 'throw' is true, always leaves two values on top of stack: [val this]. |
| 83939 | * |
| 83940 | * If 'throw' is false, returns 0 if identifier cannot be resolved, and the |
| 83941 | * stack will be unaffected in this case. If identifier is resolved, returns |
| 83942 | * 1 and leaves [val this] on top of stack. |
| 83943 | * |
| 83944 | * Note: the 'strict' flag of a reference returned by GetIdentifierReference |
| 83945 | * is ignored by GetValue. Hence we don't take a 'strict' parameter. |
| 83946 | * |
| 83947 | * The 'throw' flag is needed for implementing 'typeof' for an unreferenced |
| 83948 | * identifier. An unreference identifier in other contexts generates a |
| 83949 | * ReferenceError. |
| 83950 | */ |
| 83951 | |
| 83952 | DUK_LOCAL |
| 83953 | duk_bool_t duk__getvar_helper(duk_hthread *thr, |
| 83954 | duk_hobject *env, |
| 83955 | duk_activation *act, |
| 83956 | duk_hstring *name, |
| 83957 | duk_bool_t throw_flag) { |
| 83958 | duk__id_lookup_result ref; |
| 83959 | duk_tval tv_tmp_obj; |
| 83960 | duk_tval tv_tmp_key; |
| 83961 | duk_bool_t parents; |
| 83962 | |
| 83963 | DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O " |
| 83964 | "(env -> %!dO)" , |
| 83965 | (void *) thr, (void *) env, (void *) act, |
| 83966 | (duk_heaphdr *) name, (duk_heaphdr *) env)); |
| 83967 | |
| 83968 | DUK_ASSERT(thr != NULL); |
| 83969 | DUK_ASSERT(name != NULL); |
| 83970 | /* env and act may be NULL */ |
| 83971 | |
| 83972 | DUK_STATS_INC(thr->heap, stats_getvar_all); |
| 83973 | |
| 83974 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); |
| 83975 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); |
| 83976 | |
| 83977 | parents = 1; /* follow parent chain */ |
| 83978 | if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { |
| 83979 | if (ref.value) { |
| 83980 | duk_push_tval(thr, ref.value); |
| 83981 | duk_push_undefined(thr); |
| 83982 | } else { |
| 83983 | DUK_ASSERT(ref.holder != NULL); |
| 83984 | |
| 83985 | /* ref.holder is safe across the getprop call (even |
| 83986 | * with side effects) because 'env' is reachable and |
| 83987 | * ref.holder is a direct heap pointer. |
| 83988 | */ |
| 83989 | |
| 83990 | DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); |
| 83991 | DUK_TVAL_SET_STRING(&tv_tmp_key, name); |
| 83992 | (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [value] */ |
| 83993 | |
| 83994 | if (ref.has_this) { |
| 83995 | duk_push_hobject(thr, ref.holder); |
| 83996 | } else { |
| 83997 | duk_push_undefined(thr); |
| 83998 | } |
| 83999 | |
| 84000 | /* [value this] */ |
| 84001 | } |
| 84002 | |
| 84003 | return 1; |
| 84004 | } else { |
| 84005 | if (throw_flag) { |
| 84006 | DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR, |
| 84007 | "identifier '%s' undefined" , |
| 84008 | (const char *) DUK_HSTRING_GET_DATA(name)); |
| 84009 | DUK_WO_NORETURN(return 0;); |
| 84010 | } |
| 84011 | |
| 84012 | return 0; |
| 84013 | } |
| 84014 | } |
| 84015 | |
| 84016 | DUK_INTERNAL |
| 84017 | duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, |
| 84018 | duk_hobject *env, |
| 84019 | duk_hstring *name, |
| 84020 | duk_bool_t throw_flag) { |
| 84021 | return duk__getvar_helper(thr, env, NULL, name, throw_flag); |
| 84022 | } |
| 84023 | |
| 84024 | DUK_INTERNAL |
| 84025 | duk_bool_t duk_js_getvar_activation(duk_hthread *thr, |
| 84026 | duk_activation *act, |
| 84027 | duk_hstring *name, |
| 84028 | duk_bool_t throw_flag) { |
| 84029 | DUK_ASSERT(act != NULL); |
| 84030 | return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag); |
| 84031 | } |
| 84032 | |
| 84033 | /* |
| 84034 | * PUTVAR |
| 84035 | * |
| 84036 | * See E5 Sections: |
| 84037 | * 11.1.2 Identifier Reference |
| 84038 | * 10.3.1 Identifier Resolution |
| 84039 | * 11.13.1 Simple Assignment [example of where the Reference is PutValue'd] |
| 84040 | * 8.7.2 PutValue (V,W) [see especially step 3.b, undefined -> automatic global in non-strict mode] |
| 84041 | * 8.12.4 [[CanPut]] (P) |
| 84042 | * 8.12.5 [[Put]] (P) |
| 84043 | * |
| 84044 | * Note: may invalidate any valstack (or object) duk_tval pointers because |
| 84045 | * putting a value may reallocate any object or any valstack. Caller beware. |
| 84046 | */ |
| 84047 | |
| 84048 | DUK_LOCAL |
| 84049 | void duk__putvar_helper(duk_hthread *thr, |
| 84050 | duk_hobject *env, |
| 84051 | duk_activation *act, |
| 84052 | duk_hstring *name, |
| 84053 | duk_tval *val, |
| 84054 | duk_bool_t strict) { |
| 84055 | duk__id_lookup_result ref; |
| 84056 | duk_tval tv_tmp_val; |
| 84057 | duk_tval tv_tmp_obj; |
| 84058 | duk_tval tv_tmp_key; |
| 84059 | duk_bool_t parents; |
| 84060 | |
| 84061 | DUK_STATS_INC(thr->heap, stats_putvar_all); |
| 84062 | |
| 84063 | DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld " |
| 84064 | "(env -> %!dO, val -> %!T)" , |
| 84065 | (void *) thr, (void *) env, (void *) act, |
| 84066 | (duk_heaphdr *) name, (void *) val, (long) strict, |
| 84067 | (duk_heaphdr *) env, (duk_tval *) val)); |
| 84068 | |
| 84069 | DUK_ASSERT(thr != NULL); |
| 84070 | DUK_ASSERT(name != NULL); |
| 84071 | DUK_ASSERT(val != NULL); |
| 84072 | /* env and act may be NULL */ |
| 84073 | |
| 84074 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env); |
| 84075 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); |
| 84076 | DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val); |
| 84077 | |
| 84078 | DUK_TVAL_SET_TVAL(&tv_tmp_val, val); /* Stabilize. */ |
| 84079 | val = NULL; |
| 84080 | |
| 84081 | /* |
| 84082 | * In strict mode E5 protects 'eval' and 'arguments' from being |
| 84083 | * assigned to (or even declared anywhere). Attempt to do so |
| 84084 | * should result in a compile time SyntaxError. See the internal |
| 84085 | * design documentation for details. |
| 84086 | * |
| 84087 | * Thus, we should never come here, run-time, for strict code, |
| 84088 | * and name 'eval' or 'arguments'. |
| 84089 | */ |
| 84090 | |
| 84091 | DUK_ASSERT(!strict || |
| 84092 | (name != DUK_HTHREAD_STRING_EVAL(thr) && |
| 84093 | name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr))); |
| 84094 | |
| 84095 | /* |
| 84096 | * Lookup variable and update in-place if found. |
| 84097 | */ |
| 84098 | |
| 84099 | parents = 1; /* follow parent chain */ |
| 84100 | |
| 84101 | if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { |
| 84102 | if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) { |
| 84103 | /* Update duk_tval in-place if pointer provided and the |
| 84104 | * property is writable. If the property is not writable |
| 84105 | * (immutable binding), use duk_hobject_putprop() which |
| 84106 | * will respect mutability. |
| 84107 | */ |
| 84108 | duk_tval *tv_val; |
| 84109 | |
| 84110 | tv_val = ref.value; |
| 84111 | DUK_ASSERT(tv_val != NULL); |
| 84112 | DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, &tv_tmp_val); /* side effects */ |
| 84113 | |
| 84114 | /* ref.value invalidated here */ |
| 84115 | } else { |
| 84116 | DUK_ASSERT(ref.holder != NULL); |
| 84117 | |
| 84118 | DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder); |
| 84119 | DUK_TVAL_SET_STRING(&tv_tmp_key, name); |
| 84120 | (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, &tv_tmp_val, strict); |
| 84121 | |
| 84122 | /* ref.value invalidated here */ |
| 84123 | } |
| 84124 | |
| 84125 | return; |
| 84126 | } |
| 84127 | |
| 84128 | /* |
| 84129 | * Not found: write to global object (non-strict) or ReferenceError |
| 84130 | * (strict); see E5 Section 8.7.2, step 3. |
| 84131 | */ |
| 84132 | |
| 84133 | if (strict) { |
| 84134 | DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error" )); |
| 84135 | DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR, |
| 84136 | "identifier '%s' undefined" , |
| 84137 | (const char *) DUK_HSTRING_GET_DATA(name)); |
| 84138 | DUK_WO_NORETURN(return;); |
| 84139 | } |
| 84140 | |
| 84141 | DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global" )); |
| 84142 | |
| 84143 | DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]); |
| 84144 | DUK_TVAL_SET_STRING(&tv_tmp_key, name); |
| 84145 | (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, &tv_tmp_val, 0); /* 0 = no throw */ |
| 84146 | |
| 84147 | /* NB: 'val' may be invalidated here because put_value may realloc valstack, |
| 84148 | * caller beware. |
| 84149 | */ |
| 84150 | } |
| 84151 | |
| 84152 | DUK_INTERNAL |
| 84153 | void duk_js_putvar_envrec(duk_hthread *thr, |
| 84154 | duk_hobject *env, |
| 84155 | duk_hstring *name, |
| 84156 | duk_tval *val, |
| 84157 | duk_bool_t strict) { |
| 84158 | duk__putvar_helper(thr, env, NULL, name, val, strict); |
| 84159 | } |
| 84160 | |
| 84161 | DUK_INTERNAL |
| 84162 | void duk_js_putvar_activation(duk_hthread *thr, |
| 84163 | duk_activation *act, |
| 84164 | duk_hstring *name, |
| 84165 | duk_tval *val, |
| 84166 | duk_bool_t strict) { |
| 84167 | DUK_ASSERT(act != NULL); |
| 84168 | duk__putvar_helper(thr, act->lex_env, act, name, val, strict); |
| 84169 | } |
| 84170 | |
| 84171 | /* |
| 84172 | * DELVAR |
| 84173 | * |
| 84174 | * See E5 Sections: |
| 84175 | * 11.4.1 The delete operator |
| 84176 | * 10.2.1.1.5 DeleteBinding (N) [declarative environment record] |
| 84177 | * 10.2.1.2.5 DeleteBinding (N) [object environment record] |
| 84178 | * |
| 84179 | * Variable bindings established inside eval() are deletable (configurable), |
| 84180 | * other bindings are not, including variables declared in global level. |
| 84181 | * Registers are always non-deletable, and the deletion of other bindings |
| 84182 | * is controlled by the configurable flag. |
| 84183 | * |
| 84184 | * For strict mode code, the 'delete' operator should fail with a compile |
| 84185 | * time SyntaxError if applied to identifiers. Hence, no strict mode |
| 84186 | * run-time deletion of identifiers should ever happen. This function |
| 84187 | * should never be called from strict mode code! |
| 84188 | */ |
| 84189 | |
| 84190 | DUK_LOCAL |
| 84191 | duk_bool_t duk__delvar_helper(duk_hthread *thr, |
| 84192 | duk_hobject *env, |
| 84193 | duk_activation *act, |
| 84194 | duk_hstring *name) { |
| 84195 | duk__id_lookup_result ref; |
| 84196 | duk_bool_t parents; |
| 84197 | |
| 84198 | DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O " |
| 84199 | "(env -> %!dO)" , |
| 84200 | (void *) thr, (void *) env, (void *) act, |
| 84201 | (duk_heaphdr *) name, (duk_heaphdr *) env)); |
| 84202 | |
| 84203 | DUK_ASSERT(thr != NULL); |
| 84204 | DUK_ASSERT(name != NULL); |
| 84205 | /* env and act may be NULL */ |
| 84206 | |
| 84207 | DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name); |
| 84208 | |
| 84209 | parents = 1; /* follow parent chain */ |
| 84210 | |
| 84211 | if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) { |
| 84212 | if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) { |
| 84213 | /* Identifier found in registers (always non-deletable) |
| 84214 | * or declarative environment record and non-configurable. |
| 84215 | */ |
| 84216 | return 0; |
| 84217 | } |
| 84218 | DUK_ASSERT(ref.holder != NULL); |
| 84219 | |
| 84220 | return duk_hobject_delprop_raw(thr, ref.holder, name, 0); |
| 84221 | } |
| 84222 | |
| 84223 | /* |
| 84224 | * Not found (even in global object). |
| 84225 | * |
| 84226 | * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1, |
| 84227 | * step 3.b. In strict mode this case is a compile time SyntaxError so |
| 84228 | * we should not come here. |
| 84229 | */ |
| 84230 | |
| 84231 | DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O " |
| 84232 | "(treated as silent success)" , |
| 84233 | (duk_heaphdr *) name)); |
| 84234 | return 1; |
| 84235 | } |
| 84236 | |
| 84237 | #if 0 /*unused*/ |
| 84238 | DUK_INTERNAL |
| 84239 | duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, |
| 84240 | duk_hobject *env, |
| 84241 | duk_hstring *name) { |
| 84242 | return duk__delvar_helper(thr, env, NULL, name); |
| 84243 | } |
| 84244 | #endif |
| 84245 | |
| 84246 | DUK_INTERNAL |
| 84247 | duk_bool_t duk_js_delvar_activation(duk_hthread *thr, |
| 84248 | duk_activation *act, |
| 84249 | duk_hstring *name) { |
| 84250 | DUK_ASSERT(act != NULL); |
| 84251 | return duk__delvar_helper(thr, act->lex_env, act, name); |
| 84252 | } |
| 84253 | |
| 84254 | /* |
| 84255 | * DECLVAR |
| 84256 | * |
| 84257 | * See E5 Sections: |
| 84258 | * 10.4.3 Entering Function Code |
| 84259 | * 10.5 Declaration Binding Instantion |
| 84260 | * 12.2 Variable Statement |
| 84261 | * 11.1.2 Identifier Reference |
| 84262 | * 10.3.1 Identifier Resolution |
| 84263 | * |
| 84264 | * Variable declaration behavior is mainly discussed in Section 10.5, |
| 84265 | * and is not discussed in the execution semantics (Sections 11-13). |
| 84266 | * |
| 84267 | * Conceptually declarations happen when code (global, eval, function) |
| 84268 | * is entered, before any user code is executed. In practice, register- |
| 84269 | * bound identifiers are 'declared' automatically (by virtue of being |
| 84270 | * allocated to registers with the initial value 'undefined'). Other |
| 84271 | * identifiers are declared in the function prologue with this primitive. |
| 84272 | * |
| 84273 | * Since non-register bindings eventually back to an internal object's |
| 84274 | * properties, the 'prop_flags' argument is used to specify binding |
| 84275 | * type: |
| 84276 | * |
| 84277 | * - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false |
| 84278 | * - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false |
| 84279 | * - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it |
| 84280 | * doesn't really matter for internal objects |
| 84281 | * |
| 84282 | * All bindings are non-deletable mutable bindings except: |
| 84283 | * |
| 84284 | * - Declarations in eval code (mutable, deletable) |
| 84285 | * - 'arguments' binding in strict function code (immutable) |
| 84286 | * - Function name binding of a function expression (immutable) |
| 84287 | * |
| 84288 | * Declarations may go to declarative environment records (always |
| 84289 | * so for functions), but may also go to object environment records |
| 84290 | * (e.g. global code). The global object environment has special |
| 84291 | * behavior when re-declaring a function (but not a variable); see |
| 84292 | * E5.1 specification, Section 10.5, step 5.e. |
| 84293 | * |
| 84294 | * Declarations always go to the 'top-most' environment record, i.e. |
| 84295 | * we never check the record chain. It's not an error even if a |
| 84296 | * property (even an immutable or non-deletable one) of the same name |
| 84297 | * already exists. |
| 84298 | * |
| 84299 | * If a declared variable already exists, its value needs to be updated |
| 84300 | * (if possible). Returns 1 if a PUTVAR needs to be done by the caller; |
| 84301 | * otherwise returns 0. |
| 84302 | */ |
| 84303 | |
| 84304 | DUK_LOCAL |
| 84305 | duk_bool_t duk__declvar_helper(duk_hthread *thr, |
| 84306 | duk_hobject *env, |
| 84307 | duk_hstring *name, |
| 84308 | duk_tval *val, |
| 84309 | duk_small_uint_t prop_flags, |
| 84310 | duk_bool_t is_func_decl) { |
| 84311 | duk_hobject *holder; |
| 84312 | duk_bool_t parents; |
| 84313 | duk__id_lookup_result ref; |
| 84314 | duk_tval *tv; |
| 84315 | |
| 84316 | DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld " |
| 84317 | "(env -> %!iO)" , |
| 84318 | (void *) thr, (void *) env, (duk_heaphdr *) name, |
| 84319 | (duk_tval *) val, (unsigned long) prop_flags, |
| 84320 | (unsigned int) is_func_decl, (duk_heaphdr *) env)); |
| 84321 | |
| 84322 | DUK_ASSERT(thr != NULL); |
| 84323 | DUK_ASSERT(env != NULL); |
| 84324 | DUK_ASSERT(name != NULL); |
| 84325 | DUK_ASSERT(val != NULL); |
| 84326 | |
| 84327 | /* Note: in strict mode the compiler should reject explicit |
| 84328 | * declaration of 'eval' or 'arguments'. However, internal |
| 84329 | * bytecode may declare 'arguments' in the function prologue. |
| 84330 | * We don't bother checking (or asserting) for these now. |
| 84331 | */ |
| 84332 | |
| 84333 | /* Note: val is a stable duk_tval pointer. The caller makes |
| 84334 | * a value copy into its stack frame, so 'tv_val' is not subject |
| 84335 | * to side effects here. |
| 84336 | */ |
| 84337 | |
| 84338 | /* |
| 84339 | * Check whether already declared. |
| 84340 | * |
| 84341 | * We need to check whether the binding exists in the environment |
| 84342 | * without walking its parents. However, we still need to check |
| 84343 | * register-bound identifiers and the prototype chain of an object |
| 84344 | * environment target object. |
| 84345 | */ |
| 84346 | |
| 84347 | parents = 0; /* just check 'env' */ |
| 84348 | if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) { |
| 84349 | duk_int_t e_idx; |
| 84350 | duk_int_t h_idx; |
| 84351 | duk_small_uint_t flags; |
| 84352 | |
| 84353 | /* |
| 84354 | * Variable already declared, ignore re-declaration. |
| 84355 | * The only exception is the updated behavior of E5.1 for |
| 84356 | * global function declarations, E5.1 Section 10.5, step 5.e. |
| 84357 | * This behavior does not apply to global variable declarations. |
| 84358 | */ |
| 84359 | |
| 84360 | if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) { |
| 84361 | DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring" )); |
| 84362 | return 1; /* 1 -> needs a PUTVAR */ |
| 84363 | } |
| 84364 | |
| 84365 | /* |
| 84366 | * Special behavior in E5.1. |
| 84367 | * |
| 84368 | * Note that even though parents == 0, the conflicting property |
| 84369 | * may be an inherited property (currently our global object's |
| 84370 | * prototype is Object.prototype). Step 5.e first operates on |
| 84371 | * the existing property (which is potentially in an ancestor) |
| 84372 | * and then defines a new property in the global object (and |
| 84373 | * never modifies the ancestor). |
| 84374 | * |
| 84375 | * Also note that this logic would become even more complicated |
| 84376 | * if the conflicting property might be a virtual one. Object |
| 84377 | * prototype has no virtual properties, though. |
| 84378 | * |
| 84379 | * XXX: this is now very awkward, rework. |
| 84380 | */ |
| 84381 | |
| 84382 | DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, " |
| 84383 | "updated E5.1 processing" )); |
| 84384 | |
| 84385 | DUK_ASSERT(ref.holder != NULL); |
| 84386 | holder = ref.holder; |
| 84387 | |
| 84388 | /* holder will be set to the target object, not the actual object |
| 84389 | * where the property was found (see duk__get_identifier_reference()). |
| 84390 | */ |
| 84391 | DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL); |
| 84392 | DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */ |
| 84393 | |
| 84394 | /* XXX: use a helper for prototype traversal; no loop check here */ |
| 84395 | /* must be found: was found earlier, and cannot be inherited */ |
| 84396 | for (;;) { |
| 84397 | DUK_ASSERT(holder != NULL); |
| 84398 | if (duk_hobject_find_entry(thr->heap, holder, name, &e_idx, &h_idx)) { |
| 84399 | DUK_ASSERT(e_idx >= 0); |
| 84400 | break; |
| 84401 | } |
| 84402 | /* SCANBUILD: NULL pointer dereference, doesn't actually trigger, |
| 84403 | * asserted above. |
| 84404 | */ |
| 84405 | holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder); |
| 84406 | } |
| 84407 | DUK_ASSERT(holder != NULL); |
| 84408 | DUK_ASSERT(e_idx >= 0); |
| 84409 | /* SCANBUILD: scan-build produces a NULL pointer dereference warning |
| 84410 | * below; it never actually triggers because holder is actually never |
| 84411 | * NULL. |
| 84412 | */ |
| 84413 | |
| 84414 | /* ref.holder is global object, holder is the object with the |
| 84415 | * conflicting property. |
| 84416 | */ |
| 84417 | |
| 84418 | flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx); |
| 84419 | if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) { |
| 84420 | if (flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 84421 | DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable " |
| 84422 | "accessor -> reject" )); |
| 84423 | goto fail_existing_attributes; |
| 84424 | } |
| 84425 | if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) && |
| 84426 | (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) { |
| 84427 | DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable " |
| 84428 | "plain property which is not writable and " |
| 84429 | "enumerable -> reject" )); |
| 84430 | goto fail_existing_attributes; |
| 84431 | } |
| 84432 | |
| 84433 | DUK_DDD(DUK_DDDPRINT("existing property is not configurable but " |
| 84434 | "is plain, enumerable, and writable -> " |
| 84435 | "allow redeclaration" )); |
| 84436 | } |
| 84437 | |
| 84438 | if (holder == ref.holder) { |
| 84439 | /* XXX: if duk_hobject_define_property_internal() was updated |
| 84440 | * to handle a pre-existing accessor property, this would be |
| 84441 | * a simple call (like for the ancestor case). |
| 84442 | */ |
| 84443 | DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself" )); |
| 84444 | |
| 84445 | if (flags & DUK_PROPDESC_FLAG_ACCESSOR) { |
| 84446 | duk_hobject *tmp; |
| 84447 | |
| 84448 | tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx); |
| 84449 | DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL); |
| 84450 | DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); |
| 84451 | DUK_UNREF(tmp); |
| 84452 | tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx); |
| 84453 | DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL); |
| 84454 | DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); |
| 84455 | DUK_UNREF(tmp); |
| 84456 | } else { |
| 84457 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx); |
| 84458 | DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); |
| 84459 | } |
| 84460 | |
| 84461 | /* Here val would be potentially invalid if we didn't make |
| 84462 | * a value copy at the caller. |
| 84463 | */ |
| 84464 | |
| 84465 | tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx); |
| 84466 | DUK_TVAL_SET_TVAL(tv, val); |
| 84467 | DUK_TVAL_INCREF(thr, tv); |
| 84468 | DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags); |
| 84469 | |
| 84470 | DUK_DDD(DUK_DDDPRINT("updated global binding, final result: " |
| 84471 | "value -> %!T, prop_flags=0x%08lx" , |
| 84472 | (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx), |
| 84473 | (unsigned long) prop_flags)); |
| 84474 | } else { |
| 84475 | DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor" )); |
| 84476 | |
| 84477 | DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]); |
| 84478 | duk_push_tval(thr, val); |
| 84479 | duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags); |
| 84480 | } |
| 84481 | |
| 84482 | return 0; |
| 84483 | } |
| 84484 | |
| 84485 | /* |
| 84486 | * Not found (in registers or record objects). Declare |
| 84487 | * to current variable environment. |
| 84488 | */ |
| 84489 | |
| 84490 | /* |
| 84491 | * Get holder object |
| 84492 | */ |
| 84493 | |
| 84494 | if (DUK_HOBJECT_IS_DECENV(env)) { |
| 84495 | DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) env); |
| 84496 | holder = env; |
| 84497 | } else { |
| 84498 | DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) env); |
| 84499 | holder = ((duk_hobjenv *) env)->target; |
| 84500 | DUK_ASSERT(holder != NULL); |
| 84501 | } |
| 84502 | |
| 84503 | /* |
| 84504 | * Define new property |
| 84505 | * |
| 84506 | * Note: this may fail if the holder is not extensible. |
| 84507 | */ |
| 84508 | |
| 84509 | /* XXX: this is awkward as we use an internal method which doesn't handle |
| 84510 | * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]] |
| 84511 | * or Object.defineProperty() here. |
| 84512 | */ |
| 84513 | |
| 84514 | if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) { |
| 84515 | goto fail_not_extensible; |
| 84516 | } |
| 84517 | |
| 84518 | duk_push_hobject(thr, holder); |
| 84519 | duk_push_hstring(thr, name); |
| 84520 | duk_push_tval(thr, val); |
| 84521 | duk_xdef_prop(thr, -3, prop_flags); /* [holder name val] -> [holder] */ |
| 84522 | duk_pop_unsafe(thr); |
| 84523 | |
| 84524 | return 0; |
| 84525 | |
| 84526 | fail_existing_attributes: |
| 84527 | fail_not_extensible: |
| 84528 | DUK_ERROR_TYPE(thr, "declaration failed" ); |
| 84529 | DUK_WO_NORETURN(return 0;); |
| 84530 | } |
| 84531 | |
| 84532 | DUK_INTERNAL |
| 84533 | duk_bool_t duk_js_declvar_activation(duk_hthread *thr, |
| 84534 | duk_activation *act, |
| 84535 | duk_hstring *name, |
| 84536 | duk_tval *val, |
| 84537 | duk_small_uint_t prop_flags, |
| 84538 | duk_bool_t is_func_decl) { |
| 84539 | duk_hobject *env; |
| 84540 | duk_tval tv_val_copy; |
| 84541 | |
| 84542 | DUK_ASSERT(act != NULL); |
| 84543 | |
| 84544 | /* |
| 84545 | * Make a value copy of the input val. This ensures that |
| 84546 | * side effects cannot invalidate the pointer. |
| 84547 | */ |
| 84548 | |
| 84549 | DUK_TVAL_SET_TVAL(&tv_val_copy, val); |
| 84550 | val = &tv_val_copy; |
| 84551 | |
| 84552 | /* |
| 84553 | * Delayed env creation check |
| 84554 | */ |
| 84555 | |
| 84556 | if (!act->var_env) { |
| 84557 | DUK_ASSERT(act->lex_env == NULL); |
| 84558 | duk_js_init_activation_environment_records_delayed(thr, act); |
| 84559 | /* 'act' is a stable pointer, so still OK. */ |
| 84560 | } |
| 84561 | DUK_ASSERT(act->lex_env != NULL); |
| 84562 | DUK_ASSERT(act->var_env != NULL); |
| 84563 | |
| 84564 | env = act->var_env; |
| 84565 | DUK_ASSERT(env != NULL); |
| 84566 | DUK_ASSERT(DUK_HOBJECT_IS_ENV(env)); |
| 84567 | |
| 84568 | return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl); |
| 84569 | } |
| 84570 | #line 1 "duk_lexer.c" |
| 84571 | /* |
| 84572 | * Lexer for source files, ToNumber() string conversions, RegExp expressions, |
| 84573 | * and JSON. |
| 84574 | * |
| 84575 | * Provides a stream of ECMAScript tokens from an UTF-8/CESU-8 buffer. The |
| 84576 | * caller can also rewind the token stream into a certain position which is |
| 84577 | * needed by the compiler part for multi-pass scanning. Tokens are |
| 84578 | * represented as duk_token structures, and contain line number information. |
| 84579 | * Token types are identified with DUK_TOK_* defines. |
| 84580 | * |
| 84581 | * Characters are decoded into a fixed size lookup window consisting of |
| 84582 | * decoded Unicode code points, with window positions past the end of the |
| 84583 | * input filled with an invalid codepoint (-1). The tokenizer can thus |
| 84584 | * perform multiple character lookups efficiently and with few sanity |
| 84585 | * checks (such as access outside the end of the input), which keeps the |
| 84586 | * tokenization code small at the cost of performance. |
| 84587 | * |
| 84588 | * Character data in tokens, such as identifier names and string literals, |
| 84589 | * is encoded into CESU-8 format on-the-fly while parsing the token in |
| 84590 | * question. The string data is made reachable to garbage collection by |
| 84591 | * placing the token-related values in value stack entries allocated for |
| 84592 | * this purpose by the caller. The characters exist in Unicode code point |
| 84593 | * form only in the fixed size lookup window, which keeps character data |
| 84594 | * expansion (of especially ASCII data) low. |
| 84595 | * |
| 84596 | * Token parsing supports the full range of Unicode characters as described |
| 84597 | * in the E5 specification. Parsing has been optimized for ASCII characters |
| 84598 | * because ordinary ECMAScript code consists almost entirely of ASCII |
| 84599 | * characters. Matching of complex Unicode codepoint sets (such as in the |
| 84600 | * IdentifierStart and IdentifierPart productions) is optimized for size, |
| 84601 | * and is done using a linear scan of a bit-packed list of ranges. This is |
| 84602 | * very slow, but should never be entered unless the source code actually |
| 84603 | * contains Unicode characters. |
| 84604 | * |
| 84605 | * ECMAScript tokenization is partially context sensitive. First, |
| 84606 | * additional future reserved words are recognized in strict mode (see E5 |
| 84607 | * Section 7.6.1.2). Second, a forward slash character ('/') can be |
| 84608 | * recognized either as starting a RegExp literal or as a division operator, |
| 84609 | * depending on context. The caller must provide necessary context flags |
| 84610 | * when requesting a new token. |
| 84611 | * |
| 84612 | * Future work: |
| 84613 | * |
| 84614 | * * Make line number tracking optional, as it consumes space. |
| 84615 | * |
| 84616 | * * Add a feature flag for disabling UTF-8 decoding of input, as most |
| 84617 | * source code is ASCII. Because of Unicode escapes written in ASCII, |
| 84618 | * this does not allow Unicode support to be removed from e.g. |
| 84619 | * duk_unicode_is_identifier_start() nor does it allow removal of CESU-8 |
| 84620 | * encoding of e.g. string literals. |
| 84621 | * |
| 84622 | * * Add a feature flag for disabling Unicode compliance of e.g. identifier |
| 84623 | * names. This allows for a build more than a kilobyte smaller, because |
| 84624 | * Unicode ranges needed by duk_unicode_is_identifier_start() and |
| 84625 | * duk_unicode_is_identifier_part() can be dropped. String literals |
| 84626 | * should still be allowed to contain escaped Unicode, so this still does |
| 84627 | * not allow removal of CESU-8 encoding of e.g. string literals. |
| 84628 | * |
| 84629 | * * Character lookup tables for codepoints above BMP could be stripped. |
| 84630 | * |
| 84631 | * * Strictly speaking, E5 specification requires that source code consists |
| 84632 | * of 16-bit code units, and if not, must be conceptually converted to |
| 84633 | * that format first. The current lexer processes Unicode code points |
| 84634 | * and allows characters outside the BMP. These should be converted to |
| 84635 | * surrogate pairs while reading the source characters into the window, |
| 84636 | * not after tokens have been formed (as is done now). However, the fix |
| 84637 | * is not trivial because two characters are decoded from one codepoint. |
| 84638 | * |
| 84639 | * * Optimize for speed as well as size. Large if-else ladders are (at |
| 84640 | * least potentially) slow. |
| 84641 | */ |
| 84642 | |
| 84643 | /* #include duk_internal.h -> already included */ |
| 84644 | |
| 84645 | /* |
| 84646 | * Various defines and file specific helper macros |
| 84647 | */ |
| 84648 | |
| 84649 | #define DUK__MAX_RE_DECESC_DIGITS 9 |
| 84650 | #define DUK__MAX_RE_QUANT_DIGITS 9 /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */ |
| 84651 | |
| 84652 | /* whether to use macros or helper function depends on call count */ |
| 84653 | #define DUK__ISDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9) |
| 84654 | #define DUK__ISHEXDIGIT(x) duk__is_hex_digit((x)) |
| 84655 | #define DUK__ISOCTDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7) |
| 84656 | #define DUK__ISDIGIT03(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3) |
| 84657 | #define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7) |
| 84658 | |
| 84659 | /* lexer character window helpers */ |
| 84660 | #define DUK__LOOKUP(lex_ctx,idx) ((lex_ctx)->window[(idx)].codepoint) |
| 84661 | #define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_chars((lex_ctx), (count)) |
| 84662 | #define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count)) |
| 84663 | #define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx)) |
| 84664 | #define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x)) |
| 84665 | #define DUK__APPENDBUFFER_ASCII(lex_ctx,x) duk__appendbuffer_ascii((lex_ctx), (duk_codepoint_t) (x)) |
| 84666 | |
| 84667 | /* lookup shorthands (note: assume context variable is named 'lex_ctx') */ |
| 84668 | #define DUK__L0() DUK__LOOKUP(lex_ctx, 0) |
| 84669 | #define DUK__L1() DUK__LOOKUP(lex_ctx, 1) |
| 84670 | #define DUK__L2() DUK__LOOKUP(lex_ctx, 2) |
| 84671 | #define DUK__L3() DUK__LOOKUP(lex_ctx, 3) |
| 84672 | #define DUK__L4() DUK__LOOKUP(lex_ctx, 4) |
| 84673 | #define DUK__L5() DUK__LOOKUP(lex_ctx, 5) |
| 84674 | |
| 84675 | /* packed advance/token number macro used by multiple functions */ |
| 84676 | #define DUK__ADVTOK(advbytes,tok) ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok)) |
| 84677 | |
| 84678 | /* |
| 84679 | * Advance lookup window by N characters, filling in new characters as |
| 84680 | * necessary. After returning caller is guaranteed a character window of |
| 84681 | * at least DUK_LEXER_WINDOW_SIZE characters. |
| 84682 | * |
| 84683 | * The main function duk__advance_bytes() is called at least once per every |
| 84684 | * token so it has a major lexer/compiler performance impact. There are two |
| 84685 | * variants for the main duk__advance_bytes() algorithm: a sliding window |
| 84686 | * approach which is slightly faster at the cost of larger code footprint, |
| 84687 | * and a simple copying one. |
| 84688 | * |
| 84689 | * Decoding directly from the source string would be another lexing option. |
| 84690 | * But the lookup window based approach has the advantage of hiding the |
| 84691 | * source string and its encoding effectively which gives more flexibility |
| 84692 | * going forward to e.g. support chunked streaming of source from flash. |
| 84693 | * |
| 84694 | * Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to |
| 84695 | * U+10FFFF, causing an error if the input is unparseable. Leniency means: |
| 84696 | * |
| 84697 | * * Unicode code point validation is intentionally not performed, |
| 84698 | * except to check that the codepoint does not exceed 0x10ffff. |
| 84699 | * |
| 84700 | * * In particular, surrogate pairs are allowed and not combined, which |
| 84701 | * allows source files to represent all SourceCharacters with CESU-8. |
| 84702 | * Broken surrogate pairs are allowed, as ECMAScript does not mandate |
| 84703 | * their validation. |
| 84704 | * |
| 84705 | * * Allow non-shortest UTF-8 encodings. |
| 84706 | * |
| 84707 | * Leniency here causes few security concerns because all character data is |
| 84708 | * decoded into Unicode codepoints before lexer processing, and is then |
| 84709 | * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with |
| 84710 | * a compiler option. However, ECMAScript source characters include -all- |
| 84711 | * 16-bit unsigned integer codepoints, so leniency seems to be appropriate. |
| 84712 | * |
| 84713 | * Note that codepoints above the BMP are not strictly SourceCharacters, |
| 84714 | * but the lexer still accepts them as such. Before ending up in a string |
| 84715 | * or an identifier name, codepoints above BMP are converted into surrogate |
| 84716 | * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as |
| 84717 | * expected by ECMAScript. |
| 84718 | * |
| 84719 | * An alternative approach to dealing with invalid or partial sequences |
| 84720 | * would be to skip them and replace them with e.g. the Unicode replacement |
| 84721 | * character U+FFFD. This has limited utility because a replacement character |
| 84722 | * will most likely cause a parse error, unless it occurs inside a string. |
| 84723 | * Further, ECMAScript source is typically pure ASCII. |
| 84724 | * |
| 84725 | * See: |
| 84726 | * |
| 84727 | * http://en.wikipedia.org/wiki/UTF-8 |
| 84728 | * http://en.wikipedia.org/wiki/CESU-8 |
| 84729 | * http://tools.ietf.org/html/rfc3629 |
| 84730 | * http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences |
| 84731 | * |
| 84732 | * Future work: |
| 84733 | * |
| 84734 | * * Reject other invalid Unicode sequences (see Wikipedia entry for examples) |
| 84735 | * in strict UTF-8 mode. |
| 84736 | * |
| 84737 | * * Size optimize. An attempt to use a 16-byte lookup table for the first |
| 84738 | * byte resulted in a code increase though. |
| 84739 | * |
| 84740 | * * Is checking against maximum 0x10ffff really useful? 4-byte encoding |
| 84741 | * imposes a certain limit anyway. |
| 84742 | * |
| 84743 | * * Support chunked streaming of source code. Can be implemented either |
| 84744 | * by streaming chunks of bytes or chunks of codepoints. |
| 84745 | */ |
| 84746 | |
| 84747 | #if defined(DUK_USE_LEXER_SLIDING_WINDOW) |
| 84748 | DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) { |
| 84749 | duk_lexer_codepoint *cp, *cp_end; |
| 84750 | duk_ucodepoint_t x; |
| 84751 | duk_small_uint_t contlen; |
| 84752 | const duk_uint8_t *p, *p_end; |
| 84753 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84754 | duk_ucodepoint_t mincp; |
| 84755 | #endif |
| 84756 | duk_int_t input_line; |
| 84757 | |
| 84758 | /* Use temporaries and update lex_ctx only when finished. */ |
| 84759 | input_line = lex_ctx->input_line; |
| 84760 | p = lex_ctx->input + lex_ctx->input_offset; |
| 84761 | p_end = lex_ctx->input + lex_ctx->input_length; |
| 84762 | |
| 84763 | cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes); |
| 84764 | cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE; |
| 84765 | |
| 84766 | for (; cp != cp_end; cp++) { |
| 84767 | cp->offset = (duk_size_t) (p - lex_ctx->input); |
| 84768 | cp->line = input_line; |
| 84769 | |
| 84770 | /* XXX: potential issue with signed pointers, p_end < p. */ |
| 84771 | if (DUK_UNLIKELY(p >= p_end)) { |
| 84772 | /* If input_offset were assigned a negative value, it would |
| 84773 | * result in a large positive value. Most likely it would be |
| 84774 | * larger than input_length and be caught here. In any case |
| 84775 | * no memory unsafe behavior would happen. |
| 84776 | */ |
| 84777 | cp->codepoint = -1; |
| 84778 | continue; |
| 84779 | } |
| 84780 | |
| 84781 | x = (duk_ucodepoint_t) (*p++); |
| 84782 | |
| 84783 | /* Fast path. */ |
| 84784 | |
| 84785 | if (DUK_LIKELY(x < 0x80UL)) { |
| 84786 | DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */ |
| 84787 | if (DUK_UNLIKELY(x <= 0x000dUL)) { |
| 84788 | if ((x == 0x000aUL) || |
| 84789 | ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) { |
| 84790 | /* lookup for 0x000a above assumes shortest encoding now */ |
| 84791 | |
| 84792 | /* E5 Section 7.3, treat the following as newlines: |
| 84793 | * LF |
| 84794 | * CR [not followed by LF] |
| 84795 | * LS |
| 84796 | * PS |
| 84797 | * |
| 84798 | * For CR LF, CR is ignored if it is followed by LF, and the LF will bump |
| 84799 | * the line number. |
| 84800 | */ |
| 84801 | input_line++; |
| 84802 | } |
| 84803 | } |
| 84804 | |
| 84805 | cp->codepoint = (duk_codepoint_t) x; |
| 84806 | continue; |
| 84807 | } |
| 84808 | |
| 84809 | /* Slow path. */ |
| 84810 | |
| 84811 | if (x < 0xc0UL) { |
| 84812 | /* 10xx xxxx -> invalid */ |
| 84813 | goto error_encoding; |
| 84814 | } else if (x < 0xe0UL) { |
| 84815 | /* 110x xxxx 10xx xxxx */ |
| 84816 | contlen = 1; |
| 84817 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84818 | mincp = 0x80UL; |
| 84819 | #endif |
| 84820 | x = x & 0x1fUL; |
| 84821 | } else if (x < 0xf0UL) { |
| 84822 | /* 1110 xxxx 10xx xxxx 10xx xxxx */ |
| 84823 | contlen = 2; |
| 84824 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84825 | mincp = 0x800UL; |
| 84826 | #endif |
| 84827 | x = x & 0x0fUL; |
| 84828 | } else if (x < 0xf8UL) { |
| 84829 | /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */ |
| 84830 | contlen = 3; |
| 84831 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84832 | mincp = 0x10000UL; |
| 84833 | #endif |
| 84834 | x = x & 0x07UL; |
| 84835 | } else { |
| 84836 | /* no point in supporting encodings of 5 or more bytes */ |
| 84837 | goto error_encoding; |
| 84838 | } |
| 84839 | |
| 84840 | DUK_ASSERT(p_end >= p); |
| 84841 | if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) { |
| 84842 | goto error_clipped; |
| 84843 | } |
| 84844 | |
| 84845 | while (contlen > 0) { |
| 84846 | duk_small_uint_t y; |
| 84847 | y = *p++; |
| 84848 | if ((y & 0xc0U) != 0x80U) { |
| 84849 | /* check that byte has the form 10xx xxxx */ |
| 84850 | goto error_encoding; |
| 84851 | } |
| 84852 | x = x << 6; |
| 84853 | x += y & 0x3fUL; |
| 84854 | contlen--; |
| 84855 | } |
| 84856 | |
| 84857 | /* check final character validity */ |
| 84858 | |
| 84859 | if (x > 0x10ffffUL) { |
| 84860 | goto error_encoding; |
| 84861 | } |
| 84862 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84863 | if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) { |
| 84864 | goto error_encoding; |
| 84865 | } |
| 84866 | #endif |
| 84867 | |
| 84868 | DUK_ASSERT(x != 0x000aUL && x != 0x000dUL); |
| 84869 | if ((x == 0x2028UL) || (x == 0x2029UL)) { |
| 84870 | input_line++; |
| 84871 | } |
| 84872 | |
| 84873 | cp->codepoint = (duk_codepoint_t) x; |
| 84874 | } |
| 84875 | |
| 84876 | lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input); |
| 84877 | lex_ctx->input_line = input_line; |
| 84878 | return; |
| 84879 | |
| 84880 | error_clipped: /* clipped codepoint */ |
| 84881 | error_encoding: /* invalid codepoint encoding or codepoint */ |
| 84882 | lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input); |
| 84883 | lex_ctx->input_line = input_line; |
| 84884 | |
| 84885 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED); |
| 84886 | DUK_WO_NORETURN(return;); |
| 84887 | } |
| 84888 | |
| 84889 | DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) { |
| 84890 | duk_small_uint_t used_bytes, avail_bytes; |
| 84891 | |
| 84892 | DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */ |
| 84893 | DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))); |
| 84894 | DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer); |
| 84895 | DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE); |
| 84896 | DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint)); |
| 84897 | |
| 84898 | /* Zero 'count' is also allowed to make call sites easier. |
| 84899 | * Arithmetic in bytes generates better code in GCC. |
| 84900 | */ |
| 84901 | |
| 84902 | lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes); /* avoid multiply */ |
| 84903 | used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer); |
| 84904 | avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes; |
| 84905 | if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) { |
| 84906 | /* Not enough data to provide a full window, so "scroll" window to |
| 84907 | * start of buffer and fill up the rest. |
| 84908 | */ |
| 84909 | duk_memmove((void *) lex_ctx->buffer, |
| 84910 | (const void *) lex_ctx->window, |
| 84911 | (size_t) avail_bytes); |
| 84912 | lex_ctx->window = lex_ctx->buffer; |
| 84913 | duk__fill_lexer_buffer(lex_ctx, avail_bytes); |
| 84914 | } |
| 84915 | } |
| 84916 | |
| 84917 | DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) { |
| 84918 | lex_ctx->window = lex_ctx->buffer; |
| 84919 | duk__fill_lexer_buffer(lex_ctx, 0); |
| 84920 | } |
| 84921 | #else /* DUK_USE_LEXER_SLIDING_WINDOW */ |
| 84922 | DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) { |
| 84923 | duk_ucodepoint_t x; |
| 84924 | duk_small_uint_t len; |
| 84925 | duk_small_uint_t i; |
| 84926 | const duk_uint8_t *p; |
| 84927 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84928 | duk_ucodepoint_t mincp; |
| 84929 | #endif |
| 84930 | duk_size_t input_offset; |
| 84931 | |
| 84932 | input_offset = lex_ctx->input_offset; |
| 84933 | if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) { |
| 84934 | /* If input_offset were assigned a negative value, it would |
| 84935 | * result in a large positive value. Most likely it would be |
| 84936 | * larger than input_length and be caught here. In any case |
| 84937 | * no memory unsafe behavior would happen. |
| 84938 | */ |
| 84939 | return -1; |
| 84940 | } |
| 84941 | |
| 84942 | p = lex_ctx->input + input_offset; |
| 84943 | x = (duk_ucodepoint_t) (*p); |
| 84944 | |
| 84945 | if (DUK_LIKELY(x < 0x80UL)) { |
| 84946 | /* 0xxx xxxx -> fast path */ |
| 84947 | |
| 84948 | /* input offset tracking */ |
| 84949 | lex_ctx->input_offset++; |
| 84950 | |
| 84951 | DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */ |
| 84952 | if (DUK_UNLIKELY(x <= 0x000dUL)) { |
| 84953 | if ((x == 0x000aUL) || |
| 84954 | ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length || |
| 84955 | lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) { |
| 84956 | /* lookup for 0x000a above assumes shortest encoding now */ |
| 84957 | |
| 84958 | /* E5 Section 7.3, treat the following as newlines: |
| 84959 | * LF |
| 84960 | * CR [not followed by LF] |
| 84961 | * LS |
| 84962 | * PS |
| 84963 | * |
| 84964 | * For CR LF, CR is ignored if it is followed by LF, and the LF will bump |
| 84965 | * the line number. |
| 84966 | */ |
| 84967 | lex_ctx->input_line++; |
| 84968 | } |
| 84969 | } |
| 84970 | |
| 84971 | return (duk_codepoint_t) x; |
| 84972 | } |
| 84973 | |
| 84974 | /* Slow path. */ |
| 84975 | |
| 84976 | if (x < 0xc0UL) { |
| 84977 | /* 10xx xxxx -> invalid */ |
| 84978 | goto error_encoding; |
| 84979 | } else if (x < 0xe0UL) { |
| 84980 | /* 110x xxxx 10xx xxxx */ |
| 84981 | len = 2; |
| 84982 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84983 | mincp = 0x80UL; |
| 84984 | #endif |
| 84985 | x = x & 0x1fUL; |
| 84986 | } else if (x < 0xf0UL) { |
| 84987 | /* 1110 xxxx 10xx xxxx 10xx xxxx */ |
| 84988 | len = 3; |
| 84989 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84990 | mincp = 0x800UL; |
| 84991 | #endif |
| 84992 | x = x & 0x0fUL; |
| 84993 | } else if (x < 0xf8UL) { |
| 84994 | /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */ |
| 84995 | len = 4; |
| 84996 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 84997 | mincp = 0x10000UL; |
| 84998 | #endif |
| 84999 | x = x & 0x07UL; |
| 85000 | } else { |
| 85001 | /* no point in supporting encodings of 5 or more bytes */ |
| 85002 | goto error_encoding; |
| 85003 | } |
| 85004 | |
| 85005 | DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset); |
| 85006 | if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) { |
| 85007 | goto error_clipped; |
| 85008 | } |
| 85009 | |
| 85010 | p++; |
| 85011 | for (i = 1; i < len; i++) { |
| 85012 | duk_small_uint_t y; |
| 85013 | y = *p++; |
| 85014 | if ((y & 0xc0U) != 0x80U) { |
| 85015 | /* check that byte has the form 10xx xxxx */ |
| 85016 | goto error_encoding; |
| 85017 | } |
| 85018 | x = x << 6; |
| 85019 | x += y & 0x3fUL; |
| 85020 | } |
| 85021 | |
| 85022 | /* check final character validity */ |
| 85023 | |
| 85024 | if (x > 0x10ffffUL) { |
| 85025 | goto error_encoding; |
| 85026 | } |
| 85027 | #if defined(DUK_USE_STRICT_UTF8_SOURCE) |
| 85028 | if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) { |
| 85029 | goto error_encoding; |
| 85030 | } |
| 85031 | #endif |
| 85032 | |
| 85033 | /* input offset tracking */ |
| 85034 | lex_ctx->input_offset += len; |
| 85035 | |
| 85036 | /* line tracking */ |
| 85037 | DUK_ASSERT(x != 0x000aUL && x != 0x000dUL); |
| 85038 | if ((x == 0x2028UL) || (x == 0x2029UL)) { |
| 85039 | lex_ctx->input_line++; |
| 85040 | } |
| 85041 | |
| 85042 | return (duk_codepoint_t) x; |
| 85043 | |
| 85044 | error_clipped: /* clipped codepoint */ |
| 85045 | error_encoding: /* invalid codepoint encoding or codepoint */ |
| 85046 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED); |
| 85047 | DUK_WO_NORETURN(return 0;); |
| 85048 | } |
| 85049 | |
| 85050 | DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) { |
| 85051 | duk_small_uint_t keep_bytes; |
| 85052 | duk_lexer_codepoint *cp, *cp_end; |
| 85053 | |
| 85054 | DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */ |
| 85055 | DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))); |
| 85056 | |
| 85057 | /* Zero 'count' is also allowed to make call sites easier. */ |
| 85058 | |
| 85059 | keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes; |
| 85060 | duk_memmove((void *) lex_ctx->window, |
| 85061 | (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes), |
| 85062 | (size_t) keep_bytes); |
| 85063 | |
| 85064 | cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes); |
| 85065 | cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE; |
| 85066 | for (; cp != cp_end; cp++) { |
| 85067 | cp->offset = lex_ctx->input_offset; |
| 85068 | cp->line = lex_ctx->input_line; |
| 85069 | cp->codepoint = duk__read_char(lex_ctx); |
| 85070 | } |
| 85071 | } |
| 85072 | |
| 85073 | DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) { |
| 85074 | /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */ |
| 85075 | duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)); /* fill window */ |
| 85076 | } |
| 85077 | #endif /* DUK_USE_LEXER_SLIDING_WINDOW */ |
| 85078 | |
| 85079 | DUK_LOCAL void duk__advance_chars(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_chars) { |
| 85080 | duk__advance_bytes(lex_ctx, count_chars * sizeof(duk_lexer_codepoint)); |
| 85081 | } |
| 85082 | |
| 85083 | /* |
| 85084 | * (Re)initialize the temporary byte buffer. May be called extra times |
| 85085 | * with little impact. |
| 85086 | */ |
| 85087 | |
| 85088 | DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) { |
| 85089 | /* Reuse buffer as is unless buffer has grown large. */ |
| 85090 | if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) { |
| 85091 | /* Keep current size */ |
| 85092 | } else { |
| 85093 | duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT); |
| 85094 | } |
| 85095 | |
| 85096 | DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf); |
| 85097 | } |
| 85098 | |
| 85099 | /* |
| 85100 | * Append a Unicode codepoint to the temporary byte buffer. Performs |
| 85101 | * CESU-8 surrogate pair encoding for codepoints above the BMP. |
| 85102 | * Existing surrogate pairs are allowed and also encoded into CESU-8. |
| 85103 | */ |
| 85104 | |
| 85105 | DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) { |
| 85106 | /* |
| 85107 | * Since character data is only generated by decoding the source or by |
| 85108 | * the compiler itself, we rely on the input codepoints being correct |
| 85109 | * and avoid a check here. |
| 85110 | * |
| 85111 | * Character data can also come here through decoding of Unicode |
| 85112 | * escapes ("\udead\ubeef") so all 16-but unsigned values can be |
| 85113 | * present, even when the source file itself is strict UTF-8. |
| 85114 | */ |
| 85115 | DUK_ASSERT(x >= 0 && x <= 0x10ffffL); |
| 85116 | |
| 85117 | DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x); |
| 85118 | } |
| 85119 | |
| 85120 | DUK_LOCAL void duk__appendbuffer_ascii(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) { |
| 85121 | /* ASCII characters can be emitted as a single byte without encoding |
| 85122 | * which matters for some fast paths. |
| 85123 | */ |
| 85124 | DUK_ASSERT(x >= 0 && x <= 0x7f); |
| 85125 | |
| 85126 | DUK_BW_WRITE_ENSURE_U8(lex_ctx->thr, &lex_ctx->bw, (duk_uint8_t) x); |
| 85127 | } |
| 85128 | |
| 85129 | /* |
| 85130 | * Intern the temporary byte buffer into a valstack slot |
| 85131 | * (in practice, slot1 or slot2). |
| 85132 | */ |
| 85133 | |
| 85134 | DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) { |
| 85135 | DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx); |
| 85136 | |
| 85137 | DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw); |
| 85138 | duk_replace(lex_ctx->thr, valstack_idx); |
| 85139 | return duk_known_hstring(lex_ctx->thr, valstack_idx); |
| 85140 | } |
| 85141 | |
| 85142 | /* |
| 85143 | * Init lexer context |
| 85144 | */ |
| 85145 | |
| 85146 | DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) { |
| 85147 | DUK_ASSERT(lex_ctx != NULL); |
| 85148 | |
| 85149 | duk_memzero(lex_ctx, sizeof(*lex_ctx)); |
| 85150 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 85151 | #if defined(DUK_USE_LEXER_SLIDING_WINDOW) |
| 85152 | lex_ctx->window = NULL; |
| 85153 | #endif |
| 85154 | lex_ctx->thr = NULL; |
| 85155 | lex_ctx->input = NULL; |
| 85156 | lex_ctx->buf = NULL; |
| 85157 | #endif |
| 85158 | } |
| 85159 | |
| 85160 | /* |
| 85161 | * Set lexer input position and reinitialize lookup window. |
| 85162 | */ |
| 85163 | |
| 85164 | DUK_INTERNAL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) { |
| 85165 | pt->offset = lex_ctx->window[0].offset; |
| 85166 | pt->line = lex_ctx->window[0].line; |
| 85167 | } |
| 85168 | |
| 85169 | DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) { |
| 85170 | DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */ |
| 85171 | DUK_ASSERT(pt->line >= 1); |
| 85172 | lex_ctx->input_offset = pt->offset; |
| 85173 | lex_ctx->input_line = pt->line; |
| 85174 | duk__init_lexer_window(lex_ctx); |
| 85175 | } |
| 85176 | |
| 85177 | /* |
| 85178 | * Lexing helpers |
| 85179 | */ |
| 85180 | |
| 85181 | /* Numeric value of a hex digit (also covers octal and decimal digits) or |
| 85182 | * -1 if not a valid hex digit. |
| 85183 | */ |
| 85184 | DUK_LOCAL duk_codepoint_t duk__hexval_validate(duk_codepoint_t x) { |
| 85185 | duk_small_int_t t; |
| 85186 | |
| 85187 | /* Here 'x' is a Unicode codepoint */ |
| 85188 | if (DUK_LIKELY(x >= 0 && x <= 0xff)) { |
| 85189 | t = duk_hex_dectab[x]; |
| 85190 | if (DUK_LIKELY(t >= 0)) { |
| 85191 | return t; |
| 85192 | } |
| 85193 | } |
| 85194 | |
| 85195 | return -1; |
| 85196 | } |
| 85197 | |
| 85198 | /* Just a wrapper for call sites where 'x' is known to be valid so |
| 85199 | * we assert for it before decoding. |
| 85200 | */ |
| 85201 | DUK_LOCAL duk_codepoint_t duk__hexval(duk_codepoint_t x) { |
| 85202 | duk_codepoint_t ret; |
| 85203 | |
| 85204 | DUK_ASSERT((x >= DUK_ASC_0 && x <= DUK_ASC_9) || |
| 85205 | (x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_F) || |
| 85206 | (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_F)); |
| 85207 | ret = duk__hexval_validate(x); |
| 85208 | DUK_ASSERT(ret >= 0 && ret <= 15); |
| 85209 | return ret; |
| 85210 | } |
| 85211 | |
| 85212 | /* having this as a separate function provided a size benefit */ |
| 85213 | DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) { |
| 85214 | if (DUK_LIKELY(x >= 0 && x <= 0xff)) { |
| 85215 | return (duk_hex_dectab[x] >= 0); |
| 85216 | } |
| 85217 | return 0; |
| 85218 | } |
| 85219 | |
| 85220 | /* Parse a Unicode escape of the form \xHH, \uHHHH, or \u{H+}. Shared by |
| 85221 | * source and RegExp parsing. |
| 85222 | */ |
| 85223 | DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bool_t allow_es6) { |
| 85224 | duk_small_int_t digits; /* Initial value 2 or 4 for fixed length escapes, 0 for ES2015 \u{H+}. */ |
| 85225 | duk_codepoint_t escval; |
| 85226 | duk_codepoint_t x; |
| 85227 | duk_small_uint_t adv; |
| 85228 | |
| 85229 | DUK_ASSERT(DUK__L0() == DUK_ASC_BACKSLASH); /* caller responsibilities */ |
| 85230 | DUK_ASSERT(DUK__L1() == DUK_ASC_LC_X || DUK__L1() == DUK_ASC_LC_U); |
| 85231 | DUK_UNREF(allow_es6); |
| 85232 | |
| 85233 | adv = 2; |
| 85234 | digits = 2; |
| 85235 | if (DUK__L1() == DUK_ASC_LC_U) { |
| 85236 | digits = 4; |
| 85237 | #if defined(DUK_USE_ES6_UNICODE_ESCAPE) |
| 85238 | if (DUK__L2() == DUK_ASC_LCURLY && allow_es6) { |
| 85239 | digits = 0; |
| 85240 | adv = 3; |
| 85241 | } |
| 85242 | #endif |
| 85243 | } |
| 85244 | DUK__ADVANCECHARS(lex_ctx, adv); |
| 85245 | |
| 85246 | escval = 0; |
| 85247 | for (;;) { |
| 85248 | /* One of the escape forms: \xHH, \uHHHH, \u{H+}. |
| 85249 | * The 'digits' variable tracks parsing state and is |
| 85250 | * initialized to: |
| 85251 | * |
| 85252 | * \xHH 2 |
| 85253 | * \uHH 4 |
| 85254 | * \u{H+} 0 first time, updated to -1 to indicate |
| 85255 | * at least one digit has been parsed |
| 85256 | * |
| 85257 | * Octal parsing is handled separately because it can be |
| 85258 | * done with fixed lookahead and also has validation |
| 85259 | * rules which depend on the escape length (which is |
| 85260 | * variable). |
| 85261 | * |
| 85262 | * We don't need a specific check for x < 0 (end of |
| 85263 | * input) or duk_unicode_is_line_terminator(x) |
| 85264 | * because the 'dig' decode will fail and lead to a |
| 85265 | * SyntaxError. |
| 85266 | */ |
| 85267 | duk_codepoint_t dig; |
| 85268 | |
| 85269 | x = DUK__L0(); |
| 85270 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 85271 | |
| 85272 | dig = duk__hexval_validate(x); |
| 85273 | if (digits > 0) { |
| 85274 | digits--; |
| 85275 | if (dig < 0) { |
| 85276 | goto fail_escape; |
| 85277 | } |
| 85278 | DUK_ASSERT(dig >= 0x00 && dig <= 0x0f); |
| 85279 | escval = (escval << 4) + dig; |
| 85280 | if (digits == 0) { |
| 85281 | DUK_ASSERT(escval >= 0 && escval <= 0xffffL); |
| 85282 | break; |
| 85283 | } |
| 85284 | } else { |
| 85285 | #if defined(DUK_USE_ES6_UNICODE_ESCAPE) |
| 85286 | DUK_ASSERT(digits == 0 /* first time */ || digits == -1 /* others */); |
| 85287 | if (dig >= 0) { |
| 85288 | DUK_ASSERT(dig >= 0x00 && dig <= 0x0f); |
| 85289 | escval = (escval << 4) + dig; |
| 85290 | if (escval > 0x10ffffL) { |
| 85291 | goto fail_escape; |
| 85292 | } |
| 85293 | } else if (x == DUK_ASC_RCURLY) { |
| 85294 | if (digits == 0) { |
| 85295 | /* Empty escape, \u{}. */ |
| 85296 | goto fail_escape; |
| 85297 | } |
| 85298 | DUK_ASSERT(escval >= 0 && escval <= 0x10ffffL); |
| 85299 | break; |
| 85300 | } else { |
| 85301 | goto fail_escape; |
| 85302 | } |
| 85303 | digits = -1; /* Indicate we have at least one digit. */ |
| 85304 | #else /* DUK_USE_ES6_UNICODE_ESCAPE */ |
| 85305 | DUK_ASSERT(0); /* Never happens if \u{H+} support disabled. */ |
| 85306 | #endif /* DUK_USE_ES6_UNICODE_ESCAPE */ |
| 85307 | } |
| 85308 | } |
| 85309 | |
| 85310 | return escval; |
| 85311 | |
| 85312 | fail_escape: |
| 85313 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); |
| 85314 | DUK_WO_NORETURN(return 0;); |
| 85315 | } |
| 85316 | |
| 85317 | /* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377. Maximum |
| 85318 | * allowed value is \0377 (U+00FF), longest match is used. Used for both string |
| 85319 | * RegExp octal escape parsing. Window[0] must be the slash '\' and the first |
| 85320 | * digit must already be validated to be in [0-9] by the caller. |
| 85321 | */ |
| 85322 | DUK_LOCAL duk_codepoint_t duk__lexer_parse_legacy_octal(duk_lexer_ctx *lex_ctx, duk_small_uint_t *out_adv, duk_bool_t reject_annex_b) { |
| 85323 | duk_codepoint_t cp; |
| 85324 | duk_small_uint_t lookup_idx; |
| 85325 | duk_small_uint_t adv; |
| 85326 | duk_codepoint_t tmp; |
| 85327 | |
| 85328 | DUK_ASSERT(out_adv != NULL); |
| 85329 | DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH); |
| 85330 | DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9); |
| 85331 | |
| 85332 | cp = 0; |
| 85333 | tmp = 0; |
| 85334 | for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) { |
| 85335 | DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld" , (long) lookup_idx, (long) cp)); |
| 85336 | tmp = DUK__LOOKUP(lex_ctx, lookup_idx); |
| 85337 | if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) { |
| 85338 | /* No more valid digits. */ |
| 85339 | break; |
| 85340 | } |
| 85341 | tmp = (cp << 3) + (tmp - DUK_ASC_0); |
| 85342 | if (tmp > 0xff) { |
| 85343 | /* Three digit octal escapes above \377 (= 0xff) |
| 85344 | * are not allowed. |
| 85345 | */ |
| 85346 | break; |
| 85347 | } |
| 85348 | cp = tmp; |
| 85349 | } |
| 85350 | DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld" , (long) lookup_idx, (long) cp)); |
| 85351 | |
| 85352 | adv = lookup_idx; |
| 85353 | if (lookup_idx == 1) { |
| 85354 | DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too" )); |
| 85355 | DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9); |
| 85356 | cp = tmp; |
| 85357 | adv++; /* correction to above, eat offending character */ |
| 85358 | } else if (lookup_idx == 2 && cp == 0) { |
| 85359 | /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not. |
| 85360 | * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError. |
| 85361 | */ |
| 85362 | DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too" )); |
| 85363 | } else { |
| 85364 | /* This clause also handles non-shortest zero, e.g. \00. */ |
| 85365 | if (reject_annex_b) { |
| 85366 | DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode" , (long) cp)); |
| 85367 | cp = -1; |
| 85368 | } else { |
| 85369 | DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted" , (long) cp)); |
| 85370 | DUK_ASSERT(cp >= 0 && cp <= 0xff); |
| 85371 | } |
| 85372 | } |
| 85373 | |
| 85374 | *out_adv = adv; |
| 85375 | |
| 85376 | DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b)); |
| 85377 | return cp; |
| 85378 | } |
| 85379 | |
| 85380 | /* XXX: move strict mode to lex_ctx? */ |
| 85381 | DUK_LOCAL void duk__lexer_parse_string_literal(duk_lexer_ctx *lex_ctx, duk_token *out_token, duk_small_int_t quote, duk_bool_t strict_mode) { |
| 85382 | duk_small_uint_t adv; |
| 85383 | |
| 85384 | for (adv = 1 /* initial quote */ ;;) { |
| 85385 | duk_codepoint_t x; |
| 85386 | |
| 85387 | DUK__ADVANCECHARS(lex_ctx, adv); /* eat opening quote on first loop */ |
| 85388 | x = DUK__L0(); |
| 85389 | |
| 85390 | adv = 1; |
| 85391 | if (x == quote) { |
| 85392 | DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */ |
| 85393 | break; |
| 85394 | } else if (x == '\\') { |
| 85395 | /* DUK__L0 -> '\' char |
| 85396 | * DUK__L1 ... DUK__L5 -> more lookup |
| 85397 | */ |
| 85398 | duk_small_int_t emitcp = -1; |
| 85399 | |
| 85400 | x = DUK__L1(); |
| 85401 | |
| 85402 | /* How much to advance before next loop. */ |
| 85403 | adv = 2; /* note: long live range */ |
| 85404 | |
| 85405 | switch (x) { |
| 85406 | case '\'': |
| 85407 | emitcp = 0x0027; |
| 85408 | break; |
| 85409 | case '"': |
| 85410 | emitcp = 0x0022; |
| 85411 | break; |
| 85412 | case '\\': |
| 85413 | emitcp = 0x005c; |
| 85414 | break; |
| 85415 | case 'b': |
| 85416 | emitcp = 0x0008; |
| 85417 | break; |
| 85418 | case 'f': |
| 85419 | emitcp = 0x000c; |
| 85420 | break; |
| 85421 | case 'n': |
| 85422 | emitcp = 0x000a; |
| 85423 | break; |
| 85424 | case 'r': |
| 85425 | emitcp = 0x000d; |
| 85426 | break; |
| 85427 | case 't': |
| 85428 | emitcp = 0x0009; |
| 85429 | break; |
| 85430 | case 'v': |
| 85431 | emitcp = 0x000b; |
| 85432 | break; |
| 85433 | case 'x': |
| 85434 | case 'u': { |
| 85435 | duk_codepoint_t esc_cp; |
| 85436 | esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/); |
| 85437 | DUK__APPENDBUFFER(lex_ctx, esc_cp); |
| 85438 | adv = 0; |
| 85439 | break; |
| 85440 | } |
| 85441 | default: { |
| 85442 | if (duk_unicode_is_line_terminator(x)) { |
| 85443 | /* line continuation */ |
| 85444 | if (x == 0x000d && DUK__L2() == 0x000a) { |
| 85445 | /* CR LF again a special case */ |
| 85446 | adv = 3; /* line terminator, CR, LF */ |
| 85447 | } |
| 85448 | } else if (DUK__ISDIGIT(x)) { |
| 85449 | /* |
| 85450 | * Octal escape or zero escape: |
| 85451 | * \0 (lookahead not OctalDigit) |
| 85452 | * \1 ... \7 (lookahead not OctalDigit) |
| 85453 | * \ZeroToThree OctalDigit (lookahead not OctalDigit) |
| 85454 | * \FourToSeven OctalDigit (no lookahead restrictions) |
| 85455 | * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions) |
| 85456 | * |
| 85457 | * Zero escape is part of the standard syntax. Octal escapes are |
| 85458 | * defined in E5 Section B.1.2, and are only allowed in non-strict mode. |
| 85459 | * Any other productions starting with a decimal digit are invalid |
| 85460 | * but are in practice treated like identity escapes. |
| 85461 | * |
| 85462 | * Parse octal (up to 3 digits) from the lookup window. |
| 85463 | */ |
| 85464 | |
| 85465 | emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/); |
| 85466 | if (emitcp < 0) { |
| 85467 | goto fail_escape; |
| 85468 | } |
| 85469 | } else if (x < 0) { |
| 85470 | goto fail_unterminated; |
| 85471 | } else { |
| 85472 | /* escaped NonEscapeCharacter */ |
| 85473 | DUK__APPENDBUFFER(lex_ctx, x); |
| 85474 | } |
| 85475 | } /* end default clause */ |
| 85476 | } /* end switch */ |
| 85477 | |
| 85478 | /* Shared handling for single codepoint escapes. */ |
| 85479 | if (emitcp >= 0) { |
| 85480 | DUK__APPENDBUFFER(lex_ctx, emitcp); |
| 85481 | } |
| 85482 | |
| 85483 | /* Track number of escapes; count not really needed but directive |
| 85484 | * prologues need to detect whether there were any escapes or line |
| 85485 | * continuations or not. |
| 85486 | */ |
| 85487 | out_token->num_escapes++; |
| 85488 | } else if (x >= 0x20 && x <= 0x7f) { |
| 85489 | /* Fast path for ASCII case, avoids line terminator |
| 85490 | * check and CESU-8 encoding. |
| 85491 | */ |
| 85492 | DUK_ASSERT(x >= 0); |
| 85493 | DUK_ASSERT(!duk_unicode_is_line_terminator(x)); |
| 85494 | DUK_ASSERT(x != quote); |
| 85495 | DUK_ASSERT(x != DUK_ASC_BACKSLASH); |
| 85496 | DUK__APPENDBUFFER_ASCII(lex_ctx, x); |
| 85497 | } else if (x < 0 || duk_unicode_is_line_terminator(x)) { |
| 85498 | goto fail_unterminated; |
| 85499 | } else { |
| 85500 | /* Character which is part of the string but wasn't handled |
| 85501 | * by the fast path. |
| 85502 | */ |
| 85503 | DUK__APPENDBUFFER(lex_ctx, x); |
| 85504 | } |
| 85505 | } /* string parse loop */ |
| 85506 | |
| 85507 | return; |
| 85508 | |
| 85509 | fail_escape: |
| 85510 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); |
| 85511 | DUK_WO_NORETURN(return;); |
| 85512 | |
| 85513 | fail_unterminated: |
| 85514 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_STRING); |
| 85515 | DUK_WO_NORETURN(return;); |
| 85516 | } |
| 85517 | |
| 85518 | /* Skip to end-of-line (or end-of-file), used for single line comments. */ |
| 85519 | DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) { |
| 85520 | for (;;) { |
| 85521 | duk_codepoint_t x; |
| 85522 | |
| 85523 | x = DUK__L0(); |
| 85524 | if (x < 0 || duk_unicode_is_line_terminator(x)) { |
| 85525 | break; |
| 85526 | } |
| 85527 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 85528 | } |
| 85529 | } |
| 85530 | |
| 85531 | /* |
| 85532 | * Parse ECMAScript source InputElementDiv or InputElementRegExp |
| 85533 | * (E5 Section 7), skipping whitespace, comments, and line terminators. |
| 85534 | * |
| 85535 | * Possible results are: |
| 85536 | * (1) a token |
| 85537 | * (2) a line terminator (skipped) |
| 85538 | * (3) a comment (skipped) |
| 85539 | * (4) EOF |
| 85540 | * |
| 85541 | * White space is automatically skipped from the current position (but |
| 85542 | * not after the input element). If input has already ended, returns |
| 85543 | * DUK_TOK_EOF indefinitely. If a parse error occurs, uses an DUK_ERROR() |
| 85544 | * macro call (and hence a longjmp through current heap longjmp context). |
| 85545 | * Comments and line terminator tokens are automatically skipped. |
| 85546 | * |
| 85547 | * The input element being matched is determined by regexp_mode; if set, |
| 85548 | * parses a InputElementRegExp, otherwise a InputElementDiv. The |
| 85549 | * difference between these are handling of productions starting with a |
| 85550 | * forward slash. |
| 85551 | * |
| 85552 | * If strict_mode is set, recognizes additional future reserved words |
| 85553 | * specific to strict mode, and refuses to parse octal literals. |
| 85554 | * |
| 85555 | * The matching strategy below is to (currently) use a six character |
| 85556 | * lookup window to quickly determine which production is the -longest- |
| 85557 | * matching one, and then parse that. The top-level if-else clauses |
| 85558 | * match the first character, and the code blocks for each clause |
| 85559 | * handle -all- alternatives for that first character. ECMAScript |
| 85560 | * specification uses the "longest match wins" semantics, so the order |
| 85561 | * of the if-clauses matters. |
| 85562 | * |
| 85563 | * Misc notes: |
| 85564 | * |
| 85565 | * * ECMAScript numeric literals do not accept a sign character. |
| 85566 | * Consequently e.g. "-1.0" is parsed as two tokens: a negative |
| 85567 | * sign and a positive numeric literal. The compiler performs |
| 85568 | * the negation during compilation, so this has no adverse impact. |
| 85569 | * |
| 85570 | * * There is no token for "undefined": it is just a value available |
| 85571 | * from the global object (or simply established by doing a reference |
| 85572 | * to an undefined value). |
| 85573 | * |
| 85574 | * * Some contexts want Identifier tokens, which are IdentifierNames |
| 85575 | * excluding reserved words, while some contexts want IdentifierNames |
| 85576 | * directly. In the latter case e.g. "while" is interpreted as an |
| 85577 | * identifier name, not a DUK_TOK_WHILE token. The solution here is |
| 85578 | * to provide both token types: DUK_TOK_WHILE goes to 't' while |
| 85579 | * DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains |
| 85580 | * the identifier / keyword name. |
| 85581 | * |
| 85582 | * * Directive prologue needs to identify string literals such as |
| 85583 | * "use strict" and 'use strict', which are sensitive to line |
| 85584 | * continuations and escape sequences. For instance, "use\u0020strict" |
| 85585 | * is a valid directive but is distinct from "use strict". The solution |
| 85586 | * here is to decode escapes while tokenizing, but to keep track of the |
| 85587 | * number of escapes. Directive detection can then check that the |
| 85588 | * number of escapes is zero. |
| 85589 | * |
| 85590 | * * Multi-line comments with one or more internal LineTerminator are |
| 85591 | * treated like a line terminator to comply with automatic semicolon |
| 85592 | * insertion. |
| 85593 | */ |
| 85594 | |
| 85595 | DUK_INTERNAL |
| 85596 | void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx, |
| 85597 | duk_token *out_token, |
| 85598 | duk_bool_t strict_mode, |
| 85599 | duk_bool_t regexp_mode) { |
| 85600 | duk_codepoint_t x; /* temporary, must be signed and 32-bit to hold Unicode code points */ |
| 85601 | duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end, |
| 85602 | * init is unnecessary but suppresses "may be used uninitialized" warnings. |
| 85603 | */ |
| 85604 | duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */ |
| 85605 | |
| 85606 | if (++lex_ctx->token_count >= lex_ctx->token_limit) { |
| 85607 | goto fail_token_limit; |
| 85608 | } |
| 85609 | |
| 85610 | out_token->t = DUK_TOK_EOF; |
| 85611 | out_token->t_nores = DUK_TOK_INVALID; /* marker: copy t if not changed */ |
| 85612 | #if 0 /* not necessary to init, disabled for faster parsing */ |
| 85613 | out_token->num = DUK_DOUBLE_NAN; |
| 85614 | out_token->str1 = NULL; |
| 85615 | out_token->str2 = NULL; |
| 85616 | #endif |
| 85617 | out_token->num_escapes = 0; |
| 85618 | /* out_token->lineterm set by caller */ |
| 85619 | |
| 85620 | /* This would be nice, but parsing is faster without resetting the |
| 85621 | * value slots. The only side effect is that references to temporary |
| 85622 | * string values may linger until lexing is finished; they're then |
| 85623 | * freed normally. |
| 85624 | */ |
| 85625 | #if 0 |
| 85626 | duk_to_undefined(lex_ctx->thr, lex_ctx->slot1_idx); |
| 85627 | duk_to_undefined(lex_ctx->thr, lex_ctx->slot2_idx); |
| 85628 | #endif |
| 85629 | |
| 85630 | /* 'advtok' indicates how much to advance and which token id to assign |
| 85631 | * at the end. This shared functionality minimizes code size. All |
| 85632 | * code paths are required to set 'advtok' to some value, so no default |
| 85633 | * init value is used. Code paths calling DUK_ERROR() never return so |
| 85634 | * they don't need to set advtok. |
| 85635 | */ |
| 85636 | |
| 85637 | /* |
| 85638 | * Matching order: |
| 85639 | * |
| 85640 | * Punctuator first chars, also covers comments, regexps |
| 85641 | * LineTerminator |
| 85642 | * Identifier or reserved word, also covers null/true/false literals |
| 85643 | * NumericLiteral |
| 85644 | * StringLiteral |
| 85645 | * EOF |
| 85646 | * |
| 85647 | * The order does not matter as long as the longest match is |
| 85648 | * always correctly identified. There are order dependencies |
| 85649 | * in the clauses, so it's not trivial to convert to a switch. |
| 85650 | */ |
| 85651 | |
| 85652 | restart_lineupdate: |
| 85653 | out_token->start_line = lex_ctx->window[0].line; |
| 85654 | |
| 85655 | restart: |
| 85656 | out_token->start_offset = lex_ctx->window[0].offset; |
| 85657 | |
| 85658 | x = DUK__L0(); |
| 85659 | |
| 85660 | switch (x) { |
| 85661 | case DUK_ASC_SPACE: |
| 85662 | case DUK_ASC_HT: /* fast paths for space and tab */ |
| 85663 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 85664 | goto restart; |
| 85665 | case DUK_ASC_LF: /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */ |
| 85666 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 85667 | got_lineterm = 1; |
| 85668 | goto restart_lineupdate; |
| 85669 | #if defined(DUK_USE_SHEBANG_COMMENTS) |
| 85670 | case DUK_ASC_HASH: /* '#' */ |
| 85671 | if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 && |
| 85672 | (lex_ctx->flags & DUK_COMPILE_SHEBANG)) { |
| 85673 | /* "Shebang" comment ('#! ...') on first line. */ |
| 85674 | /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ |
| 85675 | duk__lexer_skip_to_endofline(lex_ctx); |
| 85676 | goto restart; /* line terminator will be handled on next round */ |
| 85677 | } |
| 85678 | goto fail_token; |
| 85679 | #endif /* DUK_USE_SHEBANG_COMMENTS */ |
| 85680 | case DUK_ASC_SLASH: /* '/' */ |
| 85681 | if (DUK__L1() == DUK_ASC_SLASH) { |
| 85682 | /* |
| 85683 | * E5 Section 7.4, allow SourceCharacter (which is any 16-bit |
| 85684 | * code point). |
| 85685 | */ |
| 85686 | |
| 85687 | /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */ |
| 85688 | duk__lexer_skip_to_endofline(lex_ctx); |
| 85689 | goto restart; /* line terminator will be handled on next round */ |
| 85690 | } else if (DUK__L1() == DUK_ASC_STAR) { |
| 85691 | /* |
| 85692 | * E5 Section 7.4. If the multi-line comment contains a newline, |
| 85693 | * it is treated like a single line terminator for automatic |
| 85694 | * semicolon insertion. |
| 85695 | */ |
| 85696 | |
| 85697 | duk_bool_t last_asterisk = 0; |
| 85698 | DUK__ADVANCECHARS(lex_ctx, 2); |
| 85699 | for (;;) { |
| 85700 | x = DUK__L0(); |
| 85701 | if (x < 0) { |
| 85702 | goto fail_unterm_comment; |
| 85703 | } |
| 85704 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 85705 | if (last_asterisk && x == DUK_ASC_SLASH) { |
| 85706 | break; |
| 85707 | } |
| 85708 | if (duk_unicode_is_line_terminator(x)) { |
| 85709 | got_lineterm = 1; |
| 85710 | } |
| 85711 | last_asterisk = (x == DUK_ASC_STAR); |
| 85712 | } |
| 85713 | goto restart_lineupdate; |
| 85714 | } else if (regexp_mode) { |
| 85715 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 85716 | /* |
| 85717 | * "/" followed by something in regexp mode. See E5 Section 7.8.5. |
| 85718 | * |
| 85719 | * RegExp parsing is a bit complex. First, the regexp body is delimited |
| 85720 | * by forward slashes, but the body may also contain forward slashes as |
| 85721 | * part of an escape sequence or inside a character class (delimited by |
| 85722 | * square brackets). A mini state machine is used to implement these. |
| 85723 | * |
| 85724 | * Further, an early (parse time) error must be thrown if the regexp |
| 85725 | * would cause a run-time error when used in the expression new RegExp(...). |
| 85726 | * Parsing here simply extracts the (candidate) regexp, and also accepts |
| 85727 | * invalid regular expressions (which are delimited properly). The caller |
| 85728 | * (compiler) must perform final validation and regexp compilation. |
| 85729 | * |
| 85730 | * RegExp first char may not be '/' (single line comment) or '*' (multi- |
| 85731 | * line comment). These have already been checked above, so there is no |
| 85732 | * need below for special handling of the first regexp character as in |
| 85733 | * the E5 productions. |
| 85734 | * |
| 85735 | * About unicode escapes within regexp literals: |
| 85736 | * |
| 85737 | * E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes. |
| 85738 | * However, Section 6 states that regexps accept the escapes, |
| 85739 | * see paragraph starting with "In string literals...". |
| 85740 | * The regexp grammar, which sees the decoded regexp literal |
| 85741 | * (after lexical parsing) DOES have a \uHHHH unicode escape. |
| 85742 | * So, for instance: |
| 85743 | * |
| 85744 | * /\u1234/ |
| 85745 | * |
| 85746 | * should first be parsed by the lexical grammar as: |
| 85747 | * |
| 85748 | * '\' 'u' RegularExpressionBackslashSequence |
| 85749 | * '1' RegularExpressionNonTerminator |
| 85750 | * '2' RegularExpressionNonTerminator |
| 85751 | * '3' RegularExpressionNonTerminator |
| 85752 | * '4' RegularExpressionNonTerminator |
| 85753 | * |
| 85754 | * and the escape itself is then parsed by the regexp engine. |
| 85755 | * This is the current implementation. |
| 85756 | * |
| 85757 | * Minor spec inconsistency: |
| 85758 | * |
| 85759 | * E5 Section 7.8.5 RegularExpressionBackslashSequence is: |
| 85760 | * |
| 85761 | * \ RegularExpressionNonTerminator |
| 85762 | * |
| 85763 | * while Section A.1 RegularExpressionBackslashSequence is: |
| 85764 | * |
| 85765 | * \ NonTerminator |
| 85766 | * |
| 85767 | * The latter is not normative and a typo. |
| 85768 | * |
| 85769 | */ |
| 85770 | |
| 85771 | /* first, parse regexp body roughly */ |
| 85772 | |
| 85773 | duk_small_int_t state = 0; /* 0=base, 1=esc, 2=class, 3=class+esc */ |
| 85774 | |
| 85775 | DUK__INITBUFFER(lex_ctx); |
| 85776 | for (;;) { |
| 85777 | DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */ |
| 85778 | x = DUK__L0(); |
| 85779 | if (x < 0 || duk_unicode_is_line_terminator(x)) { |
| 85780 | goto fail_unterm_regexp; |
| 85781 | } |
| 85782 | x = DUK__L0(); /* re-read to avoid spill / fetch */ |
| 85783 | if (state == 0) { |
| 85784 | if (x == DUK_ASC_SLASH) { |
| 85785 | DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */ |
| 85786 | break; |
| 85787 | } else if (x == DUK_ASC_BACKSLASH) { |
| 85788 | state = 1; |
| 85789 | } else if (x == DUK_ASC_LBRACKET) { |
| 85790 | state = 2; |
| 85791 | } |
| 85792 | } else if (state == 1) { |
| 85793 | state = 0; |
| 85794 | } else if (state == 2) { |
| 85795 | if (x == DUK_ASC_RBRACKET) { |
| 85796 | state = 0; |
| 85797 | } else if (x == DUK_ASC_BACKSLASH) { |
| 85798 | state = 3; |
| 85799 | } |
| 85800 | } else { /* state == 3 */ |
| 85801 | state = 2; |
| 85802 | } |
| 85803 | DUK__APPENDBUFFER(lex_ctx, x); |
| 85804 | } |
| 85805 | out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); |
| 85806 | |
| 85807 | /* second, parse flags */ |
| 85808 | |
| 85809 | DUK__INITBUFFER(lex_ctx); |
| 85810 | for (;;) { |
| 85811 | x = DUK__L0(); |
| 85812 | if (!duk_unicode_is_identifier_part(x)) { |
| 85813 | break; |
| 85814 | } |
| 85815 | x = DUK__L0(); /* re-read to avoid spill / fetch */ |
| 85816 | DUK__APPENDBUFFER(lex_ctx, x); |
| 85817 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 85818 | } |
| 85819 | out_token->str2 = duk__internbuffer(lex_ctx, lex_ctx->slot2_idx); |
| 85820 | |
| 85821 | DUK__INITBUFFER(lex_ctx); /* free some memory */ |
| 85822 | |
| 85823 | /* validation of the regexp is caller's responsibility */ |
| 85824 | |
| 85825 | advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP); |
| 85826 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 85827 | goto fail_regexp_support; |
| 85828 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 85829 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85830 | /* "/=" and not in regexp mode */ |
| 85831 | advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ); |
| 85832 | } else { |
| 85833 | /* "/" and not in regexp mode */ |
| 85834 | advtok = DUK__ADVTOK(1, DUK_TOK_DIV); |
| 85835 | } |
| 85836 | break; |
| 85837 | case DUK_ASC_LCURLY: /* '{' */ |
| 85838 | advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY); |
| 85839 | break; |
| 85840 | case DUK_ASC_RCURLY: /* '}' */ |
| 85841 | advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY); |
| 85842 | break; |
| 85843 | case DUK_ASC_LPAREN: /* '(' */ |
| 85844 | advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN); |
| 85845 | break; |
| 85846 | case DUK_ASC_RPAREN: /* ')' */ |
| 85847 | advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN); |
| 85848 | break; |
| 85849 | case DUK_ASC_LBRACKET: /* '[' */ |
| 85850 | advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET); |
| 85851 | break; |
| 85852 | case DUK_ASC_RBRACKET: /* ']' */ |
| 85853 | advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET); |
| 85854 | break; |
| 85855 | case DUK_ASC_PERIOD: /* '.' */ |
| 85856 | if (DUK__ISDIGIT(DUK__L1())) { |
| 85857 | /* Period followed by a digit can only start DecimalLiteral |
| 85858 | * (handled in slow path). We could jump straight into the |
| 85859 | * DecimalLiteral handling but should avoid goto to inside |
| 85860 | * a block. |
| 85861 | */ |
| 85862 | goto slow_path; |
| 85863 | } |
| 85864 | advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD); |
| 85865 | break; |
| 85866 | case DUK_ASC_SEMICOLON: /* ';' */ |
| 85867 | advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON); |
| 85868 | break; |
| 85869 | case DUK_ASC_COMMA: /* ',' */ |
| 85870 | advtok = DUK__ADVTOK(1, DUK_TOK_COMMA); |
| 85871 | break; |
| 85872 | case DUK_ASC_LANGLE: /* '<' */ |
| 85873 | #if defined(DUK_USE_HTML_COMMENTS) |
| 85874 | if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) { |
| 85875 | /* |
| 85876 | * ES2015: B.1.3, handle "<!--" SingleLineHTMLOpenComment |
| 85877 | */ |
| 85878 | |
| 85879 | /* DUK__ADVANCECHARS(lex_ctx, 4) would be correct here, but not necessary */ |
| 85880 | duk__lexer_skip_to_endofline(lex_ctx); |
| 85881 | goto restart; /* line terminator will be handled on next round */ |
| 85882 | } |
| 85883 | else |
| 85884 | #endif /* DUK_USE_HTML_COMMENTS */ |
| 85885 | if (DUK__L1() == DUK_ASC_LANGLE && DUK__L2() == DUK_ASC_EQUALS) { |
| 85886 | advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ); |
| 85887 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85888 | advtok = DUK__ADVTOK(2, DUK_TOK_LE); |
| 85889 | } else if (DUK__L1() == DUK_ASC_LANGLE) { |
| 85890 | advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT); |
| 85891 | } else { |
| 85892 | advtok = DUK__ADVTOK(1, DUK_TOK_LT); |
| 85893 | } |
| 85894 | break; |
| 85895 | case DUK_ASC_RANGLE: /* '>' */ |
| 85896 | if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE && DUK__L3() == DUK_ASC_EQUALS) { |
| 85897 | advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ); |
| 85898 | } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE) { |
| 85899 | advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT); |
| 85900 | } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_EQUALS) { |
| 85901 | advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ); |
| 85902 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85903 | advtok = DUK__ADVTOK(2, DUK_TOK_GE); |
| 85904 | } else if (DUK__L1() == DUK_ASC_RANGLE) { |
| 85905 | advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT); |
| 85906 | } else { |
| 85907 | advtok = DUK__ADVTOK(1, DUK_TOK_GT); |
| 85908 | } |
| 85909 | break; |
| 85910 | case DUK_ASC_EQUALS: /* '=' */ |
| 85911 | if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) { |
| 85912 | advtok = DUK__ADVTOK(3, DUK_TOK_SEQ); |
| 85913 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85914 | advtok = DUK__ADVTOK(2, DUK_TOK_EQ); |
| 85915 | } else { |
| 85916 | advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN); |
| 85917 | } |
| 85918 | break; |
| 85919 | case DUK_ASC_EXCLAMATION: /* '!' */ |
| 85920 | if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) { |
| 85921 | advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ); |
| 85922 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85923 | advtok = DUK__ADVTOK(2, DUK_TOK_NEQ); |
| 85924 | } else { |
| 85925 | advtok = DUK__ADVTOK(1, DUK_TOK_LNOT); |
| 85926 | } |
| 85927 | break; |
| 85928 | case DUK_ASC_PLUS: /* '+' */ |
| 85929 | if (DUK__L1() == DUK_ASC_PLUS) { |
| 85930 | advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT); |
| 85931 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85932 | advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ); |
| 85933 | } else { |
| 85934 | advtok = DUK__ADVTOK(1, DUK_TOK_ADD); |
| 85935 | } |
| 85936 | break; |
| 85937 | case DUK_ASC_MINUS: /* '-' */ |
| 85938 | #if defined(DUK_USE_HTML_COMMENTS) |
| 85939 | if (got_lineterm && DUK__L1() == DUK_ASC_MINUS && DUK__L2() == DUK_ASC_RANGLE) { |
| 85940 | /* |
| 85941 | * ES2015: B.1.3, handle "-->" SingleLineHTMLCloseComment |
| 85942 | * Only allowed: |
| 85943 | * - on new line |
| 85944 | * - preceded only by whitespace |
| 85945 | * - preceded by end of multiline comment and optional whitespace |
| 85946 | * |
| 85947 | * Since whitespace generates no tokens, and multiline comments |
| 85948 | * are treated as a line ending, consulting `got_lineterm` is |
| 85949 | * sufficient to test for these three options. |
| 85950 | */ |
| 85951 | |
| 85952 | /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */ |
| 85953 | duk__lexer_skip_to_endofline(lex_ctx); |
| 85954 | goto restart; /* line terminator will be handled on next round */ |
| 85955 | } else |
| 85956 | #endif /* DUK_USE_HTML_COMMENTS */ |
| 85957 | if (DUK__L1() == DUK_ASC_MINUS) { |
| 85958 | advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT); |
| 85959 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85960 | advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ); |
| 85961 | } else { |
| 85962 | advtok = DUK__ADVTOK(1, DUK_TOK_SUB); |
| 85963 | } |
| 85964 | break; |
| 85965 | case DUK_ASC_STAR: /* '*' */ |
| 85966 | #if defined(DUK_USE_ES7_EXP_OPERATOR) |
| 85967 | if (DUK__L1() == DUK_ASC_STAR && DUK__L2() == DUK_ASC_EQUALS) { |
| 85968 | advtok = DUK__ADVTOK(3, DUK_TOK_EXP_EQ); |
| 85969 | } else if (DUK__L1() == DUK_ASC_STAR) { |
| 85970 | advtok = DUK__ADVTOK(2, DUK_TOK_EXP); |
| 85971 | } else |
| 85972 | #endif |
| 85973 | if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85974 | advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ); |
| 85975 | } else { |
| 85976 | advtok = DUK__ADVTOK(1, DUK_TOK_MUL); |
| 85977 | } |
| 85978 | break; |
| 85979 | case DUK_ASC_PERCENT: /* '%' */ |
| 85980 | if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85981 | advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ); |
| 85982 | } else { |
| 85983 | advtok = DUK__ADVTOK(1, DUK_TOK_MOD); |
| 85984 | } |
| 85985 | break; |
| 85986 | case DUK_ASC_AMP: /* '&' */ |
| 85987 | if (DUK__L1() == DUK_ASC_AMP) { |
| 85988 | advtok = DUK__ADVTOK(2, DUK_TOK_LAND); |
| 85989 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85990 | advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ); |
| 85991 | } else { |
| 85992 | advtok = DUK__ADVTOK(1, DUK_TOK_BAND); |
| 85993 | } |
| 85994 | break; |
| 85995 | case DUK_ASC_PIPE: /* '|' */ |
| 85996 | if (DUK__L1() == DUK_ASC_PIPE) { |
| 85997 | advtok = DUK__ADVTOK(2, DUK_TOK_LOR); |
| 85998 | } else if (DUK__L1() == DUK_ASC_EQUALS) { |
| 85999 | advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ); |
| 86000 | } else { |
| 86001 | advtok = DUK__ADVTOK(1, DUK_TOK_BOR); |
| 86002 | } |
| 86003 | break; |
| 86004 | case DUK_ASC_CARET: /* '^' */ |
| 86005 | if (DUK__L1() == DUK_ASC_EQUALS) { |
| 86006 | advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ); |
| 86007 | } else { |
| 86008 | advtok = DUK__ADVTOK(1, DUK_TOK_BXOR); |
| 86009 | } |
| 86010 | break; |
| 86011 | case DUK_ASC_TILDE: /* '~' */ |
| 86012 | advtok = DUK__ADVTOK(1, DUK_TOK_BNOT); |
| 86013 | break; |
| 86014 | case DUK_ASC_QUESTION: /* '?' */ |
| 86015 | advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION); |
| 86016 | break; |
| 86017 | case DUK_ASC_COLON: /* ':' */ |
| 86018 | advtok = DUK__ADVTOK(1, DUK_TOK_COLON); |
| 86019 | break; |
| 86020 | case DUK_ASC_DOUBLEQUOTE: /* '"' */ |
| 86021 | case DUK_ASC_SINGLEQUOTE: { /* '\'' */ |
| 86022 | DUK__INITBUFFER(lex_ctx); |
| 86023 | duk__lexer_parse_string_literal(lex_ctx, out_token, x /*quote*/, strict_mode); |
| 86024 | duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); |
| 86025 | out_token->str1 = duk_known_hstring(lex_ctx->thr, lex_ctx->slot1_idx); |
| 86026 | |
| 86027 | DUK__INITBUFFER(lex_ctx); /* free some memory */ |
| 86028 | |
| 86029 | advtok = DUK__ADVTOK(0, DUK_TOK_STRING); |
| 86030 | break; |
| 86031 | } |
| 86032 | default: |
| 86033 | goto slow_path; |
| 86034 | } /* switch */ |
| 86035 | |
| 86036 | goto skip_slow_path; |
| 86037 | |
| 86038 | slow_path: |
| 86039 | if (duk_unicode_is_line_terminator(x)) { |
| 86040 | if (x == 0x000d && DUK__L1() == 0x000a) { |
| 86041 | /* |
| 86042 | * E5 Section 7.3: CR LF is detected as a single line terminator for |
| 86043 | * line numbers. Here we also detect it as a single line terminator |
| 86044 | * token. |
| 86045 | */ |
| 86046 | DUK__ADVANCECHARS(lex_ctx, 2); |
| 86047 | } else { |
| 86048 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 86049 | } |
| 86050 | got_lineterm = 1; |
| 86051 | goto restart_lineupdate; |
| 86052 | } else if (duk_unicode_is_identifier_start(x) || x == DUK_ASC_BACKSLASH) { |
| 86053 | /* |
| 86054 | * Parse an identifier and then check whether it is: |
| 86055 | * - reserved word (keyword or other reserved word) |
| 86056 | * - "null" (NullLiteral) |
| 86057 | * - "true" (BooleanLiteral) |
| 86058 | * - "false" (BooleanLiteral) |
| 86059 | * - anything else => identifier |
| 86060 | * |
| 86061 | * This does not follow the E5 productions cleanly, but is |
| 86062 | * useful and compact. |
| 86063 | * |
| 86064 | * Note that identifiers may contain Unicode escapes, |
| 86065 | * see E5 Sections 6 and 7.6. They must be decoded first, |
| 86066 | * and the result checked against allowed characters. |
| 86067 | * The above if-clause accepts an identifier start and an |
| 86068 | * '\' character -- no other token can begin with a '\'. |
| 86069 | * |
| 86070 | * Note that "get" and "set" are not reserved words in E5 |
| 86071 | * specification so they are recognized as plain identifiers |
| 86072 | * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not |
| 86073 | * used now). The compiler needs to work around this. |
| 86074 | * |
| 86075 | * Strictly speaking, following ECMAScript longest match |
| 86076 | * specification, an invalid escape for the first character |
| 86077 | * should cause a syntax error. However, an invalid escape |
| 86078 | * for IdentifierParts should just terminate the identifier |
| 86079 | * early (longest match), and let the next tokenization |
| 86080 | * fail. For instance Rhino croaks with 'foo\z' when |
| 86081 | * parsing the identifier. This has little practical impact. |
| 86082 | */ |
| 86083 | |
| 86084 | duk_small_uint_t i, i_end; |
| 86085 | duk_bool_t first = 1; |
| 86086 | duk_hstring *str; |
| 86087 | |
| 86088 | DUK__INITBUFFER(lex_ctx); |
| 86089 | for (;;) { |
| 86090 | /* re-lookup first char on first loop */ |
| 86091 | if (DUK__L0() == DUK_ASC_BACKSLASH) { |
| 86092 | duk_codepoint_t esc_cp; |
| 86093 | if (DUK__L1() != DUK_ASC_LC_U) { |
| 86094 | goto fail_escape; |
| 86095 | } |
| 86096 | esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/); |
| 86097 | DUK__APPENDBUFFER(lex_ctx, esc_cp); |
| 86098 | |
| 86099 | /* IdentifierStart is stricter than IdentifierPart, so if the first |
| 86100 | * character is escaped, must have a stricter check here. |
| 86101 | */ |
| 86102 | if (!(first ? duk_unicode_is_identifier_start(esc_cp) : duk_unicode_is_identifier_part(esc_cp))) { |
| 86103 | goto fail_escape; |
| 86104 | } |
| 86105 | |
| 86106 | /* Track number of escapes: necessary for proper keyword |
| 86107 | * detection. |
| 86108 | */ |
| 86109 | out_token->num_escapes++; |
| 86110 | } else { |
| 86111 | /* Note: first character is checked against this. But because |
| 86112 | * IdentifierPart includes all IdentifierStart characters, and |
| 86113 | * the first character (if unescaped) has already been checked |
| 86114 | * in the if condition, this is OK. |
| 86115 | */ |
| 86116 | if (!duk_unicode_is_identifier_part(DUK__L0())) { |
| 86117 | break; |
| 86118 | } |
| 86119 | DUK__APPENDBUFFER(lex_ctx, DUK__L0()); |
| 86120 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 86121 | } |
| 86122 | first = 0; |
| 86123 | } |
| 86124 | |
| 86125 | out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); |
| 86126 | str = out_token->str1; |
| 86127 | out_token->t_nores = DUK_TOK_IDENTIFIER; |
| 86128 | |
| 86129 | DUK__INITBUFFER(lex_ctx); /* free some memory */ |
| 86130 | |
| 86131 | /* |
| 86132 | * Interned identifier is compared against reserved words, which are |
| 86133 | * currently interned into the heap context. See genbuiltins.py. |
| 86134 | * |
| 86135 | * Note that an escape in the identifier disables recognition of |
| 86136 | * keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to |
| 86137 | * identifier named "if"). This is not necessarily compliant, |
| 86138 | * see test-dec-escaped-char-in-keyword.js. |
| 86139 | * |
| 86140 | * Note: "get" and "set" are awkward. They are not officially |
| 86141 | * ReservedWords (and indeed e.g. "var set = 1;" is valid), and |
| 86142 | * must come out as DUK_TOK_IDENTIFIER. The compiler needs to |
| 86143 | * work around this a bit. |
| 86144 | */ |
| 86145 | |
| 86146 | /* XXX: optimize by adding the token numbers directly into the |
| 86147 | * always interned duk_hstring objects (there should be enough |
| 86148 | * flag bits free for that)? |
| 86149 | */ |
| 86150 | |
| 86151 | i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED); |
| 86152 | |
| 86153 | advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER); |
| 86154 | if (out_token->num_escapes == 0) { |
| 86155 | for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) { |
| 86156 | DUK_ASSERT_DISABLE(i >= 0); /* unsigned */ |
| 86157 | DUK_ASSERT(i < DUK_HEAP_NUM_STRINGS); |
| 86158 | if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) { |
| 86159 | advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i)); |
| 86160 | break; |
| 86161 | } |
| 86162 | } |
| 86163 | } |
| 86164 | } else if (DUK__ISDIGIT(x) || (x == DUK_ASC_PERIOD)) { |
| 86165 | /* Note: decimal number may start with a period, but must be followed by a digit */ |
| 86166 | |
| 86167 | /* |
| 86168 | * Pre-parsing for decimal, hex, octal (both legacy and ES2015), |
| 86169 | * and binary literals, followed by an actual parser step |
| 86170 | * provided by numconv. |
| 86171 | * |
| 86172 | * Note: the leading sign character ('+' or '-') is -not- part of |
| 86173 | * the production in E5 grammar, and that the a DecimalLiteral |
| 86174 | * starting with a '0' must be followed by a non-digit. |
| 86175 | * |
| 86176 | * XXX: the two step parsing process is quite awkward, it would |
| 86177 | * be more straightforward to allow numconv to parse the longest |
| 86178 | * valid prefix (it already does that, it only needs to indicate |
| 86179 | * where the input ended). However, the lexer decodes characters |
| 86180 | * using a limited lookup window, so this is not a trivial change. |
| 86181 | */ |
| 86182 | |
| 86183 | /* XXX: because of the final check below (that the literal is not |
| 86184 | * followed by a digit), this could maybe be simplified, if we bail |
| 86185 | * out early from a leading zero (and if there are no periods etc). |
| 86186 | * Maybe too complex. |
| 86187 | */ |
| 86188 | |
| 86189 | duk_double_t val; |
| 86190 | duk_bool_t legacy_oct = 0; |
| 86191 | duk_small_int_t state; /* 0=before period/exp, |
| 86192 | * 1=after period, before exp |
| 86193 | * 2=after exp, allow '+' or '-' |
| 86194 | * 3=after exp and exp sign |
| 86195 | */ |
| 86196 | duk_small_uint_t s2n_flags; |
| 86197 | duk_codepoint_t y, z; |
| 86198 | duk_small_int_t s2n_radix = 10; |
| 86199 | duk_small_uint_t pre_adv = 0; |
| 86200 | |
| 86201 | DUK__INITBUFFER(lex_ctx); |
| 86202 | y = DUK__L1(); |
| 86203 | |
| 86204 | if (x == DUK_ASC_0) { |
| 86205 | z = DUK_LOWERCASE_CHAR_ASCII(y); |
| 86206 | |
| 86207 | pre_adv = 2; /* default for 0xNNN, 0oNNN, 0bNNN. */ |
| 86208 | if (z == DUK_ASC_LC_X) { |
| 86209 | s2n_radix = 16; |
| 86210 | } else if (z == DUK_ASC_LC_O) { |
| 86211 | s2n_radix = 8; |
| 86212 | } else if (z == DUK_ASC_LC_B) { |
| 86213 | s2n_radix = 2; |
| 86214 | } else { |
| 86215 | pre_adv = 0; |
| 86216 | if (DUK__ISDIGIT(y)) { |
| 86217 | if (strict_mode) { |
| 86218 | /* Reject octal like \07 but also octal-lookalike |
| 86219 | * decimal like \08 in strict mode. |
| 86220 | */ |
| 86221 | goto fail_number_literal; |
| 86222 | } else { |
| 86223 | /* Legacy OctalIntegerLiteral or octal-lookalice |
| 86224 | * decimal. Deciding between the two happens below |
| 86225 | * in digit scanning. |
| 86226 | */ |
| 86227 | DUK__APPENDBUFFER(lex_ctx, x); |
| 86228 | pre_adv = 1; |
| 86229 | legacy_oct = 1; |
| 86230 | s2n_radix = 8; /* tentative unless conflicting digits found */ |
| 86231 | } |
| 86232 | } |
| 86233 | } |
| 86234 | } |
| 86235 | |
| 86236 | DUK__ADVANCECHARS(lex_ctx, pre_adv); |
| 86237 | |
| 86238 | /* XXX: we could parse integers here directly, and fall back |
| 86239 | * to numconv only when encountering a fractional expression |
| 86240 | * or when an octal literal turned out to be decimal (0778 etc). |
| 86241 | */ |
| 86242 | state = 0; |
| 86243 | for (;;) { |
| 86244 | x = DUK__L0(); /* re-lookup curr char on first round */ |
| 86245 | if (DUK__ISDIGIT(x)) { |
| 86246 | /* Note: intentionally allow leading zeroes here, as the |
| 86247 | * actual parser will check for them. |
| 86248 | */ |
| 86249 | if (state == 0 && legacy_oct && (x == DUK_ASC_8 || x == DUK_ASC_9)) { |
| 86250 | /* Started out as an octal-lookalike |
| 86251 | * but interpreted as decimal, e.g. |
| 86252 | * '0779' -> 779. This also means |
| 86253 | * that fractions are allowed, e.g. |
| 86254 | * '0779.123' is allowed but '0777.123' |
| 86255 | * is not! |
| 86256 | */ |
| 86257 | s2n_radix = 10; |
| 86258 | } |
| 86259 | if (state == 2) { |
| 86260 | state = 3; |
| 86261 | } |
| 86262 | } else if (s2n_radix == 16 && DUK__ISHEXDIGIT(x)) { |
| 86263 | /* Note: 'e' and 'E' are also accepted here. */ |
| 86264 | ; |
| 86265 | } else if (x == DUK_ASC_PERIOD) { |
| 86266 | if (state >= 1 || s2n_radix != 10) { |
| 86267 | break; |
| 86268 | } else { |
| 86269 | state = 1; |
| 86270 | } |
| 86271 | } else if (x == DUK_ASC_LC_E || x == DUK_ASC_UC_E) { |
| 86272 | if (state >= 2 || s2n_radix != 10) { |
| 86273 | break; |
| 86274 | } else { |
| 86275 | state = 2; |
| 86276 | } |
| 86277 | } else if (x == DUK_ASC_MINUS || x == DUK_ASC_PLUS) { |
| 86278 | if (state != 2) { |
| 86279 | break; |
| 86280 | } else { |
| 86281 | state = 3; |
| 86282 | } |
| 86283 | } else { |
| 86284 | break; |
| 86285 | } |
| 86286 | DUK__APPENDBUFFER(lex_ctx, x); |
| 86287 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 86288 | } |
| 86289 | |
| 86290 | /* XXX: better coercion */ |
| 86291 | (void) duk__internbuffer(lex_ctx, lex_ctx->slot1_idx); |
| 86292 | |
| 86293 | if (s2n_radix != 10) { |
| 86294 | /* For bases other than 10, integer only. */ |
| 86295 | s2n_flags = DUK_S2N_FLAG_ALLOW_LEADING_ZERO; |
| 86296 | } else { |
| 86297 | s2n_flags = DUK_S2N_FLAG_ALLOW_EXP | |
| 86298 | DUK_S2N_FLAG_ALLOW_FRAC | |
| 86299 | DUK_S2N_FLAG_ALLOW_NAKED_FRAC | |
| 86300 | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | |
| 86301 | DUK_S2N_FLAG_ALLOW_LEADING_ZERO; |
| 86302 | } |
| 86303 | |
| 86304 | duk_dup(lex_ctx->thr, lex_ctx->slot1_idx); |
| 86305 | duk_numconv_parse(lex_ctx->thr, s2n_radix, s2n_flags); |
| 86306 | val = duk_to_number_m1(lex_ctx->thr); |
| 86307 | if (DUK_ISNAN(val)) { |
| 86308 | goto fail_number_literal; |
| 86309 | } |
| 86310 | duk_replace(lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */ |
| 86311 | |
| 86312 | DUK__INITBUFFER(lex_ctx); /* free some memory */ |
| 86313 | |
| 86314 | /* Section 7.8.3 (note): NumericLiteral must be followed by something other than |
| 86315 | * IdentifierStart or DecimalDigit. |
| 86316 | */ |
| 86317 | |
| 86318 | if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) { |
| 86319 | goto fail_number_literal; |
| 86320 | } |
| 86321 | |
| 86322 | out_token->num = val; |
| 86323 | advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER); |
| 86324 | } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) { |
| 86325 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 86326 | goto restart; |
| 86327 | } else if (x < 0) { |
| 86328 | advtok = DUK__ADVTOK(0, DUK_TOK_EOF); |
| 86329 | } else { |
| 86330 | goto fail_token; |
| 86331 | } |
| 86332 | skip_slow_path: |
| 86333 | |
| 86334 | /* |
| 86335 | * Shared exit path |
| 86336 | */ |
| 86337 | |
| 86338 | DUK__ADVANCEBYTES(lex_ctx, advtok >> 8); |
| 86339 | out_token->t = advtok & 0xff; |
| 86340 | if (out_token->t_nores == DUK_TOK_INVALID) { |
| 86341 | out_token->t_nores = out_token->t; |
| 86342 | } |
| 86343 | out_token->lineterm = got_lineterm; |
| 86344 | |
| 86345 | /* Automatic semicolon insertion is allowed if a token is preceded |
| 86346 | * by line terminator(s), or terminates a statement list (right curly |
| 86347 | * or EOF). |
| 86348 | */ |
| 86349 | if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) { |
| 86350 | out_token->allow_auto_semi = 1; |
| 86351 | } else { |
| 86352 | out_token->allow_auto_semi = 0; |
| 86353 | } |
| 86354 | |
| 86355 | return; |
| 86356 | |
| 86357 | fail_token_limit: |
| 86358 | DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT); |
| 86359 | DUK_WO_NORETURN(return;); |
| 86360 | |
| 86361 | fail_token: |
| 86362 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_TOKEN); |
| 86363 | DUK_WO_NORETURN(return;); |
| 86364 | |
| 86365 | fail_number_literal: |
| 86366 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_NUMBER_LITERAL); |
| 86367 | DUK_WO_NORETURN(return;); |
| 86368 | |
| 86369 | fail_escape: |
| 86370 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE); |
| 86371 | DUK_WO_NORETURN(return;); |
| 86372 | |
| 86373 | fail_unterm_regexp: |
| 86374 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_REGEXP); |
| 86375 | DUK_WO_NORETURN(return;); |
| 86376 | |
| 86377 | : |
| 86378 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_COMMENT); |
| 86379 | DUK_WO_NORETURN(return;); |
| 86380 | |
| 86381 | #if !defined(DUK_USE_REGEXP_SUPPORT) |
| 86382 | fail_regexp_support: |
| 86383 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_REGEXP_SUPPORT_DISABLED); |
| 86384 | DUK_WO_NORETURN(return;); |
| 86385 | #endif |
| 86386 | } |
| 86387 | |
| 86388 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 86389 | |
| 86390 | /* |
| 86391 | * Parse a RegExp token. The grammar is described in E5 Section 15.10. |
| 86392 | * Terminal constructions (such as quantifiers) are parsed directly here. |
| 86393 | * |
| 86394 | * 0xffffffffU is used as a marker for "infinity" in quantifiers. Further, |
| 86395 | * DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that |
| 86396 | * will be accepted for a quantifier. |
| 86397 | */ |
| 86398 | |
| 86399 | DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) { |
| 86400 | duk_small_uint_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */ |
| 86401 | duk_codepoint_t x, y; |
| 86402 | |
| 86403 | if (++lex_ctx->token_count >= lex_ctx->token_limit) { |
| 86404 | goto fail_token_limit; |
| 86405 | } |
| 86406 | |
| 86407 | duk_memzero(out_token, sizeof(*out_token)); |
| 86408 | |
| 86409 | x = DUK__L0(); |
| 86410 | y = DUK__L1(); |
| 86411 | |
| 86412 | DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld" , (long) x, (long) y)); |
| 86413 | |
| 86414 | switch (x) { |
| 86415 | case DUK_ASC_PIPE: { |
| 86416 | advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION); |
| 86417 | break; |
| 86418 | } |
| 86419 | case DUK_ASC_CARET: { |
| 86420 | advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START); |
| 86421 | break; |
| 86422 | } |
| 86423 | case DUK_ASC_DOLLAR: { |
| 86424 | advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END); |
| 86425 | break; |
| 86426 | } |
| 86427 | case DUK_ASC_QUESTION: { |
| 86428 | out_token->qmin = 0; |
| 86429 | out_token->qmax = 1; |
| 86430 | if (y == DUK_ASC_QUESTION) { |
| 86431 | advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER); |
| 86432 | out_token->greedy = 0; |
| 86433 | } else { |
| 86434 | advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER); |
| 86435 | out_token->greedy = 1; |
| 86436 | } |
| 86437 | break; |
| 86438 | } |
| 86439 | case DUK_ASC_STAR: { |
| 86440 | out_token->qmin = 0; |
| 86441 | out_token->qmax = DUK_RE_QUANTIFIER_INFINITE; |
| 86442 | if (y == DUK_ASC_QUESTION) { |
| 86443 | advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER); |
| 86444 | out_token->greedy = 0; |
| 86445 | } else { |
| 86446 | advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER); |
| 86447 | out_token->greedy = 1; |
| 86448 | } |
| 86449 | break; |
| 86450 | } |
| 86451 | case DUK_ASC_PLUS: { |
| 86452 | out_token->qmin = 1; |
| 86453 | out_token->qmax = DUK_RE_QUANTIFIER_INFINITE; |
| 86454 | if (y == DUK_ASC_QUESTION) { |
| 86455 | advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER); |
| 86456 | out_token->greedy = 0; |
| 86457 | } else { |
| 86458 | advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER); |
| 86459 | out_token->greedy = 1; |
| 86460 | } |
| 86461 | break; |
| 86462 | } |
| 86463 | case DUK_ASC_LCURLY: { |
| 86464 | /* Production allows 'DecimalDigits', including leading zeroes */ |
| 86465 | duk_uint32_t val1 = 0; |
| 86466 | duk_uint32_t val2 = DUK_RE_QUANTIFIER_INFINITE; |
| 86467 | duk_small_int_t digits = 0; |
| 86468 | #if defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86469 | duk_lexer_point lex_pt; |
| 86470 | #endif |
| 86471 | |
| 86472 | #if defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86473 | /* Store lexer position, restoring if quantifier is invalid. */ |
| 86474 | DUK_LEXER_GETPOINT(lex_ctx, &lex_pt); |
| 86475 | #endif |
| 86476 | |
| 86477 | for (;;) { |
| 86478 | DUK__ADVANCECHARS(lex_ctx, 1); /* eat '{' on entry */ |
| 86479 | x = DUK__L0(); |
| 86480 | if (DUK__ISDIGIT(x)) { |
| 86481 | digits++; |
| 86482 | val1 = val1 * 10 + (duk_uint32_t) duk__hexval(x); |
| 86483 | } else if (x == DUK_ASC_COMMA) { |
| 86484 | if (digits > DUK__MAX_RE_QUANT_DIGITS) { |
| 86485 | goto invalid_quantifier; |
| 86486 | } |
| 86487 | if (val2 != DUK_RE_QUANTIFIER_INFINITE) { |
| 86488 | goto invalid_quantifier; |
| 86489 | } |
| 86490 | if (DUK__L1() == DUK_ASC_RCURLY) { |
| 86491 | /* form: { DecimalDigits , }, val1 = min count */ |
| 86492 | if (digits == 0) { |
| 86493 | goto invalid_quantifier; |
| 86494 | } |
| 86495 | out_token->qmin = val1; |
| 86496 | out_token->qmax = DUK_RE_QUANTIFIER_INFINITE; |
| 86497 | DUK__ADVANCECHARS(lex_ctx, 2); |
| 86498 | break; |
| 86499 | } |
| 86500 | val2 = val1; |
| 86501 | val1 = 0; |
| 86502 | digits = 0; /* not strictly necessary because of lookahead '}' above */ |
| 86503 | } else if (x == DUK_ASC_RCURLY) { |
| 86504 | if (digits > DUK__MAX_RE_QUANT_DIGITS) { |
| 86505 | goto invalid_quantifier; |
| 86506 | } |
| 86507 | if (digits == 0) { |
| 86508 | goto invalid_quantifier; |
| 86509 | } |
| 86510 | if (val2 != DUK_RE_QUANTIFIER_INFINITE) { |
| 86511 | /* val2 = min count, val1 = max count */ |
| 86512 | out_token->qmin = val2; |
| 86513 | out_token->qmax = val1; |
| 86514 | } else { |
| 86515 | /* val1 = count */ |
| 86516 | out_token->qmin = val1; |
| 86517 | out_token->qmax = val1; |
| 86518 | } |
| 86519 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 86520 | break; |
| 86521 | } else { |
| 86522 | goto invalid_quantifier; |
| 86523 | } |
| 86524 | } |
| 86525 | if (DUK__L0() == DUK_ASC_QUESTION) { |
| 86526 | out_token->greedy = 0; |
| 86527 | DUK__ADVANCECHARS(lex_ctx, 1); |
| 86528 | } else { |
| 86529 | out_token->greedy = 1; |
| 86530 | } |
| 86531 | advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER); |
| 86532 | break; |
| 86533 | invalid_quantifier: |
| 86534 | #if defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86535 | /* Failed to match the quantifier, restore lexer and parse |
| 86536 | * opening brace as a literal. |
| 86537 | */ |
| 86538 | DUK_LEXER_SETPOINT(lex_ctx, &lex_pt); |
| 86539 | advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR); |
| 86540 | out_token->num = DUK_ASC_LCURLY; |
| 86541 | #else |
| 86542 | goto fail_quantifier; |
| 86543 | #endif |
| 86544 | break; |
| 86545 | } |
| 86546 | case DUK_ASC_PERIOD: { |
| 86547 | advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD); |
| 86548 | break; |
| 86549 | } |
| 86550 | case DUK_ASC_BACKSLASH: { |
| 86551 | /* The E5.1 specification does not seem to allow IdentifierPart characters |
| 86552 | * to be used as identity escapes. Unfortunately this includes '$', which |
| 86553 | * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'. |
| 86554 | * Many other implementations (including V8 and Rhino, for instance) do |
| 86555 | * accept '\$' as a valid identity escape, which is quite pragmatic, and |
| 86556 | * ES2015 Annex B relaxes the rules to allow these (and other) real world forms. |
| 86557 | */ |
| 86558 | |
| 86559 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */ |
| 86560 | if (y == DUK_ASC_LC_B) { |
| 86561 | advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY); |
| 86562 | } else if (y == DUK_ASC_UC_B) { |
| 86563 | advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY); |
| 86564 | } else if (y == DUK_ASC_LC_F) { |
| 86565 | out_token->num = 0x000c; |
| 86566 | } else if (y == DUK_ASC_LC_N) { |
| 86567 | out_token->num = 0x000a; |
| 86568 | } else if (y == DUK_ASC_LC_T) { |
| 86569 | out_token->num = 0x0009; |
| 86570 | } else if (y == DUK_ASC_LC_R) { |
| 86571 | out_token->num = 0x000d; |
| 86572 | } else if (y == DUK_ASC_LC_V) { |
| 86573 | out_token->num = 0x000b; |
| 86574 | } else if (y == DUK_ASC_LC_C) { |
| 86575 | x = DUK__L2(); |
| 86576 | if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) || |
| 86577 | (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) { |
| 86578 | out_token->num = (duk_uint32_t) (x % 32); |
| 86579 | advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR); |
| 86580 | } else { |
| 86581 | goto fail_escape; |
| 86582 | } |
| 86583 | } else if (y == DUK_ASC_LC_X || y == DUK_ASC_LC_U) { |
| 86584 | /* The token value is the Unicode codepoint without |
| 86585 | * it being decode into surrogate pair characters |
| 86586 | * here. The \u{H+} is only allowed in Unicode mode |
| 86587 | * which we don't support yet. |
| 86588 | */ |
| 86589 | out_token->num = (duk_uint32_t) duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/); |
| 86590 | advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_CHAR); |
| 86591 | } else if (y == DUK_ASC_LC_D) { |
| 86592 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT); |
| 86593 | } else if (y == DUK_ASC_UC_D) { |
| 86594 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT); |
| 86595 | } else if (y == DUK_ASC_LC_S) { |
| 86596 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE); |
| 86597 | } else if (y == DUK_ASC_UC_S) { |
| 86598 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE); |
| 86599 | } else if (y == DUK_ASC_LC_W) { |
| 86600 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR); |
| 86601 | } else if (y == DUK_ASC_UC_W) { |
| 86602 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR); |
| 86603 | } else if (DUK__ISDIGIT(y)) { |
| 86604 | /* E5 Section 15.10.2.11 */ |
| 86605 | if (y == DUK_ASC_0) { |
| 86606 | if (DUK__ISDIGIT(DUK__L2())) { |
| 86607 | goto fail_escape; |
| 86608 | } |
| 86609 | out_token->num = 0x0000; |
| 86610 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); |
| 86611 | } else { |
| 86612 | /* XXX: shared parsing? */ |
| 86613 | duk_uint32_t val = 0; |
| 86614 | duk_small_int_t i; |
| 86615 | for (i = 0; ; i++) { |
| 86616 | if (i >= DUK__MAX_RE_DECESC_DIGITS) { |
| 86617 | goto fail_escape; |
| 86618 | } |
| 86619 | DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */ |
| 86620 | x = DUK__L0(); |
| 86621 | if (!DUK__ISDIGIT(x)) { |
| 86622 | break; |
| 86623 | } |
| 86624 | val = val * 10 + (duk_uint32_t) duk__hexval(x); |
| 86625 | } |
| 86626 | /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */ |
| 86627 | advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE); |
| 86628 | out_token->num = val; |
| 86629 | } |
| 86630 | #if defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86631 | } else if (y >= 0) { |
| 86632 | /* For ES2015 Annex B, accept any source character as identity |
| 86633 | * escape except 'c' which is used for control characters. |
| 86634 | * http://www.ecma-international.org/ecma-262/6.0/#sec-regular-expressions-patterns |
| 86635 | * Careful not to match end-of-buffer (<0) here. |
| 86636 | * This is not yet full ES2015 Annex B because cases above |
| 86637 | * (like hex escape) won't backtrack. |
| 86638 | */ |
| 86639 | DUK_ASSERT(y != DUK_ASC_LC_C); /* covered above */ |
| 86640 | #else /* DUK_USE_ES6_REGEXP_SYNTAX */ |
| 86641 | } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) || |
| 86642 | y == DUK_UNICODE_CP_ZWNJ || |
| 86643 | y == DUK_UNICODE_CP_ZWJ) { |
| 86644 | /* For ES5.1 identity escapes are not allowed for identifier |
| 86645 | * parts. This conflicts with a lot of real world code as this |
| 86646 | * doesn't e.g. allow escaping a dollar sign as /\$/, see |
| 86647 | * test-regexp-identity-escape-dollar.js. |
| 86648 | */ |
| 86649 | #endif /* DUK_USE_ES6_REGEXP_SYNTAX */ |
| 86650 | out_token->num = (duk_uint32_t) y; |
| 86651 | } else { |
| 86652 | goto fail_escape; |
| 86653 | } |
| 86654 | break; |
| 86655 | } |
| 86656 | case DUK_ASC_LPAREN: { |
| 86657 | /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */ |
| 86658 | |
| 86659 | if (y == DUK_ASC_QUESTION) { |
| 86660 | if (DUK__L2() == DUK_ASC_EQUALS) { |
| 86661 | /* (?= */ |
| 86662 | advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD); |
| 86663 | } else if (DUK__L2() == DUK_ASC_EXCLAMATION) { |
| 86664 | /* (?! */ |
| 86665 | advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD); |
| 86666 | } else if (DUK__L2() == DUK_ASC_COLON) { |
| 86667 | /* (?: */ |
| 86668 | advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP); |
| 86669 | } else { |
| 86670 | goto fail_group; |
| 86671 | } |
| 86672 | } else { |
| 86673 | /* ( */ |
| 86674 | advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP); |
| 86675 | } |
| 86676 | break; |
| 86677 | } |
| 86678 | case DUK_ASC_RPAREN: { |
| 86679 | advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP); |
| 86680 | break; |
| 86681 | } |
| 86682 | case DUK_ASC_LBRACKET: { |
| 86683 | /* |
| 86684 | * To avoid creating a heavy intermediate value for the list of ranges, |
| 86685 | * only the start token ('[' or '[^') is parsed here. The regexp |
| 86686 | * compiler parses the ranges itself. |
| 86687 | */ |
| 86688 | |
| 86689 | /* XXX: with DUK_USE_ES6_REGEXP_SYNTAX we should allow left bracket |
| 86690 | * literal too, but it's not easy to parse without backtracking. |
| 86691 | */ |
| 86692 | |
| 86693 | advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS); |
| 86694 | if (y == DUK_ASC_CARET) { |
| 86695 | advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED); |
| 86696 | } |
| 86697 | break; |
| 86698 | } |
| 86699 | #if !defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86700 | case DUK_ASC_RCURLY: |
| 86701 | case DUK_ASC_RBRACKET: { |
| 86702 | /* Although these could be parsed as PatternCharacters unambiguously (here), |
| 86703 | * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters. |
| 86704 | */ |
| 86705 | goto fail_invalid_char; |
| 86706 | break; |
| 86707 | } |
| 86708 | #endif |
| 86709 | case -1: { |
| 86710 | /* EOF */ |
| 86711 | advtok = DUK__ADVTOK(0, DUK_TOK_EOF); |
| 86712 | break; |
| 86713 | } |
| 86714 | default: { |
| 86715 | /* PatternCharacter, all excluded characters are matched by cases above */ |
| 86716 | advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR); |
| 86717 | out_token->num = (duk_uint32_t) x; |
| 86718 | break; |
| 86719 | } |
| 86720 | } |
| 86721 | |
| 86722 | /* |
| 86723 | * Shared exit path |
| 86724 | */ |
| 86725 | |
| 86726 | DUK__ADVANCEBYTES(lex_ctx, advtok >> 8); |
| 86727 | out_token->t = advtok & 0xff; |
| 86728 | return; |
| 86729 | |
| 86730 | fail_token_limit: |
| 86731 | DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT); |
| 86732 | DUK_WO_NORETURN(return;); |
| 86733 | |
| 86734 | fail_escape: |
| 86735 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); |
| 86736 | DUK_WO_NORETURN(return;); |
| 86737 | |
| 86738 | fail_group: |
| 86739 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP); |
| 86740 | DUK_WO_NORETURN(return;); |
| 86741 | |
| 86742 | #if !defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86743 | fail_invalid_char: |
| 86744 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER); |
| 86745 | DUK_WO_NORETURN(return;); |
| 86746 | |
| 86747 | fail_quantifier: |
| 86748 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_QUANTIFIER); |
| 86749 | DUK_WO_NORETURN(return;); |
| 86750 | #endif |
| 86751 | } |
| 86752 | |
| 86753 | /* |
| 86754 | * Special parser for character classes; calls callback for every |
| 86755 | * range parsed and returns the number of ranges present. |
| 86756 | */ |
| 86757 | |
| 86758 | /* XXX: this duplicates functionality in duk_regexp.c where a similar loop is |
| 86759 | * required anyway. We could use that BUT we need to update the regexp compiler |
| 86760 | * 'nranges' too. Work this out a bit more cleanly to save space. |
| 86761 | */ |
| 86762 | |
| 86763 | /* XXX: the handling of character range detection is a bit convoluted. |
| 86764 | * Try to simplify and make smaller. |
| 86765 | */ |
| 86766 | |
| 86767 | /* XXX: logic for handling character ranges is now incorrect, it will accept |
| 86768 | * e.g. [\d-z] whereas it should croak from it? SMJS accepts this too, though. |
| 86769 | * |
| 86770 | * Needs a read through and a lot of additional tests. |
| 86771 | */ |
| 86772 | |
| 86773 | DUK_LOCAL |
| 86774 | void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx, |
| 86775 | duk_re_range_callback gen_range, |
| 86776 | void *userdata, |
| 86777 | const duk_uint16_t *ranges, |
| 86778 | duk_small_int_t num) { |
| 86779 | const duk_uint16_t *ranges_end; |
| 86780 | |
| 86781 | DUK_UNREF(lex_ctx); |
| 86782 | |
| 86783 | ranges_end = ranges + num; |
| 86784 | while (ranges < ranges_end) { |
| 86785 | /* mark range 'direct', bypass canonicalization (see Wiki) */ |
| 86786 | gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1); |
| 86787 | ranges += 2; |
| 86788 | } |
| 86789 | } |
| 86790 | |
| 86791 | DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) { |
| 86792 | duk_codepoint_t start = -1; |
| 86793 | duk_codepoint_t ch; |
| 86794 | duk_codepoint_t x; |
| 86795 | duk_bool_t dash = 0; |
| 86796 | duk_small_uint_t adv = 0; |
| 86797 | |
| 86798 | DUK_DD(DUK_DDPRINT("parsing regexp ranges" )); |
| 86799 | |
| 86800 | for (;;) { |
| 86801 | DUK__ADVANCECHARS(lex_ctx, adv); |
| 86802 | adv = 1; |
| 86803 | |
| 86804 | x = DUK__L0(); |
| 86805 | |
| 86806 | ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */ |
| 86807 | DUK_UNREF(ch); |
| 86808 | |
| 86809 | if (x < 0) { |
| 86810 | goto fail_unterm_charclass; |
| 86811 | } else if (x == DUK_ASC_RBRACKET) { |
| 86812 | if (start >= 0) { |
| 86813 | gen_range(userdata, start, start, 0); |
| 86814 | } |
| 86815 | DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */ |
| 86816 | break; |
| 86817 | } else if (x == DUK_ASC_MINUS) { |
| 86818 | if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) { |
| 86819 | /* '-' as a range indicator */ |
| 86820 | dash = 1; |
| 86821 | continue; |
| 86822 | } else { |
| 86823 | /* '-' verbatim */ |
| 86824 | ch = x; |
| 86825 | } |
| 86826 | } else if (x == DUK_ASC_BACKSLASH) { |
| 86827 | /* |
| 86828 | * The escapes are same as outside a character class, except that \b has a |
| 86829 | * different meaning, and \B and backreferences are prohibited (see E5 |
| 86830 | * Section 15.10.2.19). However, it's difficult to share code because we |
| 86831 | * handle e.g. "\n" very differently: here we generate a single character |
| 86832 | * range for it. |
| 86833 | */ |
| 86834 | |
| 86835 | /* XXX: ES2015 surrogate pair handling. */ |
| 86836 | |
| 86837 | x = DUK__L1(); |
| 86838 | |
| 86839 | adv = 2; |
| 86840 | |
| 86841 | if (x == DUK_ASC_LC_B) { |
| 86842 | /* Note: '\b' in char class is different than outside (assertion), |
| 86843 | * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part() |
| 86844 | * check below. |
| 86845 | */ |
| 86846 | ch = 0x0008; |
| 86847 | } else if (x == DUK_ASC_LC_F) { |
| 86848 | ch = 0x000c; |
| 86849 | } else if (x == DUK_ASC_LC_N) { |
| 86850 | ch = 0x000a; |
| 86851 | } else if (x == DUK_ASC_LC_T) { |
| 86852 | ch = 0x0009; |
| 86853 | } else if (x == DUK_ASC_LC_R) { |
| 86854 | ch = 0x000d; |
| 86855 | } else if (x == DUK_ASC_LC_V) { |
| 86856 | ch = 0x000b; |
| 86857 | } else if (x == DUK_ASC_LC_C) { |
| 86858 | x = DUK__L2(); |
| 86859 | adv = 3; |
| 86860 | if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) || |
| 86861 | (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) { |
| 86862 | ch = (x % 32); |
| 86863 | } else { |
| 86864 | goto fail_escape; |
| 86865 | } |
| 86866 | } else if (x == DUK_ASC_LC_X || x == DUK_ASC_LC_U) { |
| 86867 | /* The \u{H+} form is only allowed in Unicode mode which |
| 86868 | * we don't support yet. |
| 86869 | */ |
| 86870 | ch = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/); |
| 86871 | adv = 0; |
| 86872 | } else if (x == DUK_ASC_LC_D) { |
| 86873 | duk__emit_u16_direct_ranges(lex_ctx, |
| 86874 | gen_range, |
| 86875 | userdata, |
| 86876 | duk_unicode_re_ranges_digit, |
| 86877 | sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t)); |
| 86878 | ch = -1; |
| 86879 | } else if (x == DUK_ASC_UC_D) { |
| 86880 | duk__emit_u16_direct_ranges(lex_ctx, |
| 86881 | gen_range, |
| 86882 | userdata, |
| 86883 | duk_unicode_re_ranges_not_digit, |
| 86884 | sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t)); |
| 86885 | ch = -1; |
| 86886 | } else if (x == DUK_ASC_LC_S) { |
| 86887 | duk__emit_u16_direct_ranges(lex_ctx, |
| 86888 | gen_range, |
| 86889 | userdata, |
| 86890 | duk_unicode_re_ranges_white, |
| 86891 | sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t)); |
| 86892 | ch = -1; |
| 86893 | } else if (x == DUK_ASC_UC_S) { |
| 86894 | duk__emit_u16_direct_ranges(lex_ctx, |
| 86895 | gen_range, |
| 86896 | userdata, |
| 86897 | duk_unicode_re_ranges_not_white, |
| 86898 | sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t)); |
| 86899 | ch = -1; |
| 86900 | } else if (x == DUK_ASC_LC_W) { |
| 86901 | duk__emit_u16_direct_ranges(lex_ctx, |
| 86902 | gen_range, |
| 86903 | userdata, |
| 86904 | duk_unicode_re_ranges_wordchar, |
| 86905 | sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t)); |
| 86906 | ch = -1; |
| 86907 | } else if (x == DUK_ASC_UC_W) { |
| 86908 | duk__emit_u16_direct_ranges(lex_ctx, |
| 86909 | gen_range, |
| 86910 | userdata, |
| 86911 | duk_unicode_re_ranges_not_wordchar, |
| 86912 | sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t)); |
| 86913 | ch = -1; |
| 86914 | } else if (DUK__ISDIGIT(x)) { |
| 86915 | /* DecimalEscape, only \0 is allowed, no leading |
| 86916 | * zeroes are allowed. |
| 86917 | * |
| 86918 | * ES2015 Annex B also allows (maximal match) legacy |
| 86919 | * octal escapes up to \377 and \8 and \9 are |
| 86920 | * accepted as literal '8' and '9', also in strict mode. |
| 86921 | */ |
| 86922 | |
| 86923 | #if defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86924 | ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/); |
| 86925 | DUK_ASSERT(ch >= 0); /* no rejections */ |
| 86926 | #else |
| 86927 | if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) { |
| 86928 | ch = 0x0000; |
| 86929 | } else { |
| 86930 | goto fail_escape; |
| 86931 | } |
| 86932 | #endif |
| 86933 | #if defined(DUK_USE_ES6_REGEXP_SYNTAX) |
| 86934 | } else if (x >= 0) { |
| 86935 | /* IdentityEscape: ES2015 Annex B allows almost all |
| 86936 | * source characters here. Match anything except |
| 86937 | * EOF here. |
| 86938 | */ |
| 86939 | ch = x; |
| 86940 | #else /* DUK_USE_ES6_REGEXP_SYNTAX */ |
| 86941 | } else if (!duk_unicode_is_identifier_part(x)) { |
| 86942 | /* IdentityEscape: ES5.1 doesn't allow identity escape |
| 86943 | * for identifier part characters, which conflicts with |
| 86944 | * some real world code. For example, it doesn't allow |
| 86945 | * /[\$]/ which is awkward. |
| 86946 | */ |
| 86947 | ch = x; |
| 86948 | #endif /* DUK_USE_ES6_REGEXP_SYNTAX */ |
| 86949 | } else { |
| 86950 | goto fail_escape; |
| 86951 | } |
| 86952 | } else { |
| 86953 | /* character represents itself */ |
| 86954 | ch = x; |
| 86955 | } |
| 86956 | |
| 86957 | /* ch is a literal character here or -1 if parsed entity was |
| 86958 | * an escape such as "\s". |
| 86959 | */ |
| 86960 | |
| 86961 | if (ch < 0) { |
| 86962 | /* multi-character sets not allowed as part of ranges, see |
| 86963 | * E5 Section 15.10.2.15, abstract operation CharacterRange. |
| 86964 | */ |
| 86965 | if (start >= 0) { |
| 86966 | if (dash) { |
| 86967 | goto fail_range; |
| 86968 | } else { |
| 86969 | gen_range(userdata, start, start, 0); |
| 86970 | start = -1; |
| 86971 | /* dash is already 0 */ |
| 86972 | } |
| 86973 | } |
| 86974 | } else { |
| 86975 | if (start >= 0) { |
| 86976 | if (dash) { |
| 86977 | if (start > ch) { |
| 86978 | goto fail_range; |
| 86979 | } |
| 86980 | gen_range(userdata, start, ch, 0); |
| 86981 | start = -1; |
| 86982 | dash = 0; |
| 86983 | } else { |
| 86984 | gen_range(userdata, start, start, 0); |
| 86985 | start = ch; |
| 86986 | /* dash is already 0 */ |
| 86987 | } |
| 86988 | } else { |
| 86989 | start = ch; |
| 86990 | } |
| 86991 | } |
| 86992 | } |
| 86993 | |
| 86994 | return; |
| 86995 | |
| 86996 | fail_escape: |
| 86997 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE); |
| 86998 | DUK_WO_NORETURN(return;); |
| 86999 | |
| 87000 | fail_range: |
| 87001 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_RANGE); |
| 87002 | DUK_WO_NORETURN(return;); |
| 87003 | |
| 87004 | fail_unterm_charclass: |
| 87005 | DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_CHARCLASS); |
| 87006 | DUK_WO_NORETURN(return;); |
| 87007 | } |
| 87008 | |
| 87009 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 87010 | |
| 87011 | /* automatic undefs */ |
| 87012 | #undef DUK__ADVANCEBYTES |
| 87013 | #undef DUK__ADVANCECHARS |
| 87014 | #undef DUK__ADVTOK |
| 87015 | #undef DUK__APPENDBUFFER |
| 87016 | #undef DUK__APPENDBUFFER_ASCII |
| 87017 | #undef DUK__INITBUFFER |
| 87018 | #undef DUK__ISDIGIT |
| 87019 | #undef DUK__ISDIGIT03 |
| 87020 | #undef DUK__ISDIGIT47 |
| 87021 | #undef DUK__ISHEXDIGIT |
| 87022 | #undef DUK__ISOCTDIGIT |
| 87023 | #undef DUK__L0 |
| 87024 | #undef DUK__L1 |
| 87025 | #undef DUK__L2 |
| 87026 | #undef DUK__L3 |
| 87027 | #undef DUK__L4 |
| 87028 | #undef DUK__L5 |
| 87029 | #undef DUK__LOOKUP |
| 87030 | #undef DUK__MAX_RE_DECESC_DIGITS |
| 87031 | #undef DUK__MAX_RE_QUANT_DIGITS |
| 87032 | #line 1 "duk_numconv.c" |
| 87033 | /* |
| 87034 | * Number-to-string and string-to-number conversions. |
| 87035 | * |
| 87036 | * Slow path number-to-string and string-to-number conversion is based on |
| 87037 | * a Dragon4 variant, with fast paths for small integers. Big integer |
| 87038 | * arithmetic is needed for guaranteeing that the conversion is correct |
| 87039 | * and uses a minimum number of digits. The big number arithmetic has a |
| 87040 | * fixed maximum size and does not require dynamic allocations. |
| 87041 | * |
| 87042 | * See: doc/number-conversion.rst. |
| 87043 | */ |
| 87044 | |
| 87045 | /* #include duk_internal.h -> already included */ |
| 87046 | |
| 87047 | #define DUK__IEEE_DOUBLE_EXP_BIAS 1023 |
| 87048 | #define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */ |
| 87049 | |
| 87050 | #define DUK__DIGITCHAR(x) duk_lc_digits[(x)] |
| 87051 | |
| 87052 | /* |
| 87053 | * Tables generated with util/gennumdigits.py. |
| 87054 | * |
| 87055 | * duk__str2num_digits_for_radix indicates, for each radix, how many input |
| 87056 | * digits should be considered significant for string-to-number conversion. |
| 87057 | * The input is also padded to this many digits to give the Dragon4 |
| 87058 | * conversion enough (apparent) precision to work with. |
| 87059 | * |
| 87060 | * duk__str2num_exp_limits indicates, for each radix, the radix-specific |
| 87061 | * minimum/maximum exponent values (for a Dragon4 integer mantissa) |
| 87062 | * below and above which the number is guaranteed to underflow to zero |
| 87063 | * or overflow to Infinity. This allows parsing to keep bigint values |
| 87064 | * bounded. |
| 87065 | */ |
| 87066 | |
| 87067 | DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = { |
| 87068 | 69, 44, 35, 30, 27, 25, 23, 22, 20, 20, /* 2 to 11 */ |
| 87069 | 20, 19, 19, 18, 18, 17, 17, 17, 16, 16, /* 12 to 21 */ |
| 87070 | 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, /* 22 to 31 */ |
| 87071 | 14, 14, 14, 14, 14 /* 31 to 36 */ |
| 87072 | }; |
| 87073 | |
| 87074 | typedef struct { |
| 87075 | duk_int16_t upper; |
| 87076 | duk_int16_t lower; |
| 87077 | } duk__exp_limits; |
| 87078 | |
| 87079 | DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = { |
| 87080 | { 957, -1147 }, { 605, -725 }, { 479, -575 }, { 414, -496 }, |
| 87081 | { 372, -446 }, { 342, -411 }, { 321, -384 }, { 304, -364 }, |
| 87082 | { 291, -346 }, { 279, -334 }, { 268, -323 }, { 260, -312 }, |
| 87083 | { 252, -304 }, { 247, -296 }, { 240, -289 }, { 236, -283 }, |
| 87084 | { 231, -278 }, { 227, -273 }, { 223, -267 }, { 220, -263 }, |
| 87085 | { 216, -260 }, { 213, -256 }, { 210, -253 }, { 208, -249 }, |
| 87086 | { 205, -246 }, { 203, -244 }, { 201, -241 }, { 198, -239 }, |
| 87087 | { 196, -237 }, { 195, -234 }, { 193, -232 }, { 191, -230 }, |
| 87088 | { 190, -228 }, { 188, -226 }, { 187, -225 }, |
| 87089 | }; |
| 87090 | |
| 87091 | /* |
| 87092 | * Limited functionality bigint implementation. |
| 87093 | * |
| 87094 | * Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits, |
| 87095 | * with the caller responsible for ensuring this is never exceeded. No memory |
| 87096 | * allocation (except stack) is needed for bigint computation. Operations |
| 87097 | * have been tailored for number conversion needs. |
| 87098 | * |
| 87099 | * Argument order is "assignment order", i.e. target first, then arguments: |
| 87100 | * x <- y * z --> duk__bi_mul(x, y, z); |
| 87101 | */ |
| 87102 | |
| 87103 | /* This upper value has been experimentally determined; debug build will check |
| 87104 | * bigint size with assertions. |
| 87105 | */ |
| 87106 | #define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */ |
| 87107 | |
| 87108 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 87109 | #define DUK__BI_PRINT(name,x) duk__bi_print((name),(x)) |
| 87110 | #else |
| 87111 | #define DUK__BI_PRINT(name,x) |
| 87112 | #endif |
| 87113 | |
| 87114 | /* Current size is about 152 bytes. */ |
| 87115 | typedef struct { |
| 87116 | duk_small_int_t n; |
| 87117 | duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */ |
| 87118 | } duk__bigint; |
| 87119 | |
| 87120 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 87121 | DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) { |
| 87122 | /* Overestimate required size; debug code so not critical to be tight. */ |
| 87123 | char buf[DUK__BI_MAX_PARTS * 9 + 64]; |
| 87124 | char *p = buf; |
| 87125 | duk_small_int_t i; |
| 87126 | |
| 87127 | /* No NUL term checks in this debug code. */ |
| 87128 | p += DUK_SPRINTF(p, "%p n=%ld" , (void *) x, (long) x->n); |
| 87129 | if (x->n == 0) { |
| 87130 | p += DUK_SPRINTF(p, " 0" ); |
| 87131 | } |
| 87132 | for (i = x->n - 1; i >= 0; i--) { |
| 87133 | p += DUK_SPRINTF(p, " %08lx" , (unsigned long) x->v[i]); |
| 87134 | } |
| 87135 | |
| 87136 | DUK_DDD(DUK_DDDPRINT("%s: %s" , (const char *) name, (const char *) buf)); |
| 87137 | } |
| 87138 | #endif |
| 87139 | |
| 87140 | #if defined(DUK_USE_ASSERTIONS) |
| 87141 | DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) { |
| 87142 | return (duk_small_int_t) |
| 87143 | ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ && |
| 87144 | ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ ); |
| 87145 | } |
| 87146 | #endif |
| 87147 | |
| 87148 | DUK_LOCAL void duk__bi_normalize(duk__bigint *x) { |
| 87149 | duk_small_int_t i; |
| 87150 | |
| 87151 | for (i = x->n - 1; i >= 0; i--) { |
| 87152 | if (x->v[i] != 0) { |
| 87153 | break; |
| 87154 | } |
| 87155 | } |
| 87156 | |
| 87157 | /* Note: if 'x' is zero, x->n becomes 0 here */ |
| 87158 | x->n = i + 1; |
| 87159 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87160 | } |
| 87161 | |
| 87162 | /* x <- y */ |
| 87163 | DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) { |
| 87164 | duk_small_int_t n; |
| 87165 | |
| 87166 | n = y->n; |
| 87167 | x->n = n; |
| 87168 | /* No need to special case n == 0. */ |
| 87169 | duk_memcpy((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * (size_t) n)); |
| 87170 | } |
| 87171 | |
| 87172 | DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) { |
| 87173 | if (v == 0U) { |
| 87174 | x->n = 0; |
| 87175 | } else { |
| 87176 | x->n = 1; |
| 87177 | x->v[0] = v; |
| 87178 | } |
| 87179 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87180 | } |
| 87181 | |
| 87182 | /* Return value: <0 <=> x < y |
| 87183 | * 0 <=> x == y |
| 87184 | * >0 <=> x > y |
| 87185 | */ |
| 87186 | DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) { |
| 87187 | duk_small_int_t i, nx, ny; |
| 87188 | duk_uint32_t tx, ty; |
| 87189 | |
| 87190 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87191 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87192 | |
| 87193 | nx = x->n; |
| 87194 | ny = y->n; |
| 87195 | if (nx > ny) { |
| 87196 | goto ret_gt; |
| 87197 | } |
| 87198 | if (nx < ny) { |
| 87199 | goto ret_lt; |
| 87200 | } |
| 87201 | for (i = nx - 1; i >= 0; i--) { |
| 87202 | tx = x->v[i]; |
| 87203 | ty = y->v[i]; |
| 87204 | |
| 87205 | if (tx > ty) { |
| 87206 | goto ret_gt; |
| 87207 | } |
| 87208 | if (tx < ty) { |
| 87209 | goto ret_lt; |
| 87210 | } |
| 87211 | } |
| 87212 | |
| 87213 | return 0; |
| 87214 | |
| 87215 | ret_gt: |
| 87216 | return 1; |
| 87217 | |
| 87218 | ret_lt: |
| 87219 | return -1; |
| 87220 | } |
| 87221 | |
| 87222 | /* x <- y + z */ |
| 87223 | #if defined(DUK_USE_64BIT_OPS) |
| 87224 | DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) { |
| 87225 | duk_uint64_t tmp; |
| 87226 | duk_small_int_t i, ny, nz; |
| 87227 | |
| 87228 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87229 | DUK_ASSERT(duk__bi_is_valid(z)); |
| 87230 | |
| 87231 | if (z->n > y->n) { |
| 87232 | duk__bigint *t; |
| 87233 | t = y; y = z; z = t; |
| 87234 | } |
| 87235 | DUK_ASSERT(y->n >= z->n); |
| 87236 | |
| 87237 | ny = y->n; nz = z->n; |
| 87238 | tmp = 0U; |
| 87239 | for (i = 0; i < ny; i++) { |
| 87240 | DUK_ASSERT(i < DUK__BI_MAX_PARTS); |
| 87241 | tmp += y->v[i]; |
| 87242 | if (i < nz) { |
| 87243 | tmp += z->v[i]; |
| 87244 | } |
| 87245 | x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL); |
| 87246 | tmp = tmp >> 32; |
| 87247 | } |
| 87248 | if (tmp != 0U) { |
| 87249 | DUK_ASSERT(i < DUK__BI_MAX_PARTS); |
| 87250 | x->v[i++] = (duk_uint32_t) tmp; |
| 87251 | } |
| 87252 | x->n = i; |
| 87253 | DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS); |
| 87254 | |
| 87255 | /* no need to normalize */ |
| 87256 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87257 | } |
| 87258 | #else /* DUK_USE_64BIT_OPS */ |
| 87259 | DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) { |
| 87260 | duk_uint32_t carry, tmp1, tmp2; |
| 87261 | duk_small_int_t i, ny, nz; |
| 87262 | |
| 87263 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87264 | DUK_ASSERT(duk__bi_is_valid(z)); |
| 87265 | |
| 87266 | if (z->n > y->n) { |
| 87267 | duk__bigint *t; |
| 87268 | t = y; y = z; z = t; |
| 87269 | } |
| 87270 | DUK_ASSERT(y->n >= z->n); |
| 87271 | |
| 87272 | ny = y->n; nz = z->n; |
| 87273 | carry = 0U; |
| 87274 | for (i = 0; i < ny; i++) { |
| 87275 | /* Carry is detected based on wrapping which relies on exact 32-bit |
| 87276 | * types. |
| 87277 | */ |
| 87278 | DUK_ASSERT(i < DUK__BI_MAX_PARTS); |
| 87279 | tmp1 = y->v[i]; |
| 87280 | tmp2 = tmp1; |
| 87281 | if (i < nz) { |
| 87282 | tmp2 += z->v[i]; |
| 87283 | } |
| 87284 | |
| 87285 | /* Careful with carry condition: |
| 87286 | * - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678) |
| 87287 | * - If carry added: 0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678) |
| 87288 | */ |
| 87289 | if (carry) { |
| 87290 | tmp2++; |
| 87291 | carry = (tmp2 <= tmp1 ? 1U : 0U); |
| 87292 | } else { |
| 87293 | carry = (tmp2 < tmp1 ? 1U : 0U); |
| 87294 | } |
| 87295 | |
| 87296 | x->v[i] = tmp2; |
| 87297 | } |
| 87298 | if (carry) { |
| 87299 | DUK_ASSERT(i < DUK__BI_MAX_PARTS); |
| 87300 | DUK_ASSERT(carry == 1U); |
| 87301 | x->v[i++] = carry; |
| 87302 | } |
| 87303 | x->n = i; |
| 87304 | DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS); |
| 87305 | |
| 87306 | /* no need to normalize */ |
| 87307 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87308 | } |
| 87309 | #endif /* DUK_USE_64BIT_OPS */ |
| 87310 | |
| 87311 | /* x <- y + z */ |
| 87312 | DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) { |
| 87313 | duk__bigint tmp; |
| 87314 | |
| 87315 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87316 | |
| 87317 | /* XXX: this could be optimized; there is only one call site now though */ |
| 87318 | duk__bi_set_small(&tmp, z); |
| 87319 | duk__bi_add(x, y, &tmp); |
| 87320 | |
| 87321 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87322 | } |
| 87323 | |
| 87324 | #if 0 /* unused */ |
| 87325 | /* x <- x + y, use t as temp */ |
| 87326 | DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) { |
| 87327 | duk__bi_add(t, x, y); |
| 87328 | duk__bi_copy(x, t); |
| 87329 | } |
| 87330 | #endif |
| 87331 | |
| 87332 | /* x <- y - z, require x >= y => z >= 0, i.e. y >= z */ |
| 87333 | #if defined(DUK_USE_64BIT_OPS) |
| 87334 | DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) { |
| 87335 | duk_small_int_t i, ny, nz; |
| 87336 | duk_uint32_t ty, tz; |
| 87337 | duk_int64_t tmp; |
| 87338 | |
| 87339 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87340 | DUK_ASSERT(duk__bi_is_valid(z)); |
| 87341 | DUK_ASSERT(duk__bi_compare(y, z) >= 0); |
| 87342 | DUK_ASSERT(y->n >= z->n); |
| 87343 | |
| 87344 | ny = y->n; nz = z->n; |
| 87345 | tmp = 0; |
| 87346 | for (i = 0; i < ny; i++) { |
| 87347 | ty = y->v[i]; |
| 87348 | if (i < nz) { |
| 87349 | tz = z->v[i]; |
| 87350 | } else { |
| 87351 | tz = 0; |
| 87352 | } |
| 87353 | tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp; |
| 87354 | x->v[i] = (duk_uint32_t) ((duk_uint64_t) tmp & 0xffffffffUL); |
| 87355 | tmp = tmp >> 32; /* 0 or -1 */ |
| 87356 | } |
| 87357 | DUK_ASSERT(tmp == 0); |
| 87358 | |
| 87359 | x->n = i; |
| 87360 | duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */ |
| 87361 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87362 | } |
| 87363 | #else |
| 87364 | DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) { |
| 87365 | duk_small_int_t i, ny, nz; |
| 87366 | duk_uint32_t tmp1, tmp2, borrow; |
| 87367 | |
| 87368 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87369 | DUK_ASSERT(duk__bi_is_valid(z)); |
| 87370 | DUK_ASSERT(duk__bi_compare(y, z) >= 0); |
| 87371 | DUK_ASSERT(y->n >= z->n); |
| 87372 | |
| 87373 | ny = y->n; nz = z->n; |
| 87374 | borrow = 0U; |
| 87375 | for (i = 0; i < ny; i++) { |
| 87376 | /* Borrow is detected based on wrapping which relies on exact 32-bit |
| 87377 | * types. |
| 87378 | */ |
| 87379 | tmp1 = y->v[i]; |
| 87380 | tmp2 = tmp1; |
| 87381 | if (i < nz) { |
| 87382 | tmp2 -= z->v[i]; |
| 87383 | } |
| 87384 | |
| 87385 | /* Careful with borrow condition: |
| 87386 | * - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678) |
| 87387 | * - If borrow subtracted: 0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678) |
| 87388 | */ |
| 87389 | if (borrow) { |
| 87390 | tmp2--; |
| 87391 | borrow = (tmp2 >= tmp1 ? 1U : 0U); |
| 87392 | } else { |
| 87393 | borrow = (tmp2 > tmp1 ? 1U : 0U); |
| 87394 | } |
| 87395 | |
| 87396 | x->v[i] = tmp2; |
| 87397 | } |
| 87398 | DUK_ASSERT(borrow == 0U); |
| 87399 | |
| 87400 | x->n = i; |
| 87401 | duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */ |
| 87402 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87403 | } |
| 87404 | #endif |
| 87405 | |
| 87406 | #if 0 /* unused */ |
| 87407 | /* x <- y - z */ |
| 87408 | DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) { |
| 87409 | duk__bigint tmp; |
| 87410 | |
| 87411 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87412 | |
| 87413 | /* XXX: this could be optimized */ |
| 87414 | duk__bi_set_small(&tmp, z); |
| 87415 | duk__bi_sub(x, y, &tmp); |
| 87416 | |
| 87417 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87418 | } |
| 87419 | #endif |
| 87420 | |
| 87421 | /* x <- x - y, use t as temp */ |
| 87422 | DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) { |
| 87423 | duk__bi_sub(t, x, y); |
| 87424 | duk__bi_copy(x, t); |
| 87425 | } |
| 87426 | |
| 87427 | /* x <- y * z */ |
| 87428 | DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) { |
| 87429 | duk_small_int_t i, j, nx, nz; |
| 87430 | |
| 87431 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87432 | DUK_ASSERT(duk__bi_is_valid(z)); |
| 87433 | |
| 87434 | nx = y->n + z->n; /* max possible */ |
| 87435 | DUK_ASSERT(nx <= DUK__BI_MAX_PARTS); |
| 87436 | |
| 87437 | if (nx == 0) { |
| 87438 | /* Both inputs are zero; cases where only one is zero can go |
| 87439 | * through main algorithm. |
| 87440 | */ |
| 87441 | x->n = 0; |
| 87442 | return; |
| 87443 | } |
| 87444 | |
| 87445 | duk_memzero((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx)); |
| 87446 | x->n = nx; |
| 87447 | |
| 87448 | nz = z->n; |
| 87449 | for (i = 0; i < y->n; i++) { |
| 87450 | #if defined(DUK_USE_64BIT_OPS) |
| 87451 | duk_uint64_t tmp = 0U; |
| 87452 | for (j = 0; j < nz; j++) { |
| 87453 | tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j]; |
| 87454 | x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL); |
| 87455 | tmp = tmp >> 32; |
| 87456 | } |
| 87457 | if (tmp > 0) { |
| 87458 | DUK_ASSERT(i + j < nx); |
| 87459 | DUK_ASSERT(i + j < DUK__BI_MAX_PARTS); |
| 87460 | DUK_ASSERT(x->v[i+j] == 0U); |
| 87461 | x->v[i+j] = (duk_uint32_t) tmp; |
| 87462 | } |
| 87463 | #else |
| 87464 | /* |
| 87465 | * Multiply + add + carry for 32-bit components using only 16x16->32 |
| 87466 | * multiplies and carry detection based on unsigned overflow. |
| 87467 | * |
| 87468 | * 1st mult, 32-bit: (A*2^16 + B) |
| 87469 | * 2nd mult, 32-bit: (C*2^16 + D) |
| 87470 | * 3rd add, 32-bit: E |
| 87471 | * 4th add, 32-bit: F |
| 87472 | * |
| 87473 | * (AC*2^16 + B) * (C*2^16 + D) + E + F |
| 87474 | * = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F |
| 87475 | * = AC*2^32 + (AD + BC)*2^16 + (BD + E + F) |
| 87476 | * = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F) |
| 87477 | */ |
| 87478 | duk_uint32_t a, b, c, d, e, f; |
| 87479 | duk_uint32_t r, s, t; |
| 87480 | |
| 87481 | a = y->v[i]; b = a & 0xffffUL; a = a >> 16; |
| 87482 | |
| 87483 | f = 0; |
| 87484 | for (j = 0; j < nz; j++) { |
| 87485 | c = z->v[j]; d = c & 0xffffUL; c = c >> 16; |
| 87486 | e = x->v[i+j]; |
| 87487 | |
| 87488 | /* build result as: (r << 32) + s: start with (BD + E + F) */ |
| 87489 | r = 0; |
| 87490 | s = b * d; |
| 87491 | |
| 87492 | /* add E */ |
| 87493 | t = s + e; |
| 87494 | if (t < s) { r++; } /* carry */ |
| 87495 | s = t; |
| 87496 | |
| 87497 | /* add F */ |
| 87498 | t = s + f; |
| 87499 | if (t < s) { r++; } /* carry */ |
| 87500 | s = t; |
| 87501 | |
| 87502 | /* add BC*2^16 */ |
| 87503 | t = b * c; |
| 87504 | r += (t >> 16); |
| 87505 | t = s + ((t & 0xffffUL) << 16); |
| 87506 | if (t < s) { r++; } /* carry */ |
| 87507 | s = t; |
| 87508 | |
| 87509 | /* add AD*2^16 */ |
| 87510 | t = a * d; |
| 87511 | r += (t >> 16); |
| 87512 | t = s + ((t & 0xffffUL) << 16); |
| 87513 | if (t < s) { r++; } /* carry */ |
| 87514 | s = t; |
| 87515 | |
| 87516 | /* add AC*2^32 */ |
| 87517 | t = a * c; |
| 87518 | r += t; |
| 87519 | |
| 87520 | DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx" , |
| 87521 | (unsigned long) y->v[i], (unsigned long) z->v[j], |
| 87522 | (unsigned long) x->v[i+j], (unsigned long) r, |
| 87523 | (unsigned long) s)); |
| 87524 | |
| 87525 | x->v[i+j] = s; |
| 87526 | f = r; |
| 87527 | } |
| 87528 | if (f > 0U) { |
| 87529 | DUK_ASSERT(i + j < nx); |
| 87530 | DUK_ASSERT(i + j < DUK__BI_MAX_PARTS); |
| 87531 | DUK_ASSERT(x->v[i+j] == 0U); |
| 87532 | x->v[i+j] = (duk_uint32_t) f; |
| 87533 | } |
| 87534 | #endif /* DUK_USE_64BIT_OPS */ |
| 87535 | } |
| 87536 | |
| 87537 | duk__bi_normalize(x); |
| 87538 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87539 | } |
| 87540 | |
| 87541 | /* x <- y * z */ |
| 87542 | DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) { |
| 87543 | duk__bigint tmp; |
| 87544 | |
| 87545 | DUK_ASSERT(duk__bi_is_valid(y)); |
| 87546 | |
| 87547 | /* XXX: this could be optimized */ |
| 87548 | duk__bi_set_small(&tmp, z); |
| 87549 | duk__bi_mul(x, y, &tmp); |
| 87550 | |
| 87551 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87552 | } |
| 87553 | |
| 87554 | /* x <- x * y, use t as temp */ |
| 87555 | DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) { |
| 87556 | duk__bi_mul(t, x, y); |
| 87557 | duk__bi_copy(x, t); |
| 87558 | } |
| 87559 | |
| 87560 | /* x <- x * y, use t as temp */ |
| 87561 | DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) { |
| 87562 | duk__bi_mul_small(t, x, y); |
| 87563 | duk__bi_copy(x, t); |
| 87564 | } |
| 87565 | |
| 87566 | DUK_LOCAL int duk__bi_is_even(duk__bigint *x) { |
| 87567 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87568 | return (x->n == 0) || ((x->v[0] & 0x01) == 0); |
| 87569 | } |
| 87570 | |
| 87571 | DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) { |
| 87572 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87573 | return (x->n == 0); /* this is the case for normalized numbers */ |
| 87574 | } |
| 87575 | |
| 87576 | /* Bigint is 2^52. Used to detect normalized IEEE double mantissa values |
| 87577 | * which are at the lowest edge (next floating point value downwards has |
| 87578 | * a different exponent). The lowest mantissa has the form: |
| 87579 | * |
| 87580 | * 1000........000 (52 zeroes; only "hidden bit" is set) |
| 87581 | */ |
| 87582 | DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) { |
| 87583 | DUK_ASSERT(duk__bi_is_valid(x)); |
| 87584 | return (duk_small_int_t) |
| 87585 | (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32))); |
| 87586 | } |
| 87587 | |
| 87588 | /* x <- (1<<y) */ |
| 87589 | DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) { |
| 87590 | duk_small_int_t n, r; |
| 87591 | |
| 87592 | n = (y / 32) + 1; |
| 87593 | DUK_ASSERT(n > 0); |
| 87594 | r = y % 32; |
| 87595 | duk_memzero((void *) x->v, sizeof(duk_uint32_t) * (size_t) n); |
| 87596 | x->n = n; |
| 87597 | x->v[n - 1] = (((duk_uint32_t) 1) << r); |
| 87598 | } |
| 87599 | |
| 87600 | /* x <- b^y; use t1 and t2 as temps */ |
| 87601 | DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_int_t y, duk__bigint *t1, duk__bigint *t2) { |
| 87602 | /* Fast path the binary case */ |
| 87603 | |
| 87604 | DUK_ASSERT(x != t1 && x != t2 && t1 != t2); /* distinct bignums, easy mistake to make */ |
| 87605 | DUK_ASSERT(b >= 0); |
| 87606 | DUK_ASSERT(y >= 0); |
| 87607 | |
| 87608 | if (b == 2) { |
| 87609 | duk__bi_twoexp(x, y); |
| 87610 | return; |
| 87611 | } |
| 87612 | |
| 87613 | /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */ |
| 87614 | |
| 87615 | DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld" , (long) b, (long) y)); |
| 87616 | |
| 87617 | duk__bi_set_small(x, 1); |
| 87618 | duk__bi_set_small(t1, (duk_uint32_t) b); |
| 87619 | for (;;) { |
| 87620 | /* Loop structure ensures that we don't compute t1^2 unnecessarily |
| 87621 | * on the final round, as that might create a bignum exceeding the |
| 87622 | * current DUK__BI_MAX_PARTS limit. |
| 87623 | */ |
| 87624 | if (y & 0x01) { |
| 87625 | duk__bi_mul_copy(x, t1, t2); |
| 87626 | } |
| 87627 | y = y >> 1; |
| 87628 | if (y == 0) { |
| 87629 | break; |
| 87630 | } |
| 87631 | duk__bi_mul_copy(t1, t1, t2); |
| 87632 | } |
| 87633 | |
| 87634 | DUK__BI_PRINT("exp_small result" , x); |
| 87635 | } |
| 87636 | |
| 87637 | /* |
| 87638 | * A Dragon4 number-to-string variant, based on: |
| 87639 | * |
| 87640 | * Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers |
| 87641 | * Accurately" |
| 87642 | * |
| 87643 | * Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers |
| 87644 | * Quickly and Accurately" |
| 87645 | * |
| 87646 | * The current algorithm is based on Figure 1 of the Burger-Dybvig paper, |
| 87647 | * i.e. the base implementation without logarithm estimation speedups |
| 87648 | * (these would increase code footprint considerably). Fixed-format output |
| 87649 | * does not follow the suggestions in the paper; instead, we generate an |
| 87650 | * extra digit and round-with-carry. |
| 87651 | * |
| 87652 | * The same algorithm is used for number parsing (with b=10 and B=2) |
| 87653 | * by generating one extra digit and doing rounding manually. |
| 87654 | * |
| 87655 | * See doc/number-conversion.rst for limitations. |
| 87656 | */ |
| 87657 | |
| 87658 | /* Maximum number of digits generated. */ |
| 87659 | #define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + slack */ |
| 87660 | |
| 87661 | /* Maximum number of characters in formatted value. */ |
| 87662 | #define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + slack */ |
| 87663 | |
| 87664 | /* Number and (minimum) size of bigints in the nc_ctx structure. */ |
| 87665 | #define DUK__NUMCONV_CTX_NUM_BIGINTS 7 |
| 87666 | #define DUK__NUMCONV_CTX_BIGINTS_SIZE (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS) |
| 87667 | |
| 87668 | typedef struct { |
| 87669 | /* Currently about 7*152 = 1064 bytes. The space for these |
| 87670 | * duk__bigints is used also as a temporary buffer for generating |
| 87671 | * the final string. This is a bit awkard; a union would be |
| 87672 | * more correct. |
| 87673 | */ |
| 87674 | duk__bigint f, r, s, mp, mm, t1, t2; |
| 87675 | |
| 87676 | duk_small_int_t is_s2n; /* if 1, doing a string-to-number; else doing a number-to-string */ |
| 87677 | duk_small_int_t is_fixed; /* if 1, doing a fixed format output (not free format) */ |
| 87678 | duk_small_int_t req_digits; /* requested number of output digits; 0 = free-format */ |
| 87679 | duk_small_int_t abs_pos; /* digit position is absolute, not relative */ |
| 87680 | duk_small_int_t e; /* exponent for 'f' */ |
| 87681 | duk_small_int_t b; /* input radix */ |
| 87682 | duk_small_int_t B; /* output radix */ |
| 87683 | duk_small_int_t k; /* see algorithm */ |
| 87684 | duk_small_int_t low_ok; /* see algorithm */ |
| 87685 | duk_small_int_t high_ok; /* see algorithm */ |
| 87686 | duk_small_int_t unequal_gaps; /* m+ != m- (very rarely) */ |
| 87687 | |
| 87688 | /* Buffer used for generated digits, values are in the range [0,B-1]. */ |
| 87689 | duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS]; |
| 87690 | duk_small_int_t count; /* digit count */ |
| 87691 | } duk__numconv_stringify_ctx; |
| 87692 | |
| 87693 | /* Note: computes with 'idx' in assertions, so caller beware. |
| 87694 | * 'idx' is preincremented, i.e. '1' on first call, because it |
| 87695 | * is more convenient for the caller. |
| 87696 | */ |
| 87697 | #define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x) do { \ |
| 87698 | DUK_ASSERT((preinc_idx) - 1 >= 0); \ |
| 87699 | DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \ |
| 87700 | ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \ |
| 87701 | } while (0) |
| 87702 | |
| 87703 | DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) { |
| 87704 | duk_uint8_t *p; |
| 87705 | duk_size_t len; |
| 87706 | duk_small_int_t dig; |
| 87707 | duk_uint32_t t; |
| 87708 | |
| 87709 | DUK_ASSERT(buf != NULL); |
| 87710 | DUK_ASSERT(radix >= 2 && radix <= 36); |
| 87711 | |
| 87712 | /* A 32-bit unsigned integer formats to at most 32 digits (the |
| 87713 | * worst case happens with radix == 2). Output the digits backwards, |
| 87714 | * and use a memmove() to get them in the right place. |
| 87715 | */ |
| 87716 | |
| 87717 | p = buf + 32; |
| 87718 | for (;;) { |
| 87719 | t = x / (duk_uint32_t) radix; |
| 87720 | dig = (duk_small_int_t) (x - t * (duk_uint32_t) radix); |
| 87721 | x = t; |
| 87722 | |
| 87723 | DUK_ASSERT(dig >= 0 && dig < 36); |
| 87724 | *(--p) = DUK__DIGITCHAR(dig); |
| 87725 | |
| 87726 | if (x == 0) { |
| 87727 | break; |
| 87728 | } |
| 87729 | } |
| 87730 | len = (duk_size_t) ((buf + 32) - p); |
| 87731 | |
| 87732 | duk_memmove((void *) buf, (const void *) p, (size_t) len); |
| 87733 | |
| 87734 | return len; |
| 87735 | } |
| 87736 | |
| 87737 | DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) { |
| 87738 | duk_small_int_t lowest_mantissa; |
| 87739 | |
| 87740 | #if 1 |
| 87741 | /* Assume IEEE round-to-even, so that shorter encoding can be used |
| 87742 | * when round-to-even would produce correct result. By removing |
| 87743 | * this check (and having low_ok == high_ok == 0) the results would |
| 87744 | * still be accurate but in some cases longer than necessary. |
| 87745 | */ |
| 87746 | if (duk__bi_is_even(&nc_ctx->f)) { |
| 87747 | DUK_DDD(DUK_DDDPRINT("f is even" )); |
| 87748 | nc_ctx->low_ok = 1; |
| 87749 | nc_ctx->high_ok = 1; |
| 87750 | } else { |
| 87751 | DUK_DDD(DUK_DDDPRINT("f is odd" )); |
| 87752 | nc_ctx->low_ok = 0; |
| 87753 | nc_ctx->high_ok = 0; |
| 87754 | } |
| 87755 | #else |
| 87756 | /* Note: not honoring round-to-even should work but now generates incorrect |
| 87757 | * results. For instance, 1e23 serializes to "a000...", i.e. the first digit |
| 87758 | * equals the radix (10). Scaling stops one step too early in this case. |
| 87759 | * Don't know why this is the case, but since this code path is unused, it |
| 87760 | * doesn't matter. |
| 87761 | */ |
| 87762 | nc_ctx->low_ok = 0; |
| 87763 | nc_ctx->high_ok = 0; |
| 87764 | #endif |
| 87765 | |
| 87766 | /* For string-to-number, pretend we never have the lowest mantissa as there |
| 87767 | * is no natural "precision" for inputs. Having lowest_mantissa == 0, we'll |
| 87768 | * fall into the base cases for both e >= 0 and e < 0. |
| 87769 | */ |
| 87770 | if (nc_ctx->is_s2n) { |
| 87771 | lowest_mantissa = 0; |
| 87772 | } else { |
| 87773 | lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f); |
| 87774 | } |
| 87775 | |
| 87776 | nc_ctx->unequal_gaps = 0; |
| 87777 | if (nc_ctx->e >= 0) { |
| 87778 | /* exponent non-negative (and thus not minimum exponent) */ |
| 87779 | |
| 87780 | if (lowest_mantissa) { |
| 87781 | /* (>= e 0) AND (= f (expt b (- p 1))) |
| 87782 | * |
| 87783 | * be <- (expt b e) == b^e |
| 87784 | * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1) |
| 87785 | * r <- (* f be1 2) == 2 * f * b^(e+1) [if b==2 -> f * b^(e+2)] |
| 87786 | * s <- (* b 2) [if b==2 -> 4] |
| 87787 | * m+ <- be1 == b^(e+1) |
| 87788 | * m- <- be == b^e |
| 87789 | * k <- 0 |
| 87790 | * B <- B |
| 87791 | * low_ok <- round |
| 87792 | * high_ok <- round |
| 87793 | */ |
| 87794 | |
| 87795 | DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); " |
| 87796 | "lowest mantissa value for this exponent -> " |
| 87797 | "unequal gaps" )); |
| 87798 | |
| 87799 | duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */ |
| 87800 | duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, (duk_uint32_t) nc_ctx->b); /* mp <- b^(e+1) */ |
| 87801 | duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2); |
| 87802 | duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */ |
| 87803 | duk__bi_set_small(&nc_ctx->s, (duk_uint32_t) (nc_ctx->b * 2)); /* s <- 2 * b */ |
| 87804 | nc_ctx->unequal_gaps = 1; |
| 87805 | } else { |
| 87806 | /* (>= e 0) AND (not (= f (expt b (- p 1)))) |
| 87807 | * |
| 87808 | * be <- (expt b e) == b^e |
| 87809 | * r <- (* f be 2) == 2 * f * b^e [if b==2 -> f * b^(e+1)] |
| 87810 | * s <- 2 |
| 87811 | * m+ <- be == b^e |
| 87812 | * m- <- be == b^e |
| 87813 | * k <- 0 |
| 87814 | * B <- B |
| 87815 | * low_ok <- round |
| 87816 | * high_ok <- round |
| 87817 | */ |
| 87818 | |
| 87819 | DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); " |
| 87820 | "not lowest mantissa for this exponent -> " |
| 87821 | "equal gaps" )); |
| 87822 | |
| 87823 | duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */ |
| 87824 | duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm); /* mp <- b^e */ |
| 87825 | duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2); |
| 87826 | duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^e */ |
| 87827 | duk__bi_set_small(&nc_ctx->s, 2); /* s <- 2 */ |
| 87828 | } |
| 87829 | } else { |
| 87830 | /* When doing string-to-number, lowest_mantissa is always 0 so |
| 87831 | * the exponent check, while incorrect, won't matter. |
| 87832 | */ |
| 87833 | if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ && |
| 87834 | lowest_mantissa /* lowest mantissa for this exponent*/) { |
| 87835 | /* r <- (* f b 2) [if b==2 -> (* f 4)] |
| 87836 | * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2 [if b==2 -> b^(2-e)] |
| 87837 | * m+ <- b == 2 |
| 87838 | * m- <- 1 |
| 87839 | * k <- 0 |
| 87840 | * B <- B |
| 87841 | * low_ok <- round |
| 87842 | * high_ok <- round |
| 87843 | */ |
| 87844 | |
| 87845 | DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and " |
| 87846 | "lowest mantissa for this exponent -> " |
| 87847 | "unequal gaps" )); |
| 87848 | |
| 87849 | duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, (duk_uint32_t) (nc_ctx->b * 2)); /* r <- (2 * b) * f */ |
| 87850 | 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 */ |
| 87851 | duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */ |
| 87852 | duk__bi_set_small(&nc_ctx->mp, 2); |
| 87853 | duk__bi_set_small(&nc_ctx->mm, 1); |
| 87854 | nc_ctx->unequal_gaps = 1; |
| 87855 | } else { |
| 87856 | /* r <- (* f 2) |
| 87857 | * s <- (* (expt b (- e)) 2) == b^(-e) * 2 [if b==2 -> b^(1-e)] |
| 87858 | * m+ <- 1 |
| 87859 | * m- <- 1 |
| 87860 | * k <- 0 |
| 87861 | * B <- B |
| 87862 | * low_ok <- round |
| 87863 | * high_ok <- round |
| 87864 | */ |
| 87865 | |
| 87866 | DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not " |
| 87867 | "lowest mantissa for this exponent -> " |
| 87868 | "equal gaps" )); |
| 87869 | |
| 87870 | duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2); /* r <- 2 * f */ |
| 87871 | 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 */ |
| 87872 | duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(-e) * 2 */ |
| 87873 | duk__bi_set_small(&nc_ctx->mp, 1); |
| 87874 | duk__bi_set_small(&nc_ctx->mm, 1); |
| 87875 | } |
| 87876 | } |
| 87877 | } |
| 87878 | |
| 87879 | DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) { |
| 87880 | duk_small_int_t k = 0; |
| 87881 | |
| 87882 | /* This is essentially the 'scale' algorithm, with recursion removed. |
| 87883 | * Note that 'k' is either correct immediately, or will move in one |
| 87884 | * direction in the loop. There's no need to do the low/high checks |
| 87885 | * on every round (like the Scheme algorithm does). |
| 87886 | * |
| 87887 | * The scheme algorithm finds 'k' and updates 's' simultaneously, |
| 87888 | * while the logical algorithm finds 'k' with 's' having its initial |
| 87889 | * value, after which 's' is updated separately (see the Burger-Dybvig |
| 87890 | * paper, Section 3.1, steps 2 and 3). |
| 87891 | * |
| 87892 | * The case where m+ == m- (almost always) is optimized for, because |
| 87893 | * it reduces the bigint operations considerably and almost always |
| 87894 | * applies. The scale loop only needs to work with m+, so this works. |
| 87895 | */ |
| 87896 | |
| 87897 | /* XXX: this algorithm could be optimized quite a lot by using e.g. |
| 87898 | * a logarithm based estimator for 'k' and performing B^n multiplication |
| 87899 | * using a lookup table or using some bit-representation based exp |
| 87900 | * algorithm. Currently we just loop, with significant performance |
| 87901 | * impact for very large and very small numbers. |
| 87902 | */ |
| 87903 | |
| 87904 | DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld" , |
| 87905 | (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok)); |
| 87906 | DUK__BI_PRINT("r(init)" , &nc_ctx->r); |
| 87907 | DUK__BI_PRINT("s(init)" , &nc_ctx->s); |
| 87908 | DUK__BI_PRINT("mp(init)" , &nc_ctx->mp); |
| 87909 | DUK__BI_PRINT("mm(init)" , &nc_ctx->mm); |
| 87910 | |
| 87911 | for (;;) { |
| 87912 | DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld" , (long) k)); |
| 87913 | DUK__BI_PRINT("r" , &nc_ctx->r); |
| 87914 | DUK__BI_PRINT("s" , &nc_ctx->s); |
| 87915 | DUK__BI_PRINT("m+" , &nc_ctx->mp); |
| 87916 | DUK__BI_PRINT("m-" , &nc_ctx->mm); |
| 87917 | |
| 87918 | duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */ |
| 87919 | if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) { |
| 87920 | DUK_DDD(DUK_DDDPRINT("k is too low" )); |
| 87921 | /* r <- r |
| 87922 | * s <- (* s B) |
| 87923 | * m+ <- m+ |
| 87924 | * m- <- m- |
| 87925 | * k <- (+ k 1) |
| 87926 | */ |
| 87927 | |
| 87928 | duk__bi_mul_small_copy(&nc_ctx->s, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); |
| 87929 | k++; |
| 87930 | } else { |
| 87931 | break; |
| 87932 | } |
| 87933 | } |
| 87934 | |
| 87935 | /* k > 0 -> k was too low, and cannot be too high */ |
| 87936 | if (k > 0) { |
| 87937 | goto skip_dec_k; |
| 87938 | } |
| 87939 | |
| 87940 | for (;;) { |
| 87941 | DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld" , (long) k)); |
| 87942 | DUK__BI_PRINT("r" , &nc_ctx->r); |
| 87943 | DUK__BI_PRINT("s" , &nc_ctx->s); |
| 87944 | DUK__BI_PRINT("m+" , &nc_ctx->mp); |
| 87945 | DUK__BI_PRINT("m-" , &nc_ctx->mm); |
| 87946 | |
| 87947 | duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */ |
| 87948 | duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, (duk_uint32_t) nc_ctx->B); /* t2 = (* (+ r m+) B) */ |
| 87949 | if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) { |
| 87950 | DUK_DDD(DUK_DDDPRINT("k is too high" )); |
| 87951 | /* r <- (* r B) |
| 87952 | * s <- s |
| 87953 | * m+ <- (* m+ B) |
| 87954 | * m- <- (* m- B) |
| 87955 | * k <- (- k 1) |
| 87956 | */ |
| 87957 | duk__bi_mul_small_copy(&nc_ctx->r, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); |
| 87958 | duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); |
| 87959 | if (nc_ctx->unequal_gaps) { |
| 87960 | DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too" )); |
| 87961 | duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1); |
| 87962 | } |
| 87963 | k--; |
| 87964 | } else { |
| 87965 | break; |
| 87966 | } |
| 87967 | } |
| 87968 | |
| 87969 | skip_dec_k: |
| 87970 | |
| 87971 | if (!nc_ctx->unequal_gaps) { |
| 87972 | DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+" )); |
| 87973 | duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp); /* mm <- mp */ |
| 87974 | } |
| 87975 | nc_ctx->k = k; |
| 87976 | |
| 87977 | DUK_DDD(DUK_DDDPRINT("final k: %ld" , (long) k)); |
| 87978 | DUK__BI_PRINT("r(final)" , &nc_ctx->r); |
| 87979 | DUK__BI_PRINT("s(final)" , &nc_ctx->s); |
| 87980 | DUK__BI_PRINT("mp(final)" , &nc_ctx->mp); |
| 87981 | DUK__BI_PRINT("mm(final)" , &nc_ctx->mm); |
| 87982 | } |
| 87983 | |
| 87984 | DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) { |
| 87985 | duk_small_int_t tc1, tc2; /* terminating conditions */ |
| 87986 | duk_small_int_t d; /* current digit */ |
| 87987 | duk_small_int_t count = 0; /* digit count */ |
| 87988 | |
| 87989 | /* |
| 87990 | * Digit generation loop. |
| 87991 | * |
| 87992 | * Different termination conditions: |
| 87993 | * |
| 87994 | * 1. Free format output. Terminate when shortest accurate |
| 87995 | * representation found. |
| 87996 | * |
| 87997 | * 2. Fixed format output, with specific number of digits. |
| 87998 | * Ignore termination conditions, terminate when digits |
| 87999 | * generated. Caller requests an extra digit and rounds. |
| 88000 | * |
| 88001 | * 3. Fixed format output, with a specific absolute cut-off |
| 88002 | * position (e.g. 10 digits after decimal point). Note |
| 88003 | * that we always generate at least one digit, even if |
| 88004 | * the digit is below the cut-off point already. |
| 88005 | */ |
| 88006 | |
| 88007 | for (;;) { |
| 88008 | DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld" , |
| 88009 | (long) count, (long) nc_ctx->k, (long) nc_ctx->B, |
| 88010 | (long) nc_ctx->low_ok, (long) nc_ctx->high_ok)); |
| 88011 | DUK__BI_PRINT("r" , &nc_ctx->r); |
| 88012 | DUK__BI_PRINT("s" , &nc_ctx->s); |
| 88013 | DUK__BI_PRINT("m+" , &nc_ctx->mp); |
| 88014 | DUK__BI_PRINT("m-" , &nc_ctx->mm); |
| 88015 | |
| 88016 | /* (quotient-remainder (* r B) s) using a dummy subtraction loop */ |
| 88017 | duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, (duk_uint32_t) nc_ctx->B); /* t1 <- (* r B) */ |
| 88018 | d = 0; |
| 88019 | for (;;) { |
| 88020 | if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { |
| 88021 | break; |
| 88022 | } |
| 88023 | duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2); /* t1 <- t1 - s */ |
| 88024 | d++; |
| 88025 | } |
| 88026 | duk__bi_copy(&nc_ctx->r, &nc_ctx->t1); /* r <- (remainder (* r B) s) */ |
| 88027 | /* d <- (quotient (* r B) s) (in range 0...B-1) */ |
| 88028 | DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld" , (long) d)); |
| 88029 | DUK__BI_PRINT("r(rem)" , &nc_ctx->r); |
| 88030 | |
| 88031 | duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */ |
| 88032 | duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */ |
| 88033 | DUK__BI_PRINT("mp(upd)" , &nc_ctx->mp); |
| 88034 | DUK__BI_PRINT("mm(upd)" , &nc_ctx->mm); |
| 88035 | |
| 88036 | /* Terminating conditions. For fixed width output, we just ignore the |
| 88037 | * terminating conditions (and pretend that tc1 == tc2 == false). The |
| 88038 | * the current shortcut for fixed-format output is to generate a few |
| 88039 | * extra digits and use rounding (with carry) to finish the output. |
| 88040 | */ |
| 88041 | |
| 88042 | if (nc_ctx->is_fixed == 0) { |
| 88043 | /* free-form */ |
| 88044 | tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1)); |
| 88045 | |
| 88046 | duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 <- (+ r m+) */ |
| 88047 | tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)); |
| 88048 | |
| 88049 | DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld" , (long) tc1, (long) tc2)); |
| 88050 | } else { |
| 88051 | /* fixed-format */ |
| 88052 | tc1 = 0; |
| 88053 | tc2 = 0; |
| 88054 | } |
| 88055 | |
| 88056 | /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call |
| 88057 | * on purpose, which is taken into account by the macro. |
| 88058 | */ |
| 88059 | count++; |
| 88060 | |
| 88061 | if (tc1) { |
| 88062 | if (tc2) { |
| 88063 | /* tc1 = true, tc2 = true */ |
| 88064 | duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2); |
| 88065 | if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { /* (< (* r 2) s) */ |
| 88066 | DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)" , |
| 88067 | (long) d, (long) nc_ctx->k)); |
| 88068 | DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d); |
| 88069 | } else { |
| 88070 | DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)" , |
| 88071 | (long) (d + 1), (long) nc_ctx->k)); |
| 88072 | DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1); |
| 88073 | } |
| 88074 | break; |
| 88075 | } else { |
| 88076 | /* tc1 = true, tc2 = false */ |
| 88077 | DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)" , |
| 88078 | (long) d, (long) nc_ctx->k)); |
| 88079 | DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d); |
| 88080 | break; |
| 88081 | } |
| 88082 | } else { |
| 88083 | if (tc2) { |
| 88084 | /* tc1 = false, tc2 = true */ |
| 88085 | DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)" , |
| 88086 | (long) (d + 1), (long) nc_ctx->k)); |
| 88087 | DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1); |
| 88088 | break; |
| 88089 | } else { |
| 88090 | /* tc1 = false, tc2 = false */ |
| 88091 | DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)" , |
| 88092 | (long) d, (long) nc_ctx->k)); |
| 88093 | DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d); |
| 88094 | |
| 88095 | /* r <- r (updated above: r <- (remainder (* r B) s) |
| 88096 | * s <- s |
| 88097 | * m+ <- m+ (updated above: m+ <- (* m+ B) |
| 88098 | * m- <- m- (updated above: m- <- (* m- B) |
| 88099 | * B, low_ok, high_ok are fixed |
| 88100 | */ |
| 88101 | |
| 88102 | /* fall through and continue for-loop */ |
| 88103 | } |
| 88104 | } |
| 88105 | |
| 88106 | /* fixed-format termination conditions */ |
| 88107 | if (nc_ctx->is_fixed) { |
| 88108 | if (nc_ctx->abs_pos) { |
| 88109 | int pos = nc_ctx->k - count + 1; /* count is already incremented, take into account */ |
| 88110 | DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld" , |
| 88111 | (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits)); |
| 88112 | if (pos <= nc_ctx->req_digits) { |
| 88113 | DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop" )); |
| 88114 | break; |
| 88115 | } |
| 88116 | } else { |
| 88117 | DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld" , |
| 88118 | (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits)); |
| 88119 | if (count >= nc_ctx->req_digits) { |
| 88120 | DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop" )); |
| 88121 | break; |
| 88122 | } |
| 88123 | } |
| 88124 | } |
| 88125 | } /* for */ |
| 88126 | |
| 88127 | nc_ctx->count = count; |
| 88128 | |
| 88129 | DUK_DDD(DUK_DDDPRINT("generate finished" )); |
| 88130 | |
| 88131 | #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2) |
| 88132 | { |
| 88133 | duk_uint8_t buf[2048]; |
| 88134 | duk_small_int_t i, t; |
| 88135 | duk_memzero(buf, sizeof(buf)); |
| 88136 | for (i = 0; i < nc_ctx->count; i++) { |
| 88137 | t = nc_ctx->digits[i]; |
| 88138 | if (t < 0 || t > 36) { |
| 88139 | buf[i] = (duk_uint8_t) '?'; |
| 88140 | } else { |
| 88141 | buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t); |
| 88142 | } |
| 88143 | } |
| 88144 | DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'" , |
| 88145 | (long) nc_ctx->k, (const char *) buf)); |
| 88146 | } |
| 88147 | #endif |
| 88148 | } |
| 88149 | |
| 88150 | /* Round up digits to a given position. If position is out-of-bounds, |
| 88151 | * does nothing. If carry propagates over the first digit, a '1' is |
| 88152 | * prepended to digits and 'k' will be updated. Return value indicates |
| 88153 | * whether carry propagated over the first digit. |
| 88154 | * |
| 88155 | * Note that nc_ctx->count is NOT updated based on the rounding position |
| 88156 | * (it is updated only if carry overflows over the first digit and an |
| 88157 | * extra digit is prepended). |
| 88158 | */ |
| 88159 | DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) { |
| 88160 | duk_small_int_t t; |
| 88161 | duk_uint8_t *p; |
| 88162 | duk_uint8_t roundup_limit; |
| 88163 | duk_small_int_t ret = 0; |
| 88164 | |
| 88165 | /* |
| 88166 | * round_idx points to the digit which is considered for rounding; the |
| 88167 | * digit to its left is the final digit of the rounded value. If round_idx |
| 88168 | * is zero, rounding will be performed; the result will either be an empty |
| 88169 | * rounded value or if carry happens a '1' digit is generated. |
| 88170 | */ |
| 88171 | |
| 88172 | if (round_idx >= nc_ctx->count) { |
| 88173 | DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding" , |
| 88174 | (long) round_idx, (long) nc_ctx->count)); |
| 88175 | return 0; |
| 88176 | } else if (round_idx < 0) { |
| 88177 | DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding" , |
| 88178 | (long) round_idx)); |
| 88179 | return 0; |
| 88180 | } |
| 88181 | |
| 88182 | /* |
| 88183 | * Round-up limit. |
| 88184 | * |
| 88185 | * For even values, divides evenly, e.g. 10 -> roundup_limit=5. |
| 88186 | * |
| 88187 | * For odd values, rounds up, e.g. 3 -> roundup_limit=2. |
| 88188 | * If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up. |
| 88189 | */ |
| 88190 | roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2); |
| 88191 | |
| 88192 | p = &nc_ctx->digits[round_idx]; |
| 88193 | if (*p >= roundup_limit) { |
| 88194 | DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required" )); |
| 88195 | /* carry */ |
| 88196 | for (;;) { |
| 88197 | *p = 0; |
| 88198 | if (p == &nc_ctx->digits[0]) { |
| 88199 | DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling" )); |
| 88200 | duk_memmove((void *) (&nc_ctx->digits[1]), |
| 88201 | (const void *) (&nc_ctx->digits[0]), |
| 88202 | (size_t) (sizeof(char) * (size_t) nc_ctx->count)); |
| 88203 | nc_ctx->digits[0] = 1; /* don't increase 'count' */ |
| 88204 | nc_ctx->k++; /* position of highest digit changed */ |
| 88205 | nc_ctx->count++; /* number of digits changed */ |
| 88206 | ret = 1; |
| 88207 | break; |
| 88208 | } |
| 88209 | |
| 88210 | DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p" , |
| 88211 | (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits)); |
| 88212 | p--; |
| 88213 | t = *p; |
| 88214 | DUK_DDD(DUK_DDDPRINT("digit before carry: %ld" , (long) t)); |
| 88215 | if (++t < nc_ctx->B) { |
| 88216 | DUK_DDD(DUK_DDDPRINT("rounding carry terminated" )); |
| 88217 | *p = (duk_uint8_t) t; |
| 88218 | break; |
| 88219 | } |
| 88220 | |
| 88221 | DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit" )); |
| 88222 | } |
| 88223 | } |
| 88224 | |
| 88225 | return ret; |
| 88226 | } |
| 88227 | |
| 88228 | #define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */ |
| 88229 | |
| 88230 | DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx, |
| 88231 | duk_hthread *thr, |
| 88232 | duk_small_int_t radix, |
| 88233 | duk_small_int_t digits, |
| 88234 | duk_small_uint_t flags, |
| 88235 | duk_small_int_t neg) { |
| 88236 | duk_small_int_t k; |
| 88237 | duk_small_int_t pos, pos_end; |
| 88238 | duk_small_int_t expt; |
| 88239 | duk_small_int_t dig; |
| 88240 | duk_uint8_t *q; |
| 88241 | duk_uint8_t *buf; |
| 88242 | |
| 88243 | /* |
| 88244 | * The string conversion here incorporates all the necessary ECMAScript |
| 88245 | * semantics without attempting to be generic. nc_ctx->digits contains |
| 88246 | * nc_ctx->count digits (>= 1), with the topmost digit's 'position' |
| 88247 | * indicated by nc_ctx->k as follows: |
| 88248 | * |
| 88249 | * digits="123" count=3 k=0 --> 0.123 |
| 88250 | * digits="123" count=3 k=1 --> 1.23 |
| 88251 | * digits="123" count=3 k=5 --> 12300 |
| 88252 | * digits="123" count=3 k=-1 --> 0.0123 |
| 88253 | * |
| 88254 | * Note that the identifier names used for format selection are different |
| 88255 | * in Burger-Dybvig paper and ECMAScript specification (quite confusingly |
| 88256 | * so, because e.g. 'k' has a totally different meaning in each). See |
| 88257 | * documentation for discussion. |
| 88258 | * |
| 88259 | * ECMAScript doesn't specify any specific behavior for format selection |
| 88260 | * (e.g. when to use exponent notation) for non-base-10 numbers. |
| 88261 | * |
| 88262 | * The bigint space in the context is reused for string output, as there |
| 88263 | * is more than enough space for that (>1kB at the moment), and we avoid |
| 88264 | * allocating even more stack. |
| 88265 | */ |
| 88266 | |
| 88267 | DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH); |
| 88268 | DUK_ASSERT(nc_ctx->count >= 1); |
| 88269 | |
| 88270 | k = nc_ctx->k; |
| 88271 | buf = (duk_uint8_t *) &nc_ctx->f; /* XXX: union would be more correct */ |
| 88272 | q = buf; |
| 88273 | |
| 88274 | /* Exponent handling: if exponent format is used, record exponent value and |
| 88275 | * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23"). |
| 88276 | * |
| 88277 | * toFixed() prevents exponent use; otherwise apply a set of criteria to |
| 88278 | * match the other API calls (toString(), toPrecision, etc). |
| 88279 | */ |
| 88280 | |
| 88281 | expt = DUK__NO_EXP; |
| 88282 | if (!nc_ctx->abs_pos /* toFixed() */) { |
| 88283 | if ((flags & DUK_N2S_FLAG_FORCE_EXP) || /* exponential notation forced */ |
| 88284 | ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) && /* fixed precision and zero padding would be required */ |
| 88285 | (k - digits >= 1)) || /* (e.g. k=3, digits=2 -> "12X") */ |
| 88286 | ((k > 21 || k <= -6) && (radix == 10))) { /* toString() conditions */ |
| 88287 | DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld" , |
| 88288 | (long) k, (long) (k - 1))); |
| 88289 | expt = k - 1; /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */ |
| 88290 | k = 1; /* generate mantissa with a single leading whole number digit */ |
| 88291 | } |
| 88292 | } |
| 88293 | |
| 88294 | if (neg) { |
| 88295 | *q++ = '-'; |
| 88296 | } |
| 88297 | |
| 88298 | /* Start position (inclusive) and end position (exclusive) */ |
| 88299 | pos = (k >= 1 ? k : 1); |
| 88300 | if (nc_ctx->is_fixed) { |
| 88301 | if (nc_ctx->abs_pos) { |
| 88302 | /* toFixed() */ |
| 88303 | pos_end = -digits; |
| 88304 | } else { |
| 88305 | pos_end = k - digits; |
| 88306 | } |
| 88307 | } else { |
| 88308 | pos_end = k - nc_ctx->count; |
| 88309 | } |
| 88310 | if (pos_end > 0) { |
| 88311 | pos_end = 0; |
| 88312 | } |
| 88313 | |
| 88314 | DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, " |
| 88315 | "digits=%ld, abs_pos=%ld" , |
| 88316 | (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end, |
| 88317 | (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos)); |
| 88318 | |
| 88319 | /* Digit generation */ |
| 88320 | while (pos > pos_end) { |
| 88321 | DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld" , |
| 88322 | (long) pos, (long) pos_end)); |
| 88323 | if (pos == 0) { |
| 88324 | *q++ = (duk_uint8_t) '.'; |
| 88325 | } |
| 88326 | if (pos > k) { |
| 88327 | *q++ = (duk_uint8_t) '0'; |
| 88328 | } else if (pos <= k - nc_ctx->count) { |
| 88329 | *q++ = (duk_uint8_t) '0'; |
| 88330 | } else { |
| 88331 | dig = nc_ctx->digits[k - pos]; |
| 88332 | DUK_ASSERT(dig >= 0 && dig < nc_ctx->B); |
| 88333 | *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig); |
| 88334 | } |
| 88335 | |
| 88336 | pos--; |
| 88337 | } |
| 88338 | DUK_ASSERT(pos <= 1); |
| 88339 | |
| 88340 | /* Exponent */ |
| 88341 | if (expt != DUK__NO_EXP) { |
| 88342 | /* |
| 88343 | * Exponent notation for non-base-10 numbers isn't specified in ECMAScript |
| 88344 | * specification, as it never explicitly turns up: non-decimal numbers can |
| 88345 | * only be formatted with Number.prototype.toString([radix]) and for that, |
| 88346 | * behavior is not explicitly specified. |
| 88347 | * |
| 88348 | * Logical choices include formatting the exponent as decimal (e.g. binary |
| 88349 | * 100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101). |
| 88350 | * The Dragon4 algorithm (in the original paper) prints the exponent value |
| 88351 | * in the target radix B. However, for radix values 15 and above, the |
| 88352 | * exponent separator 'e' is no longer easily parseable. Consider, for |
| 88353 | * instance, the number "1.faecee+1c". |
| 88354 | */ |
| 88355 | |
| 88356 | duk_size_t len; |
| 88357 | char expt_sign; |
| 88358 | |
| 88359 | *q++ = 'e'; |
| 88360 | if (expt >= 0) { |
| 88361 | expt_sign = '+'; |
| 88362 | } else { |
| 88363 | expt_sign = '-'; |
| 88364 | expt = -expt; |
| 88365 | } |
| 88366 | *q++ = (duk_uint8_t) expt_sign; |
| 88367 | len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix); |
| 88368 | q += len; |
| 88369 | } |
| 88370 | |
| 88371 | duk_push_lstring(thr, (const char *) buf, (size_t) (q - buf)); |
| 88372 | } |
| 88373 | |
| 88374 | /* |
| 88375 | * Conversion helpers |
| 88376 | */ |
| 88377 | |
| 88378 | DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) { |
| 88379 | duk_double_union u; |
| 88380 | duk_uint32_t tmp; |
| 88381 | duk_small_int_t expt; |
| 88382 | |
| 88383 | /* |
| 88384 | * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff |
| 88385 | * A B C D E F G H |
| 88386 | * |
| 88387 | * s sign bit |
| 88388 | * eee... exponent field |
| 88389 | * fff... fraction |
| 88390 | * |
| 88391 | * ieee value = 1.ffff... * 2^(e - 1023) (normal) |
| 88392 | * = 0.ffff... * 2^(-1022) (denormal) |
| 88393 | * |
| 88394 | * algorithm v = f * b^e |
| 88395 | */ |
| 88396 | |
| 88397 | DUK_DBLUNION_SET_DOUBLE(&u, x); |
| 88398 | |
| 88399 | nc_ctx->f.n = 2; |
| 88400 | |
| 88401 | tmp = DUK_DBLUNION_GET_LOW32(&u); |
| 88402 | nc_ctx->f.v[0] = tmp; |
| 88403 | tmp = DUK_DBLUNION_GET_HIGH32(&u); |
| 88404 | nc_ctx->f.v[1] = tmp & 0x000fffffUL; |
| 88405 | expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL); |
| 88406 | |
| 88407 | if (expt == 0) { |
| 88408 | /* denormal */ |
| 88409 | expt = DUK__IEEE_DOUBLE_EXP_MIN - 52; |
| 88410 | duk__bi_normalize(&nc_ctx->f); |
| 88411 | } else { |
| 88412 | /* normal: implicit leading 1-bit */ |
| 88413 | nc_ctx->f.v[1] |= 0x00100000UL; |
| 88414 | expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52; |
| 88415 | DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); /* true, because v[1] has at least one bit set */ |
| 88416 | } |
| 88417 | |
| 88418 | DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); |
| 88419 | |
| 88420 | nc_ctx->e = expt; |
| 88421 | } |
| 88422 | |
| 88423 | DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) { |
| 88424 | duk_double_union u; |
| 88425 | duk_small_int_t expt; |
| 88426 | duk_small_int_t i; |
| 88427 | duk_small_int_t bitstart; |
| 88428 | duk_small_int_t bitround; |
| 88429 | duk_small_int_t bitidx; |
| 88430 | duk_small_int_t skip_round; |
| 88431 | duk_uint32_t t, v; |
| 88432 | |
| 88433 | DUK_ASSERT(nc_ctx->count == 53 + 1); |
| 88434 | |
| 88435 | /* Sometimes this assert is not true right now; it will be true after |
| 88436 | * rounding. See: test-bug-numconv-mantissa-assert.js. |
| 88437 | */ |
| 88438 | DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1); /* zero handled by caller */ |
| 88439 | |
| 88440 | /* Should not be required because the code below always sets both high |
| 88441 | * and low parts, but at least gcc-4.4.5 fails to deduce this correctly |
| 88442 | * (perhaps because the low part is set (seemingly) conditionally in a |
| 88443 | * loop), so this is here to avoid the bogus warning. |
| 88444 | */ |
| 88445 | duk_memzero((void *) &u, sizeof(u)); |
| 88446 | |
| 88447 | /* |
| 88448 | * Figure out how generated digits match up with the mantissa, |
| 88449 | * and then perform rounding. If mantissa overflows, need to |
| 88450 | * recompute the exponent (it is bumped and may overflow to |
| 88451 | * infinity). |
| 88452 | * |
| 88453 | * For normal numbers the leading '1' is hidden and ignored, |
| 88454 | * and the last bit is used for rounding: |
| 88455 | * |
| 88456 | * rounding pt |
| 88457 | * <--------52------->| |
| 88458 | * 1 x x x x ... x x x x|y ==> x x x x ... x x x x |
| 88459 | * |
| 88460 | * For denormals, the leading '1' is included in the number, |
| 88461 | * and the rounding point is different: |
| 88462 | * |
| 88463 | * rounding pt |
| 88464 | * <--52 or less--->| |
| 88465 | * 1 x x x x ... x x|x x y ==> 0 0 ... 1 x x ... x x |
| 88466 | * |
| 88467 | * The largest denormals will have a mantissa beginning with |
| 88468 | * a '1' (the explicit leading bit); smaller denormals will |
| 88469 | * have leading zero bits. |
| 88470 | * |
| 88471 | * If the exponent would become too high, the result becomes |
| 88472 | * Infinity. If the exponent is so small that the entire |
| 88473 | * mantissa becomes zero, the result becomes zero. |
| 88474 | * |
| 88475 | * Note: the Dragon4 'k' is off-by-one with respect to the IEEE |
| 88476 | * exponent. For instance, k==0 indicates that the leading '1' |
| 88477 | * digit is at the first binary fraction position (0.1xxx...); |
| 88478 | * the corresponding IEEE exponent would be -1. |
| 88479 | */ |
| 88480 | |
| 88481 | skip_round = 0; |
| 88482 | |
| 88483 | recheck_exp: |
| 88484 | |
| 88485 | expt = nc_ctx->k - 1; /* IEEE exp without bias */ |
| 88486 | if (expt > 1023) { |
| 88487 | /* Infinity */ |
| 88488 | bitstart = -255; /* needed for inf: causes mantissa to become zero, |
| 88489 | * and rounding to be skipped. |
| 88490 | */ |
| 88491 | expt = 2047; |
| 88492 | } else if (expt >= -1022) { |
| 88493 | /* normal */ |
| 88494 | bitstart = 1; /* skip leading digit */ |
| 88495 | expt += DUK__IEEE_DOUBLE_EXP_BIAS; |
| 88496 | DUK_ASSERT(expt >= 1 && expt <= 2046); |
| 88497 | } else { |
| 88498 | /* denormal or zero */ |
| 88499 | bitstart = 1023 + expt; /* expt==-1023 -> bitstart=0 (leading 1); |
| 88500 | * expt==-1024 -> bitstart=-1 (one left of leading 1), etc |
| 88501 | */ |
| 88502 | expt = 0; |
| 88503 | } |
| 88504 | bitround = bitstart + 52; |
| 88505 | |
| 88506 | DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld" , |
| 88507 | (long) expt, (long) bitstart, (long) bitround)); |
| 88508 | |
| 88509 | if (!skip_round) { |
| 88510 | if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) { |
| 88511 | /* Corner case: see test-numconv-parse-mant-carry.js. We could |
| 88512 | * just bump the exponent and update bitstart, but it's more robust |
| 88513 | * to recompute (but avoid rounding twice). |
| 88514 | */ |
| 88515 | DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent" )); |
| 88516 | skip_round = 1; |
| 88517 | goto recheck_exp; |
| 88518 | } |
| 88519 | } |
| 88520 | |
| 88521 | /* |
| 88522 | * Create mantissa |
| 88523 | */ |
| 88524 | |
| 88525 | t = 0; |
| 88526 | for (i = 0; i < 52; i++) { |
| 88527 | bitidx = bitstart + 52 - 1 - i; |
| 88528 | if (bitidx >= nc_ctx->count) { |
| 88529 | v = 0; |
| 88530 | } else if (bitidx < 0) { |
| 88531 | v = 0; |
| 88532 | } else { |
| 88533 | v = nc_ctx->digits[bitidx]; |
| 88534 | } |
| 88535 | DUK_ASSERT(v == 0 || v == 1); |
| 88536 | t += v << (i % 32); |
| 88537 | if (i == 31) { |
| 88538 | /* low 32 bits is complete */ |
| 88539 | DUK_DBLUNION_SET_LOW32(&u, t); |
| 88540 | t = 0; |
| 88541 | } |
| 88542 | } |
| 88543 | /* t has high mantissa */ |
| 88544 | |
| 88545 | DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx" , |
| 88546 | (unsigned long) t, |
| 88547 | (unsigned long) DUK_DBLUNION_GET_LOW32(&u))); |
| 88548 | |
| 88549 | DUK_ASSERT(expt >= 0 && expt <= 0x7ffL); |
| 88550 | t += ((duk_uint32_t) expt) << 20; |
| 88551 | #if 0 /* caller handles sign change */ |
| 88552 | if (negative) { |
| 88553 | t |= 0x80000000U; |
| 88554 | } |
| 88555 | #endif |
| 88556 | DUK_DBLUNION_SET_HIGH32(&u, t); |
| 88557 | |
| 88558 | DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx" , |
| 88559 | (unsigned long) DUK_DBLUNION_GET_HIGH32(&u), |
| 88560 | (unsigned long) DUK_DBLUNION_GET_LOW32(&u))); |
| 88561 | |
| 88562 | *x = DUK_DBLUNION_GET_DOUBLE(&u); |
| 88563 | } |
| 88564 | |
| 88565 | /* |
| 88566 | * Exposed number-to-string API |
| 88567 | * |
| 88568 | * Input: [ number ] |
| 88569 | * Output: [ string ] |
| 88570 | */ |
| 88571 | |
| 88572 | DUK_LOCAL DUK_NOINLINE void duk__numconv_stringify_raw(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) { |
| 88573 | duk_double_t x; |
| 88574 | duk_small_int_t c; |
| 88575 | duk_small_int_t neg; |
| 88576 | duk_uint32_t uval; |
| 88577 | duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */ |
| 88578 | duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc; |
| 88579 | |
| 88580 | x = (duk_double_t) duk_require_number(thr, -1); |
| 88581 | duk_pop(thr); |
| 88582 | |
| 88583 | /* |
| 88584 | * Handle special cases (NaN, infinity, zero). |
| 88585 | */ |
| 88586 | |
| 88587 | c = (duk_small_int_t) DUK_FPCLASSIFY(x); |
| 88588 | if (DUK_SIGNBIT((double) x)) { |
| 88589 | x = -x; |
| 88590 | neg = 1; |
| 88591 | } else { |
| 88592 | neg = 0; |
| 88593 | } |
| 88594 | |
| 88595 | /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */ |
| 88596 | DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0); |
| 88597 | |
| 88598 | if (c == DUK_FP_NAN) { |
| 88599 | duk_push_hstring_stridx(thr, DUK_STRIDX_NAN); |
| 88600 | return; |
| 88601 | } else if (c == DUK_FP_INFINITE) { |
| 88602 | if (neg) { |
| 88603 | /* -Infinity */ |
| 88604 | duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_INFINITY); |
| 88605 | } else { |
| 88606 | /* Infinity */ |
| 88607 | duk_push_hstring_stridx(thr, DUK_STRIDX_INFINITY); |
| 88608 | } |
| 88609 | return; |
| 88610 | } else if (c == DUK_FP_ZERO) { |
| 88611 | /* We can't shortcut zero here if it goes through special formatting |
| 88612 | * (such as forced exponential notation). |
| 88613 | */ |
| 88614 | ; |
| 88615 | } |
| 88616 | |
| 88617 | /* |
| 88618 | * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1]) |
| 88619 | * specially, as they're very likely for embedded programs. This |
| 88620 | * is now done for all radix values. We must be careful not to use |
| 88621 | * the fast path when special formatting (e.g. forced exponential) |
| 88622 | * is in force. |
| 88623 | * |
| 88624 | * XXX: could save space by supporting radix 10 only and using |
| 88625 | * sprintf "%lu" for the fast path and for exponent formatting. |
| 88626 | */ |
| 88627 | |
| 88628 | uval = duk_double_to_uint32_t(x); |
| 88629 | if (duk_double_equals((double) uval, x) && /* integer number in range */ |
| 88630 | flags == 0) { /* no special formatting */ |
| 88631 | /* use bigint area as a temp */ |
| 88632 | duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f); |
| 88633 | duk_uint8_t *p = buf; |
| 88634 | |
| 88635 | DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */ |
| 88636 | if (neg && uval != 0) { |
| 88637 | /* no negative sign for zero */ |
| 88638 | *p++ = (duk_uint8_t) '-'; |
| 88639 | } |
| 88640 | p += duk__dragon4_format_uint32(p, uval, radix); |
| 88641 | duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf)); |
| 88642 | return; |
| 88643 | } |
| 88644 | |
| 88645 | /* |
| 88646 | * Dragon4 setup. |
| 88647 | * |
| 88648 | * Convert double from IEEE representation for conversion; |
| 88649 | * normal finite values have an implicit leading 1-bit. The |
| 88650 | * slow path algorithm doesn't handle zero, so zero is special |
| 88651 | * cased here but still creates a valid nc_ctx, and goes |
| 88652 | * through normal formatting in case special formatting has |
| 88653 | * been requested (e.g. forced exponential format: 0 -> "0e+0"). |
| 88654 | */ |
| 88655 | |
| 88656 | /* Would be nice to bulk clear the allocation, but the context |
| 88657 | * is 1-2 kilobytes and nothing should rely on it being zeroed. |
| 88658 | */ |
| 88659 | #if 0 |
| 88660 | duk_memzero((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */ |
| 88661 | #endif |
| 88662 | |
| 88663 | nc_ctx->is_s2n = 0; |
| 88664 | nc_ctx->b = 2; |
| 88665 | nc_ctx->B = radix; |
| 88666 | nc_ctx->abs_pos = 0; |
| 88667 | if (flags & DUK_N2S_FLAG_FIXED_FORMAT) { |
| 88668 | nc_ctx->is_fixed = 1; |
| 88669 | if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) { |
| 88670 | /* absolute req_digits; e.g. digits = 1 -> last digit is 0, |
| 88671 | * but add an extra digit for rounding. |
| 88672 | */ |
| 88673 | nc_ctx->abs_pos = 1; |
| 88674 | nc_ctx->req_digits = (-digits + 1) - 1; |
| 88675 | } else { |
| 88676 | nc_ctx->req_digits = digits + 1; |
| 88677 | } |
| 88678 | } else { |
| 88679 | nc_ctx->is_fixed = 0; |
| 88680 | nc_ctx->req_digits = 0; |
| 88681 | } |
| 88682 | |
| 88683 | if (c == DUK_FP_ZERO) { |
| 88684 | /* Zero special case: fake requested number of zero digits; ensure |
| 88685 | * no sign bit is printed. Relative and absolute fixed format |
| 88686 | * require separate handling. |
| 88687 | */ |
| 88688 | duk_small_int_t count; |
| 88689 | if (nc_ctx->is_fixed) { |
| 88690 | if (nc_ctx->abs_pos) { |
| 88691 | count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */ |
| 88692 | } else { |
| 88693 | count = digits + 1; /* + 1 for rounding */ |
| 88694 | } |
| 88695 | } else { |
| 88696 | count = 1; |
| 88697 | } |
| 88698 | DUK_DDD(DUK_DDDPRINT("count=%ld" , (long) count)); |
| 88699 | DUK_ASSERT(count >= 1); |
| 88700 | duk_memzero((void *) nc_ctx->digits, (size_t) count); |
| 88701 | nc_ctx->count = count; |
| 88702 | nc_ctx->k = 1; /* 0.000... */ |
| 88703 | neg = 0; |
| 88704 | goto zero_skip; |
| 88705 | } |
| 88706 | |
| 88707 | duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */ |
| 88708 | DUK__BI_PRINT("f" , &nc_ctx->f); |
| 88709 | DUK_DDD(DUK_DDDPRINT("e=%ld" , (long) nc_ctx->e)); |
| 88710 | |
| 88711 | /* |
| 88712 | * Dragon4 slow path digit generation. |
| 88713 | */ |
| 88714 | |
| 88715 | duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */ |
| 88716 | |
| 88717 | DUK_DDD(DUK_DDDPRINT("after prepare:" )); |
| 88718 | DUK__BI_PRINT("r" , &nc_ctx->r); |
| 88719 | DUK__BI_PRINT("s" , &nc_ctx->s); |
| 88720 | DUK__BI_PRINT("mp" , &nc_ctx->mp); |
| 88721 | DUK__BI_PRINT("mm" , &nc_ctx->mm); |
| 88722 | |
| 88723 | duk__dragon4_scale(nc_ctx); |
| 88724 | |
| 88725 | DUK_DDD(DUK_DDDPRINT("after scale; k=%ld" , (long) nc_ctx->k)); |
| 88726 | DUK__BI_PRINT("r" , &nc_ctx->r); |
| 88727 | DUK__BI_PRINT("s" , &nc_ctx->s); |
| 88728 | DUK__BI_PRINT("mp" , &nc_ctx->mp); |
| 88729 | DUK__BI_PRINT("mm" , &nc_ctx->mm); |
| 88730 | |
| 88731 | duk__dragon4_generate(nc_ctx); |
| 88732 | |
| 88733 | /* |
| 88734 | * Convert and push final string. |
| 88735 | */ |
| 88736 | |
| 88737 | zero_skip: |
| 88738 | |
| 88739 | if (flags & DUK_N2S_FLAG_FIXED_FORMAT) { |
| 88740 | /* Perform fixed-format rounding. */ |
| 88741 | duk_small_int_t roundpos; |
| 88742 | if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) { |
| 88743 | /* 'roundpos' is relative to nc_ctx->k and increases to the right |
| 88744 | * (opposite of how 'k' changes). |
| 88745 | */ |
| 88746 | roundpos = -digits; /* absolute position for digit considered for rounding */ |
| 88747 | roundpos = nc_ctx->k - roundpos; |
| 88748 | } else { |
| 88749 | roundpos = digits; |
| 88750 | } |
| 88751 | DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld" , |
| 88752 | (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos)); |
| 88753 | (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos); |
| 88754 | |
| 88755 | /* Note: 'count' is currently not adjusted by rounding (i.e. the |
| 88756 | * digits are not "chopped off". That shouldn't matter because |
| 88757 | * the digit position (absolute or relative) is passed on to the |
| 88758 | * convert-and-push function. |
| 88759 | */ |
| 88760 | } |
| 88761 | |
| 88762 | duk__dragon4_convert_and_push(nc_ctx, thr, radix, digits, flags, neg); |
| 88763 | } |
| 88764 | |
| 88765 | DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) { |
| 88766 | duk_native_stack_check(thr); |
| 88767 | duk__numconv_stringify_raw(thr, radix, digits, flags); |
| 88768 | } |
| 88769 | |
| 88770 | /* |
| 88771 | * Exposed string-to-number API |
| 88772 | * |
| 88773 | * Input: [ string ] |
| 88774 | * Output: [ number ] |
| 88775 | * |
| 88776 | * If number parsing fails, a NaN is pushed as the result. If number parsing |
| 88777 | * fails due to an internal error, an InternalError is thrown. |
| 88778 | */ |
| 88779 | |
| 88780 | DUK_LOCAL DUK_NOINLINE void duk__numconv_parse_raw(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) { |
| 88781 | duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */ |
| 88782 | duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc; |
| 88783 | duk_double_t res; |
| 88784 | duk_hstring *h_str; |
| 88785 | duk_int_t expt; |
| 88786 | duk_bool_t expt_neg; |
| 88787 | duk_small_int_t expt_adj; |
| 88788 | duk_small_int_t neg; |
| 88789 | duk_small_int_t dig; |
| 88790 | duk_small_int_t dig_whole; |
| 88791 | duk_small_int_t dig_lzero; |
| 88792 | duk_small_int_t dig_frac; |
| 88793 | duk_small_int_t dig_expt; |
| 88794 | duk_small_int_t dig_prec; |
| 88795 | const duk__exp_limits *explim; |
| 88796 | const duk_uint8_t *p; |
| 88797 | duk_small_int_t ch; |
| 88798 | |
| 88799 | DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx" , |
| 88800 | (duk_tval *) duk_get_tval(thr, -1), |
| 88801 | (long) radix, (unsigned long) flags)); |
| 88802 | |
| 88803 | DUK_ASSERT(radix >= 2 && radix <= 36); |
| 88804 | DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix)); |
| 88805 | |
| 88806 | /* |
| 88807 | * Preliminaries: trim, sign, Infinity check |
| 88808 | * |
| 88809 | * We rely on the interned string having a NUL terminator, which will |
| 88810 | * cause a parse failure wherever it is encountered. As a result, we |
| 88811 | * don't need separate pointer checks. |
| 88812 | * |
| 88813 | * There is no special parsing for 'NaN' in the specification although |
| 88814 | * 'Infinity' (with an optional sign) is allowed in some contexts. |
| 88815 | * Some contexts allow plus/minus sign, while others only allow the |
| 88816 | * minus sign (like JSON.parse()). |
| 88817 | * |
| 88818 | * Automatic hex number detection (leading '0x' or '0X') and octal |
| 88819 | * number detection (leading '0' followed by at least one octal digit) |
| 88820 | * is done here too. |
| 88821 | * |
| 88822 | * Symbols are not explicitly rejected here (that's up to the caller). |
| 88823 | * If a symbol were passed here, it should ultimately safely fail |
| 88824 | * parsing due to a syntax error. |
| 88825 | */ |
| 88826 | |
| 88827 | if (flags & DUK_S2N_FLAG_TRIM_WHITE) { |
| 88828 | /* Leading / trailing whitespace is sometimes accepted and |
| 88829 | * sometimes not. After white space trimming, all valid input |
| 88830 | * characters are pure ASCII. |
| 88831 | */ |
| 88832 | duk_trim(thr, -1); |
| 88833 | } |
| 88834 | h_str = duk_require_hstring(thr, -1); |
| 88835 | DUK_ASSERT(h_str != NULL); |
| 88836 | p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str); |
| 88837 | |
| 88838 | neg = 0; |
| 88839 | ch = *p; |
| 88840 | if (ch == (duk_small_int_t) '+') { |
| 88841 | if ((flags & DUK_S2N_FLAG_ALLOW_PLUS) == 0) { |
| 88842 | DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed" )); |
| 88843 | goto parse_fail; |
| 88844 | } |
| 88845 | p++; |
| 88846 | } else if (ch == (duk_small_int_t) '-') { |
| 88847 | if ((flags & DUK_S2N_FLAG_ALLOW_MINUS) == 0) { |
| 88848 | DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed" )); |
| 88849 | goto parse_fail; |
| 88850 | } |
| 88851 | p++; |
| 88852 | neg = 1; |
| 88853 | } |
| 88854 | |
| 88855 | if ((flags & DUK_S2N_FLAG_ALLOW_INF) && DUK_STRNCMP((const char *) p, "Infinity" , 8) == 0) { |
| 88856 | /* Don't check for Infinity unless the context allows it. |
| 88857 | * 'Infinity' is a valid integer literal in e.g. base-36: |
| 88858 | * |
| 88859 | * parseInt('Infinity', 36) |
| 88860 | * 1461559270678 |
| 88861 | */ |
| 88862 | |
| 88863 | if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0 && p[8] != DUK_ASC_NUL) { |
| 88864 | DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed" )); |
| 88865 | goto parse_fail; |
| 88866 | } else { |
| 88867 | res = DUK_DOUBLE_INFINITY; |
| 88868 | goto negcheck_and_ret; |
| 88869 | } |
| 88870 | } |
| 88871 | ch = *p; |
| 88872 | if (ch == (duk_small_int_t) '0') { |
| 88873 | duk_small_int_t detect_radix = 0; |
| 88874 | ch = DUK_LOWERCASE_CHAR_ASCII(p[1]); /* 'x' or 'X' -> 'x' */ |
| 88875 | if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT) && ch == DUK_ASC_LC_X) { |
| 88876 | DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent" )); |
| 88877 | detect_radix = 16; |
| 88878 | #if 0 |
| 88879 | } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT) && |
| 88880 | (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) { |
| 88881 | DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent" )); |
| 88882 | detect_radix = 8; |
| 88883 | |
| 88884 | /* NOTE: if this legacy octal case is added back, it has |
| 88885 | * different flags and 'p' advance so this needs to be |
| 88886 | * reworked. |
| 88887 | */ |
| 88888 | flags |= DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO; /* interpret e.g. '09' as '0', not NaN */ |
| 88889 | p += 1; |
| 88890 | #endif |
| 88891 | } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) && ch == DUK_ASC_LC_O) { |
| 88892 | DUK_DDD(DUK_DDDPRINT("detected 0o oct prefix, changing radix and preventing fractions and exponent" )); |
| 88893 | detect_radix = 8; |
| 88894 | } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT) && ch == DUK_ASC_LC_B) { |
| 88895 | DUK_DDD(DUK_DDDPRINT("detected 0b bin prefix, changing radix and preventing fractions and exponent" )); |
| 88896 | detect_radix = 2; |
| 88897 | } |
| 88898 | if (detect_radix > 0) { |
| 88899 | radix = detect_radix; |
| 88900 | /* Clear empty as zero flag: interpret e.g. '0x' and '0xg' as a NaN (= parse error) */ |
| 88901 | flags &= ~(DUK_S2N_FLAG_ALLOW_EXP | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | |
| 88902 | DUK_S2N_FLAG_ALLOW_FRAC | DUK_S2N_FLAG_ALLOW_NAKED_FRAC | |
| 88903 | DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO); |
| 88904 | flags |= DUK_S2N_FLAG_ALLOW_LEADING_ZERO; /* allow e.g. '0x0009' and '0b00010001' */ |
| 88905 | p += 2; |
| 88906 | } |
| 88907 | } |
| 88908 | |
| 88909 | /* |
| 88910 | * Scan number and setup for Dragon4. |
| 88911 | * |
| 88912 | * The fast path case is detected during setup: an integer which |
| 88913 | * can be converted without rounding, no net exponent. The fast |
| 88914 | * path could be implemented as a separate scan, but may not really |
| 88915 | * be worth it: the multiplications for building 'f' are not |
| 88916 | * expensive when 'f' is small. |
| 88917 | * |
| 88918 | * The significand ('f') must contain enough bits of (apparent) |
| 88919 | * accuracy, so that Dragon4 will generate enough binary output digits. |
| 88920 | * For decimal numbers, this means generating a 20-digit significand, |
| 88921 | * which should yield enough practical accuracy to parse IEEE doubles. |
| 88922 | * In fact, the ECMAScript specification explicitly allows an |
| 88923 | * implementation to treat digits beyond 20 as zeroes (and even |
| 88924 | * to round the 20th digit upwards). For non-decimal numbers, the |
| 88925 | * appropriate number of digits has been precomputed for comparable |
| 88926 | * accuracy. |
| 88927 | * |
| 88928 | * Digit counts: |
| 88929 | * |
| 88930 | * [ dig_lzero ] |
| 88931 | * | |
| 88932 | * .+-..---[ dig_prec ]----. |
| 88933 | * | || | |
| 88934 | * 0000123.456789012345678901234567890e+123456 |
| 88935 | * | | | | | | |
| 88936 | * `--+--' `------[ dig_frac ]-------' `-+--' |
| 88937 | * | | |
| 88938 | * [ dig_whole ] [ dig_expt ] |
| 88939 | * |
| 88940 | * dig_frac and dig_expt are -1 if not present |
| 88941 | * dig_lzero is only computed for whole number part |
| 88942 | * |
| 88943 | * Parsing state |
| 88944 | * |
| 88945 | * Parsing whole part dig_frac < 0 AND dig_expt < 0 |
| 88946 | * Parsing fraction part dig_frac >= 0 AND dig_expt < 0 |
| 88947 | * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0) |
| 88948 | * |
| 88949 | * Note: in case we hit an implementation limit (like exponent range), |
| 88950 | * we should throw an error, NOT return NaN or Infinity. Even with |
| 88951 | * very large exponent (or significand) values the final result may be |
| 88952 | * finite, so NaN/Infinity would be incorrect. |
| 88953 | */ |
| 88954 | |
| 88955 | duk__bi_set_small(&nc_ctx->f, 0); |
| 88956 | dig_prec = 0; |
| 88957 | dig_lzero = 0; |
| 88958 | dig_whole = 0; |
| 88959 | dig_frac = -1; |
| 88960 | dig_expt = -1; |
| 88961 | expt = 0; |
| 88962 | expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */ |
| 88963 | expt_neg = 0; |
| 88964 | for (;;) { |
| 88965 | ch = *p++; |
| 88966 | |
| 88967 | DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, " |
| 88968 | "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld" , |
| 88969 | (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch, |
| 88970 | (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac, |
| 88971 | (long) dig_expt, (long) dig_lzero, (long) dig_prec)); |
| 88972 | DUK__BI_PRINT("f" , &nc_ctx->f); |
| 88973 | |
| 88974 | /* Most common cases first. */ |
| 88975 | if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') { |
| 88976 | dig = (duk_small_int_t) ch - '0' + 0; |
| 88977 | } else if (ch == (duk_small_int_t) '.') { |
| 88978 | /* A leading digit is not required in some cases, e.g. accept ".123". |
| 88979 | * In other cases (JSON.parse()) a leading digit is required. This |
| 88980 | * is checked for after the loop. |
| 88981 | */ |
| 88982 | if (dig_frac >= 0 || dig_expt >= 0) { |
| 88983 | if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) { |
| 88984 | DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)" )); |
| 88985 | break; |
| 88986 | } else { |
| 88987 | DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed" )); |
| 88988 | goto parse_fail; |
| 88989 | } |
| 88990 | } |
| 88991 | |
| 88992 | if ((flags & DUK_S2N_FLAG_ALLOW_FRAC) == 0) { |
| 88993 | /* Some contexts don't allow fractions at all; this can't be a |
| 88994 | * post-check because the state ('f' and expt) would be incorrect. |
| 88995 | */ |
| 88996 | if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) { |
| 88997 | DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)" )); |
| 88998 | break; |
| 88999 | } else { |
| 89000 | DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed" )); |
| 89001 | } |
| 89002 | } |
| 89003 | |
| 89004 | DUK_DDD(DUK_DDDPRINT("start fraction part" )); |
| 89005 | dig_frac = 0; |
| 89006 | continue; |
| 89007 | } else if (ch == (duk_small_int_t) 0) { |
| 89008 | DUK_DDD(DUK_DDDPRINT("NUL termination" )); |
| 89009 | break; |
| 89010 | } else if ((flags & DUK_S2N_FLAG_ALLOW_EXP) && |
| 89011 | dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) { |
| 89012 | /* Note: we don't parse back exponent notation for anything else |
| 89013 | * than radix 10, so this is not an ambiguous check (e.g. hex |
| 89014 | * exponent values may have 'e' either as a significand digit |
| 89015 | * or as an exponent separator). |
| 89016 | * |
| 89017 | * If the exponent separator occurs twice, 'e' will be interpreted |
| 89018 | * as a digit (= 14) and will be rejected as an invalid decimal |
| 89019 | * digit. |
| 89020 | */ |
| 89021 | |
| 89022 | DUK_DDD(DUK_DDDPRINT("start exponent part" )); |
| 89023 | |
| 89024 | /* Exponent without a sign or with a +/- sign is accepted |
| 89025 | * by all call sites (even JSON.parse()). |
| 89026 | */ |
| 89027 | ch = *p; |
| 89028 | if (ch == (duk_small_int_t) '-') { |
| 89029 | expt_neg = 1; |
| 89030 | p++; |
| 89031 | } else if (ch == (duk_small_int_t) '+') { |
| 89032 | p++; |
| 89033 | } |
| 89034 | dig_expt = 0; |
| 89035 | continue; |
| 89036 | } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') { |
| 89037 | dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a); |
| 89038 | } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') { |
| 89039 | dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a); |
| 89040 | } else { |
| 89041 | dig = 255; /* triggers garbage digit check below */ |
| 89042 | } |
| 89043 | DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255); |
| 89044 | |
| 89045 | if (dig >= radix) { |
| 89046 | if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) { |
| 89047 | DUK_DDD(DUK_DDDPRINT("garbage termination" )); |
| 89048 | break; |
| 89049 | } else { |
| 89050 | DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit" )); |
| 89051 | goto parse_fail; |
| 89052 | } |
| 89053 | } |
| 89054 | |
| 89055 | if (dig_expt < 0) { |
| 89056 | /* whole or fraction digit */ |
| 89057 | |
| 89058 | if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) { |
| 89059 | /* significant from precision perspective */ |
| 89060 | |
| 89061 | duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f); |
| 89062 | if (f_zero && dig == 0) { |
| 89063 | /* Leading zero is not counted towards precision digits; not |
| 89064 | * in the integer part, nor in the fraction part. |
| 89065 | */ |
| 89066 | if (dig_frac < 0) { |
| 89067 | dig_lzero++; |
| 89068 | } |
| 89069 | } else { |
| 89070 | /* XXX: join these ops (multiply-accumulate), but only if |
| 89071 | * code footprint decreases. |
| 89072 | */ |
| 89073 | duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, (duk_uint32_t) radix); |
| 89074 | duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, (duk_uint32_t) dig); |
| 89075 | dig_prec++; |
| 89076 | } |
| 89077 | } else { |
| 89078 | /* Ignore digits beyond a radix-specific limit, but note them |
| 89079 | * in expt_adj. |
| 89080 | */ |
| 89081 | expt_adj++; |
| 89082 | } |
| 89083 | |
| 89084 | if (dig_frac >= 0) { |
| 89085 | dig_frac++; |
| 89086 | expt_adj--; |
| 89087 | } else { |
| 89088 | dig_whole++; |
| 89089 | } |
| 89090 | } else { |
| 89091 | /* exponent digit */ |
| 89092 | |
| 89093 | DUK_ASSERT(radix == 10); |
| 89094 | expt = expt * radix + dig; |
| 89095 | if (expt > DUK_S2N_MAX_EXPONENT) { |
| 89096 | /* Impose a reasonable exponent limit, so that exp |
| 89097 | * doesn't need to get tracked using a bigint. |
| 89098 | */ |
| 89099 | DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large" )); |
| 89100 | goto parse_explimit_error; |
| 89101 | } |
| 89102 | dig_expt++; |
| 89103 | } |
| 89104 | } |
| 89105 | |
| 89106 | /* Leading zero. */ |
| 89107 | |
| 89108 | if (dig_lzero > 0 && dig_whole > 1) { |
| 89109 | if ((flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO) == 0) { |
| 89110 | DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part" )); |
| 89111 | goto parse_fail; |
| 89112 | } |
| 89113 | } |
| 89114 | |
| 89115 | /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */ |
| 89116 | |
| 89117 | if (dig_whole == 0) { |
| 89118 | if (dig_frac == 0) { |
| 89119 | /* "." is not accepted in any format */ |
| 89120 | DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits" )); |
| 89121 | goto parse_fail; |
| 89122 | } else if (dig_frac > 0) { |
| 89123 | /* ".123" */ |
| 89124 | if ((flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC) == 0) { |
| 89125 | DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without " |
| 89126 | "leading integer digit(s)" )); |
| 89127 | goto parse_fail; |
| 89128 | } |
| 89129 | } else { |
| 89130 | /* Empty ("") is allowed in some formats (e.g. Number(''), as zero, |
| 89131 | * but it must not have a leading +/- sign (GH-2019). Note that |
| 89132 | * for Number(), h_str is already trimmed so we can check for zero |
| 89133 | * length and still get Number(' + ') == NaN. |
| 89134 | */ |
| 89135 | if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO) == 0) { |
| 89136 | DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)" )); |
| 89137 | goto parse_fail; |
| 89138 | } else if (DUK_HSTRING_GET_BYTELEN(h_str) != 0) { |
| 89139 | DUK_DDD(DUK_DDDPRINT("parse failed: no digits, but not empty (had a +/- sign)" )); |
| 89140 | goto parse_fail; |
| 89141 | } |
| 89142 | } |
| 89143 | } else { |
| 89144 | if (dig_frac == 0) { |
| 89145 | /* "123." is allowed in some formats */ |
| 89146 | if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC) == 0) { |
| 89147 | DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions" )); |
| 89148 | goto parse_fail; |
| 89149 | } |
| 89150 | } else if (dig_frac > 0) { |
| 89151 | /* "123.456" */ |
| 89152 | ; |
| 89153 | } else { |
| 89154 | /* "123" */ |
| 89155 | ; |
| 89156 | } |
| 89157 | } |
| 89158 | |
| 89159 | /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is |
| 89160 | * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0). |
| 89161 | */ |
| 89162 | |
| 89163 | if (dig_expt == 0) { |
| 89164 | if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0) { |
| 89165 | DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent" )); |
| 89166 | goto parse_fail; |
| 89167 | } |
| 89168 | DUK_ASSERT(expt == 0); |
| 89169 | } |
| 89170 | |
| 89171 | if (expt_neg) { |
| 89172 | expt = -expt; |
| 89173 | } |
| 89174 | DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld" , |
| 89175 | (long) expt, (long) expt_adj, (long) (expt + expt_adj))); |
| 89176 | expt += expt_adj; |
| 89177 | |
| 89178 | /* Fast path check. */ |
| 89179 | |
| 89180 | if (nc_ctx->f.n <= 1 && /* 32-bit value */ |
| 89181 | expt == 0 /* no net exponent */) { |
| 89182 | /* Fast path is triggered for no exponent and also for balanced exponent |
| 89183 | * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect |
| 89184 | * zero sign. |
| 89185 | */ |
| 89186 | |
| 89187 | /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */ |
| 89188 | DUK_DDD(DUK_DDDPRINT("fast path number parse" )); |
| 89189 | if (nc_ctx->f.n == 1) { |
| 89190 | res = (double) nc_ctx->f.v[0]; |
| 89191 | } else { |
| 89192 | res = 0.0; |
| 89193 | } |
| 89194 | goto negcheck_and_ret; |
| 89195 | } |
| 89196 | |
| 89197 | /* Significand ('f') padding. */ |
| 89198 | |
| 89199 | while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) { |
| 89200 | /* Pad significand with "virtual" zero digits so that Dragon4 will |
| 89201 | * have enough (apparent) precision to work with. |
| 89202 | */ |
| 89203 | DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero" , (long) dig_prec)); |
| 89204 | duk__bi_mul_small_copy(&nc_ctx->f, (duk_uint32_t) radix, &nc_ctx->t1); |
| 89205 | DUK__BI_PRINT("f" , &nc_ctx->f); |
| 89206 | expt--; |
| 89207 | dig_prec++; |
| 89208 | } |
| 89209 | |
| 89210 | DUK_DDD(DUK_DDDPRINT("final exponent: %ld" , (long) expt)); |
| 89211 | |
| 89212 | /* Detect zero special case. */ |
| 89213 | |
| 89214 | if (nc_ctx->f.n == 0) { |
| 89215 | /* This may happen even after the fast path check, if exponent is |
| 89216 | * not balanced (e.g. "0e1"). Remember to respect zero sign. |
| 89217 | */ |
| 89218 | DUK_DDD(DUK_DDDPRINT("significand is zero" )); |
| 89219 | res = 0.0; |
| 89220 | goto negcheck_and_ret; |
| 89221 | } |
| 89222 | |
| 89223 | |
| 89224 | /* Quick reject of too large or too small exponents. This check |
| 89225 | * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity) |
| 89226 | * so zero check must be above. |
| 89227 | */ |
| 89228 | |
| 89229 | explim = &duk__str2num_exp_limits[radix - 2]; |
| 89230 | if (expt > explim->upper) { |
| 89231 | DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite" )); |
| 89232 | res = (duk_double_t) DUK_DOUBLE_INFINITY; |
| 89233 | goto negcheck_and_ret; |
| 89234 | } else if (expt < explim->lower) { |
| 89235 | DUK_DDD(DUK_DDDPRINT("exponent too small -> zero" )); |
| 89236 | res = (duk_double_t) 0.0; |
| 89237 | goto negcheck_and_ret; |
| 89238 | } |
| 89239 | |
| 89240 | nc_ctx->is_s2n = 1; |
| 89241 | nc_ctx->e = expt; |
| 89242 | nc_ctx->b = radix; |
| 89243 | nc_ctx->B = 2; |
| 89244 | nc_ctx->is_fixed = 1; |
| 89245 | nc_ctx->abs_pos = 0; |
| 89246 | nc_ctx->req_digits = 53 + 1; |
| 89247 | |
| 89248 | DUK__BI_PRINT("f" , &nc_ctx->f); |
| 89249 | DUK_DDD(DUK_DDDPRINT("e=%ld" , (long) nc_ctx->e)); |
| 89250 | |
| 89251 | /* |
| 89252 | * Dragon4 slow path (binary) digit generation. |
| 89253 | * An extra digit is generated for rounding. |
| 89254 | */ |
| 89255 | |
| 89256 | duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */ |
| 89257 | |
| 89258 | DUK_DDD(DUK_DDDPRINT("after prepare:" )); |
| 89259 | DUK__BI_PRINT("r" , &nc_ctx->r); |
| 89260 | DUK__BI_PRINT("s" , &nc_ctx->s); |
| 89261 | DUK__BI_PRINT("mp" , &nc_ctx->mp); |
| 89262 | DUK__BI_PRINT("mm" , &nc_ctx->mm); |
| 89263 | |
| 89264 | duk__dragon4_scale(nc_ctx); |
| 89265 | |
| 89266 | DUK_DDD(DUK_DDDPRINT("after scale; k=%ld" , (long) nc_ctx->k)); |
| 89267 | DUK__BI_PRINT("r" , &nc_ctx->r); |
| 89268 | DUK__BI_PRINT("s" , &nc_ctx->s); |
| 89269 | DUK__BI_PRINT("mp" , &nc_ctx->mp); |
| 89270 | DUK__BI_PRINT("mm" , &nc_ctx->mm); |
| 89271 | |
| 89272 | duk__dragon4_generate(nc_ctx); |
| 89273 | |
| 89274 | DUK_ASSERT(nc_ctx->count == 53 + 1); |
| 89275 | |
| 89276 | /* |
| 89277 | * Convert binary digits into an IEEE double. Need to handle |
| 89278 | * denormals and rounding correctly. |
| 89279 | * |
| 89280 | * Some call sites currently assume the result is always a |
| 89281 | * non-fastint double. If this is changed, check all call |
| 89282 | * sites. |
| 89283 | */ |
| 89284 | |
| 89285 | duk__dragon4_ctx_to_double(nc_ctx, &res); |
| 89286 | goto negcheck_and_ret; |
| 89287 | |
| 89288 | negcheck_and_ret: |
| 89289 | if (neg) { |
| 89290 | res = -res; |
| 89291 | } |
| 89292 | duk_pop(thr); |
| 89293 | duk_push_number(thr, (double) res); |
| 89294 | DUK_DDD(DUK_DDDPRINT("result: %!T" , (duk_tval *) duk_get_tval(thr, -1))); |
| 89295 | return; |
| 89296 | |
| 89297 | parse_fail: |
| 89298 | DUK_DDD(DUK_DDDPRINT("parse failed" )); |
| 89299 | duk_pop(thr); |
| 89300 | duk_push_nan(thr); |
| 89301 | return; |
| 89302 | |
| 89303 | parse_explimit_error: |
| 89304 | DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value" )); |
| 89305 | DUK_ERROR_RANGE(thr, "exponent too large" ); |
| 89306 | DUK_WO_NORETURN(return;); |
| 89307 | } |
| 89308 | |
| 89309 | DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) { |
| 89310 | duk_native_stack_check(thr); |
| 89311 | duk__numconv_parse_raw(thr, radix, flags); |
| 89312 | } |
| 89313 | |
| 89314 | /* automatic undefs */ |
| 89315 | #undef DUK__BI_MAX_PARTS |
| 89316 | #undef DUK__BI_PRINT |
| 89317 | #undef DUK__DIGITCHAR |
| 89318 | #undef DUK__DRAGON4_OUTPUT_PREINC |
| 89319 | #undef DUK__IEEE_DOUBLE_EXP_BIAS |
| 89320 | #undef DUK__IEEE_DOUBLE_EXP_MIN |
| 89321 | #undef DUK__MAX_FORMATTED_LENGTH |
| 89322 | #undef DUK__MAX_OUTPUT_DIGITS |
| 89323 | #undef DUK__NO_EXP |
| 89324 | #undef DUK__NUMCONV_CTX_BIGINTS_SIZE |
| 89325 | #undef DUK__NUMCONV_CTX_NUM_BIGINTS |
| 89326 | #line 1 "duk_regexp_compiler.c" |
| 89327 | /* |
| 89328 | * Regexp compilation. |
| 89329 | * |
| 89330 | * See doc/regexp.rst for a discussion of the compilation approach and |
| 89331 | * current limitations. |
| 89332 | * |
| 89333 | * Regexp bytecode assumes jumps can be expressed with signed 32-bit |
| 89334 | * integers. Consequently the bytecode size must not exceed 0x7fffffffL. |
| 89335 | * The implementation casts duk_size_t (buffer size) to duk_(u)int32_t |
| 89336 | * in many places. Although this could be changed, the bytecode format |
| 89337 | * limit would still prevent regexps exceeding the signed 32-bit limit |
| 89338 | * from working. |
| 89339 | * |
| 89340 | * XXX: The implementation does not prevent bytecode from exceeding the |
| 89341 | * maximum supported size. This could be done by limiting the maximum |
| 89342 | * input string size (assuming an upper bound can be computed for number |
| 89343 | * of bytecode bytes emitted per input byte) or checking buffer maximum |
| 89344 | * size when emitting bytecode (slower). |
| 89345 | */ |
| 89346 | |
| 89347 | /* #include duk_internal.h -> already included */ |
| 89348 | |
| 89349 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 89350 | |
| 89351 | /* |
| 89352 | * Helper macros |
| 89353 | */ |
| 89354 | |
| 89355 | #define DUK__RE_INITIAL_BUFSIZE 64 |
| 89356 | |
| 89357 | #define DUK__RE_BUFLEN(re_ctx) \ |
| 89358 | DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw) |
| 89359 | |
| 89360 | /* |
| 89361 | * Disjunction struct: result of parsing a disjunction |
| 89362 | */ |
| 89363 | |
| 89364 | typedef struct { |
| 89365 | /* Number of characters that the atom matches (e.g. 3 for 'abc'), |
| 89366 | * -1 if atom is complex and number of matched characters either |
| 89367 | * varies or is not known. |
| 89368 | */ |
| 89369 | duk_int32_t charlen; |
| 89370 | |
| 89371 | #if 0 |
| 89372 | /* These are not needed to implement quantifier capture handling, |
| 89373 | * but might be needed at some point. |
| 89374 | */ |
| 89375 | |
| 89376 | /* re_ctx->captures at start and end of atom parsing. |
| 89377 | * Since 'captures' indicates highest capture number emitted |
| 89378 | * so far in a DUK_REOP_SAVE, the captures numbers saved by |
| 89379 | * the atom are: ]start_captures,end_captures]. |
| 89380 | */ |
| 89381 | duk_uint32_t start_captures; |
| 89382 | duk_uint32_t end_captures; |
| 89383 | #endif |
| 89384 | } duk__re_disjunction_info; |
| 89385 | |
| 89386 | /* |
| 89387 | * Encoding helpers |
| 89388 | * |
| 89389 | * Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit |
| 89390 | * even though the buffer operations will use duk_size_t. |
| 89391 | */ |
| 89392 | |
| 89393 | /* XXX: the insert helpers should ensure that the bytecode result is not |
| 89394 | * larger than expected (or at least assert for it). Many things in the |
| 89395 | * bytecode, like skip offsets, won't work correctly if the bytecode is |
| 89396 | * larger than say 2G. |
| 89397 | */ |
| 89398 | |
| 89399 | DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) { |
| 89400 | if (x < 0) { |
| 89401 | return ((duk_uint32_t) (-x)) * 2 + 1; |
| 89402 | } else { |
| 89403 | return ((duk_uint32_t) x) * 2; |
| 89404 | } |
| 89405 | } |
| 89406 | |
| 89407 | /* XXX: return type should probably be duk_size_t, or explicit checks are needed for |
| 89408 | * maximum size. |
| 89409 | */ |
| 89410 | DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) { |
| 89411 | duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH]; |
| 89412 | duk_small_int_t len; |
| 89413 | |
| 89414 | len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf); |
| 89415 | DUK_ASSERT(len >= 0); |
| 89416 | DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, (duk_size_t) len); |
| 89417 | return (duk_uint32_t) len; |
| 89418 | } |
| 89419 | |
| 89420 | DUK_LOCAL void duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) { |
| 89421 | DUK_BW_WRITE_ENSURE_XUTF8(re_ctx->thr, &re_ctx->bw, x); |
| 89422 | } |
| 89423 | |
| 89424 | DUK_LOCAL void duk__append_7bit(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) { |
| 89425 | #if defined(DUK_USE_PREFER_SIZE) |
| 89426 | duk__append_u32(re_ctx, x); |
| 89427 | #else |
| 89428 | DUK_ASSERT(x <= 0x7fU); |
| 89429 | DUK_BW_WRITE_ENSURE_U8(re_ctx->thr, &re_ctx->bw, (duk_uint8_t) x); |
| 89430 | #endif |
| 89431 | } |
| 89432 | |
| 89433 | #if 0 |
| 89434 | DUK_LOCAL void duk__append_2bytes(duk_re_compiler_ctx *re_ctx, duk_uint8_t x, duk_uint8_t y) { |
| 89435 | DUK_BW_WRITE_ENSURE_U8_2(re_ctx->thr, &re_ctx->bw, x, y); |
| 89436 | } |
| 89437 | #endif |
| 89438 | |
| 89439 | DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) { |
| 89440 | return duk__insert_u32(re_ctx, offset, duk__encode_i32(x)); |
| 89441 | } |
| 89442 | |
| 89443 | DUK_LOCAL void duk__append_reop(duk_re_compiler_ctx *re_ctx, duk_uint32_t reop) { |
| 89444 | DUK_ASSERT(reop <= 0x7fU); |
| 89445 | (void) duk__append_7bit(re_ctx, reop); |
| 89446 | } |
| 89447 | |
| 89448 | #if 0 /* unused */ |
| 89449 | DUK_LOCAL void duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) { |
| 89450 | duk__append_u32(re_ctx, duk__encode_i32(x)); |
| 89451 | } |
| 89452 | #endif |
| 89453 | |
| 89454 | /* special helper for emitting u16 lists (used for character ranges for built-in char classes) */ |
| 89455 | DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) { |
| 89456 | /* Call sites don't need the result length so it's not accumulated. */ |
| 89457 | while (count-- > 0) { |
| 89458 | duk__append_u32(re_ctx, (duk_uint32_t) (*values++)); |
| 89459 | } |
| 89460 | } |
| 89461 | |
| 89462 | DUK_LOCAL void duk__insert_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t data_offset, duk_uint32_t data_length) { |
| 89463 | DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length); |
| 89464 | } |
| 89465 | |
| 89466 | DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) { |
| 89467 | DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length); |
| 89468 | } |
| 89469 | |
| 89470 | DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) { |
| 89471 | DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length); |
| 89472 | } |
| 89473 | |
| 89474 | /* |
| 89475 | * Insert a jump offset at 'offset' to complete an instruction |
| 89476 | * (the jump offset is always the last component of an instruction). |
| 89477 | * The 'skip' argument must be computed relative to 'offset', |
| 89478 | * -without- taking into account the skip field being inserted. |
| 89479 | * |
| 89480 | * ... A B C ins X Y Z ... (ins may be a JUMP, SPLIT1/SPLIT2, etc) |
| 89481 | * => ... A B C ins SKIP X Y Z |
| 89482 | * |
| 89483 | * Computing the final (adjusted) skip value, which is relative to the |
| 89484 | * first byte of the next instruction, is a bit tricky because of the |
| 89485 | * variable length UTF-8 encoding. See doc/regexp.rst for discussion. |
| 89486 | */ |
| 89487 | DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) { |
| 89488 | #if 0 |
| 89489 | /* Iterative solution. */ |
| 89490 | if (skip < 0) { |
| 89491 | duk_small_int_t len; |
| 89492 | /* two encoding attempts suffices */ |
| 89493 | len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip)); |
| 89494 | len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len)); |
| 89495 | DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */ |
| 89496 | skip -= (duk_int32_t) len; |
| 89497 | } |
| 89498 | #endif |
| 89499 | |
| 89500 | #if defined(DUK_USE_PREFER_SIZE) |
| 89501 | /* Closed form solution, this produces smallest code. |
| 89502 | * See re_neg_jump_offset (closed2). |
| 89503 | */ |
| 89504 | if (skip < 0) { |
| 89505 | skip--; |
| 89506 | if (skip < -0x3fL) { |
| 89507 | skip--; |
| 89508 | } |
| 89509 | if (skip < -0x3ffL) { |
| 89510 | skip--; |
| 89511 | } |
| 89512 | if (skip < -0x7fffL) { |
| 89513 | skip--; |
| 89514 | } |
| 89515 | if (skip < -0xfffffL) { |
| 89516 | skip--; |
| 89517 | } |
| 89518 | if (skip < -0x1ffffffL) { |
| 89519 | skip--; |
| 89520 | } |
| 89521 | if (skip < -0x3fffffffL) { |
| 89522 | skip--; |
| 89523 | } |
| 89524 | } |
| 89525 | #else /* DUK_USE_PREFER_SIZE */ |
| 89526 | /* Closed form solution, this produces fastest code. |
| 89527 | * See re_neg_jump_offset (closed1). |
| 89528 | */ |
| 89529 | if (skip < 0) { |
| 89530 | if (skip >= -0x3eL) { |
| 89531 | skip -= 1; |
| 89532 | } else if (skip >= -0x3fdL) { |
| 89533 | skip -= 2; |
| 89534 | } else if (skip >= -0x7ffcL) { |
| 89535 | skip -= 3; |
| 89536 | } else if (skip >= -0xffffbL) { |
| 89537 | skip -= 4; |
| 89538 | } else if (skip >= -0x1fffffaL) { |
| 89539 | skip -= 5; |
| 89540 | } else if (skip >= -0x3ffffff9L) { |
| 89541 | skip -= 6; |
| 89542 | } else { |
| 89543 | skip -= 7; |
| 89544 | } |
| 89545 | } |
| 89546 | #endif /* DUK_USE_PREFER_SIZE */ |
| 89547 | |
| 89548 | return duk__insert_i32(re_ctx, offset, skip); |
| 89549 | } |
| 89550 | |
| 89551 | DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) { |
| 89552 | return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip); |
| 89553 | } |
| 89554 | |
| 89555 | /* |
| 89556 | * duk_re_range_callback for generating character class ranges. |
| 89557 | * |
| 89558 | * When ignoreCase is false, the range is simply emitted as is. We don't, |
| 89559 | * for instance, eliminate duplicates or overlapping ranges in a character |
| 89560 | * class. |
| 89561 | * |
| 89562 | * When ignoreCase is true but the 'direct' flag is set, the caller knows |
| 89563 | * that the range canonicalizes to itself for case insensitive matching, |
| 89564 | * so the range is emitted as is. This is mainly useful for built-in ranges |
| 89565 | * like \W. |
| 89566 | * |
| 89567 | * Otherwise, when ignoreCase is true, the range needs to be normalized |
| 89568 | * through canonicalization. Unfortunately a canonicalized version of a |
| 89569 | * continuous range is not necessarily continuous (e.g. [x-{] is continuous |
| 89570 | * but [X-{] is not). As a result, a single input range may expand to a lot |
| 89571 | * of output ranges. The current algorithm creates the canonicalized ranges |
| 89572 | * footprint efficiently at the cost of compile time execution time; see |
| 89573 | * doc/regexp.rst for discussion, and some more details below. |
| 89574 | * |
| 89575 | * Note that the ctx->nranges is a context-wide temporary value. This is OK |
| 89576 | * because there cannot be multiple character classes being parsed |
| 89577 | * simultaneously. |
| 89578 | * |
| 89579 | * More detail on canonicalization: |
| 89580 | * |
| 89581 | * Conceptually, a range is canonicalized by scanning the entire range, |
| 89582 | * normalizing each codepoint by converting it to uppercase, and generating |
| 89583 | * a set of result ranges. |
| 89584 | * |
| 89585 | * Ideally a minimal set of output ranges would be emitted by merging all |
| 89586 | * possible ranges even if they're emitted out of sequence. Because the |
| 89587 | * input string is also case normalized during matching, some codepoints |
| 89588 | * never occur at runtime; these "don't care" codepoints can be included or |
| 89589 | * excluded from ranges when merging/optimizing ranges. |
| 89590 | * |
| 89591 | * The current algorithm does not do optimal range merging. Rather, output |
| 89592 | * codepoints are generated in sequence, and when the output codepoints are |
| 89593 | * continuous (CP, CP+1, CP+2, ...), they are merged locally into as large a |
| 89594 | * range as possible. A small canonicalization bitmap is used to reduce |
| 89595 | * actual codepoint canonicalizations which are quite slow at present. The |
| 89596 | * bitmap provides a "codepoint block is continuous with respect to |
| 89597 | * canonicalization" for N-codepoint blocks. This allows blocks to be |
| 89598 | * skipped quickly. |
| 89599 | * |
| 89600 | * There are a number of shortcomings and future work here: |
| 89601 | * |
| 89602 | * - Individual codepoint normalizations are slow because they involve |
| 89603 | * walking bit-packed rules without a lookup index. |
| 89604 | * |
| 89605 | * - The conceptual algorithm needs to canonicalize every codepoint in the |
| 89606 | * input range to figure out the output range(s). Even with the small |
| 89607 | * canonicalization bitmap the algorithm runs quite slowly for worst case |
| 89608 | * inputs. There are many data structure alternatives to improve this. |
| 89609 | * |
| 89610 | * - While the current algorithm generates maximal output ranges when the |
| 89611 | * output codepoints are emitted linearly, output ranges are not sorted or |
| 89612 | * merged otherwise. In the worst case a lot of ranges are emitted when |
| 89613 | * most of the ranges could be merged. In this process one could take |
| 89614 | * advantage of "don't care" codepoints, which are never matched against at |
| 89615 | * runtime due to canonicalization of input codepoints before comparison, |
| 89616 | * to merge otherwise discontinuous output ranges. |
| 89617 | * |
| 89618 | * - The runtime data structure is just a linear list of ranges to match |
| 89619 | * against. This can be quite slow if there are a lot of output ranges. |
| 89620 | * There are various ways to make matching against the ranges faster, |
| 89621 | * e.g. sorting the ranges and using a binary search; skip lists; tree |
| 89622 | * based representations; full or approximate codepoint bitmaps, etc. |
| 89623 | * |
| 89624 | * - Only BMP is supported, codepoints above BMP are assumed to canonicalize |
| 89625 | * to themselves. For now this is one place where we don't want to |
| 89626 | * support chars outside the BMP, because the exhaustive search would be |
| 89627 | * massively larger. It would be possible to support non-BMP with a |
| 89628 | * different algorithm, or perhaps doing case normalization only at match |
| 89629 | * time. |
| 89630 | */ |
| 89631 | |
| 89632 | DUK_LOCAL void duk__regexp_emit_range(duk_re_compiler_ctx *re_ctx, duk_codepoint_t r1, duk_codepoint_t r2) { |
| 89633 | DUK_ASSERT(r2 >= r1); |
| 89634 | duk__append_u32(re_ctx, (duk_uint32_t) r1); |
| 89635 | duk__append_u32(re_ctx, (duk_uint32_t) r2); |
| 89636 | re_ctx->nranges++; |
| 89637 | } |
| 89638 | |
| 89639 | #if defined(DUK_USE_REGEXP_CANON_BITMAP) |
| 89640 | /* Find next canonicalization discontinuity (conservative estimate) starting |
| 89641 | * from 'start', not exceeding 'end'. If continuity is fine up to 'end' |
| 89642 | * inclusive, returns end. Minimum possible return value is start. |
| 89643 | */ |
| 89644 | DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) { |
| 89645 | duk_uint_t start_blk; |
| 89646 | duk_uint_t end_blk; |
| 89647 | duk_uint_t blk; |
| 89648 | duk_uint_t offset; |
| 89649 | duk_uint8_t mask; |
| 89650 | |
| 89651 | /* Inclusive block range. */ |
| 89652 | DUK_ASSERT(start >= 0); |
| 89653 | DUK_ASSERT(end >= 0); |
| 89654 | DUK_ASSERT(end >= start); |
| 89655 | start_blk = (duk_uint_t) (start >> DUK_CANON_BITMAP_BLKSHIFT); |
| 89656 | end_blk = (duk_uint_t) (end >> DUK_CANON_BITMAP_BLKSHIFT); |
| 89657 | |
| 89658 | for (blk = start_blk; blk <= end_blk; blk++) { |
| 89659 | offset = blk >> 3; |
| 89660 | mask = 1U << (blk & 0x07); |
| 89661 | if (offset >= sizeof(duk_unicode_re_canon_bitmap)) { |
| 89662 | /* Reached non-BMP range which is assumed continuous. */ |
| 89663 | return end; |
| 89664 | } |
| 89665 | DUK_ASSERT(offset < sizeof(duk_unicode_re_canon_bitmap)); |
| 89666 | if ((duk_unicode_re_canon_bitmap[offset] & mask) == 0) { |
| 89667 | /* Block is discontinuous, continuity is guaranteed |
| 89668 | * only up to end of previous block (+1 for exclusive |
| 89669 | * return value => start of current block). Start |
| 89670 | * block requires special handling. |
| 89671 | */ |
| 89672 | if (blk > start_blk) { |
| 89673 | return (duk_codepoint_t) (blk << DUK_CANON_BITMAP_BLKSHIFT); |
| 89674 | } else { |
| 89675 | return start; |
| 89676 | } |
| 89677 | } |
| 89678 | } |
| 89679 | DUK_ASSERT(blk == end_blk + 1); /* Reached end block which is continuous. */ |
| 89680 | return end; |
| 89681 | } |
| 89682 | #else /* DUK_USE_REGEXP_CANON_BITMAP */ |
| 89683 | DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) { |
| 89684 | DUK_ASSERT(start >= 0); |
| 89685 | DUK_ASSERT(end >= 0); |
| 89686 | DUK_ASSERT(end >= start); |
| 89687 | if (start >= 0x10000) { |
| 89688 | /* Even without the bitmap, treat non-BMP as continuous. */ |
| 89689 | return end; |
| 89690 | } |
| 89691 | return start; |
| 89692 | } |
| 89693 | #endif /* DUK_USE_REGEXP_CANON_BITMAP */ |
| 89694 | |
| 89695 | DUK_LOCAL void duk__regexp_generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) { |
| 89696 | duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata; |
| 89697 | duk_codepoint_t r_start; |
| 89698 | duk_codepoint_t r_end; |
| 89699 | duk_codepoint_t i; |
| 89700 | duk_codepoint_t t; |
| 89701 | duk_codepoint_t r_disc; |
| 89702 | |
| 89703 | DUK_DD(DUK_DDPRINT("duk__regexp_generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld" , |
| 89704 | (void *) re_ctx, (long) r1, (long) r2, (long) direct)); |
| 89705 | |
| 89706 | DUK_ASSERT(r2 >= r1); /* SyntaxError for out of order range. */ |
| 89707 | |
| 89708 | if (direct || (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) == 0) { |
| 89709 | DUK_DD(DUK_DDPRINT("direct or not case sensitive, emit range: [%ld,%ld]" , (long) r1, (long) r2)); |
| 89710 | duk__regexp_emit_range(re_ctx, r1, r2); |
| 89711 | return; |
| 89712 | } |
| 89713 | |
| 89714 | DUK_DD(DUK_DDPRINT("case sensitive, process range: [%ld,%ld]" , (long) r1, (long) r2)); |
| 89715 | |
| 89716 | r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1); |
| 89717 | r_end = r_start; |
| 89718 | |
| 89719 | for (i = r1 + 1; i <= r2;) { |
| 89720 | /* Input codepoint space processed up to i-1, and |
| 89721 | * current range in r_{start,end} is up-to-date |
| 89722 | * (inclusive) and may either break or continue. |
| 89723 | */ |
| 89724 | r_disc = duk__re_canon_next_discontinuity(i, r2); |
| 89725 | DUK_ASSERT(r_disc >= i); |
| 89726 | DUK_ASSERT(r_disc <= r2); |
| 89727 | |
| 89728 | r_end += r_disc - i; /* May be zero. */ |
| 89729 | t = duk_unicode_re_canonicalize_char(re_ctx->thr, r_disc); |
| 89730 | if (t == r_end + 1) { |
| 89731 | /* Not actually a discontinuity, continue range |
| 89732 | * to r_disc and recheck. |
| 89733 | */ |
| 89734 | r_end = t; |
| 89735 | } else { |
| 89736 | duk__regexp_emit_range(re_ctx, r_start, r_end); |
| 89737 | r_start = t; |
| 89738 | r_end = t; |
| 89739 | } |
| 89740 | i = r_disc + 1; /* Guarantees progress. */ |
| 89741 | } |
| 89742 | duk__regexp_emit_range(re_ctx, r_start, r_end); |
| 89743 | |
| 89744 | #if 0 /* Exhaustive search, very slow. */ |
| 89745 | r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1); |
| 89746 | r_end = r_start; |
| 89747 | for (i = r1 + 1; i <= r2; i++) { |
| 89748 | t = duk_unicode_re_canonicalize_char(re_ctx->thr, i); |
| 89749 | if (t == r_end + 1) { |
| 89750 | r_end = t; |
| 89751 | } else { |
| 89752 | DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]" , (long) r_start, (long) r_end)); |
| 89753 | duk__append_u32(re_ctx, (duk_uint32_t) r_start); |
| 89754 | duk__append_u32(re_ctx, (duk_uint32_t) r_end); |
| 89755 | re_ctx->nranges++; |
| 89756 | r_start = t; |
| 89757 | r_end = t; |
| 89758 | } |
| 89759 | } |
| 89760 | DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]" , (long) r_start, (long) r_end)); |
| 89761 | duk__append_u32(re_ctx, (duk_uint32_t) r_start); |
| 89762 | duk__append_u32(re_ctx, (duk_uint32_t) r_end); |
| 89763 | re_ctx->nranges++; |
| 89764 | #endif |
| 89765 | } |
| 89766 | |
| 89767 | /* |
| 89768 | * Parse regexp Disjunction. Most of regexp compilation happens here. |
| 89769 | * |
| 89770 | * Handles Disjunction, Alternative, and Term productions directly without |
| 89771 | * recursion. The only constructs requiring recursion are positive/negative |
| 89772 | * lookaheads, capturing parentheses, and non-capturing parentheses. |
| 89773 | * |
| 89774 | * The function determines whether the entire disjunction is a 'simple atom' |
| 89775 | * (see doc/regexp.rst discussion on 'simple quantifiers') and if so, |
| 89776 | * returns the atom character length which is needed by the caller to keep |
| 89777 | * track of its own atom character length. A disjunction with more than one |
| 89778 | * alternative is never considered a simple atom (although in some cases |
| 89779 | * that might be the case). |
| 89780 | * |
| 89781 | * Return value: simple atom character length or < 0 if not a simple atom. |
| 89782 | * Appends the bytecode for the disjunction matcher to the end of the temp |
| 89783 | * buffer. |
| 89784 | * |
| 89785 | * Regexp top level structure is: |
| 89786 | * |
| 89787 | * Disjunction = Term* |
| 89788 | * | Term* | Disjunction |
| 89789 | * |
| 89790 | * Term = Assertion |
| 89791 | * | Atom |
| 89792 | * | Atom Quantifier |
| 89793 | * |
| 89794 | * An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/). |
| 89795 | * |
| 89796 | * Notes: |
| 89797 | * |
| 89798 | * * Tracking of the 'simple-ness' of the current atom vs. the entire |
| 89799 | * disjunction are separate matters. For instance, the disjunction |
| 89800 | * may be complex, but individual atoms may be simple. Furthermore, |
| 89801 | * simple quantifiers are used whenever possible, even if the |
| 89802 | * disjunction as a whole is complex. |
| 89803 | * |
| 89804 | * * The estimate of whether an atom is simple is conservative now, |
| 89805 | * and it would be possible to expand it. For instance, captures |
| 89806 | * cause the disjunction to be marked complex, even though captures |
| 89807 | * -can- be handled by simple quantifiers with some minor modifications. |
| 89808 | * |
| 89809 | * * Disjunction 'tainting' as 'complex' is handled at the end of the |
| 89810 | * main for loop collectively for atoms. Assertions, quantifiers, |
| 89811 | * and '|' tokens need to taint the result manually if necessary. |
| 89812 | * Assertions cannot add to result char length, only atoms (and |
| 89813 | * quantifiers) can; currently quantifiers will taint the result |
| 89814 | * as complex though. |
| 89815 | */ |
| 89816 | |
| 89817 | DUK_LOCAL const duk_uint16_t * const duk__re_range_lookup1[3] = { |
| 89818 | duk_unicode_re_ranges_digit, |
| 89819 | duk_unicode_re_ranges_white, |
| 89820 | duk_unicode_re_ranges_wordchar |
| 89821 | }; |
| 89822 | DUK_LOCAL const duk_uint8_t duk__re_range_lookup2[3] = { |
| 89823 | sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)), |
| 89824 | sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)), |
| 89825 | sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t)) |
| 89826 | }; |
| 89827 | |
| 89828 | DUK_LOCAL void duk__append_range_atom_matcher(duk_re_compiler_ctx *re_ctx, duk_small_uint_t re_op, const duk_uint16_t *ranges, duk_small_uint_t count) { |
| 89829 | #if 0 |
| 89830 | DUK_ASSERT(re_op <= 0x7fUL); |
| 89831 | DUK_ASSERT(count <= 0x7fUL); |
| 89832 | duk__append_2bytes(re_ctx, (duk_uint8_t) re_op, (duk_uint8_t) count); |
| 89833 | #endif |
| 89834 | duk__append_reop(re_ctx, re_op); |
| 89835 | duk__append_7bit(re_ctx, count); |
| 89836 | duk__append_u16_list(re_ctx, ranges, count * 2); |
| 89837 | } |
| 89838 | |
| 89839 | DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) { |
| 89840 | duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */ |
| 89841 | duk_int32_t atom_char_length = 0; /* negative -> complex atom */ |
| 89842 | duk_uint32_t atom_start_captures = re_ctx->captures; /* value of re_ctx->captures at start of atom */ |
| 89843 | duk_int32_t unpatched_disjunction_split = -1; |
| 89844 | duk_int32_t unpatched_disjunction_jump = -1; |
| 89845 | duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); |
| 89846 | duk_int32_t res_charlen = 0; /* -1 if disjunction is complex, char length if simple */ |
| 89847 | duk__re_disjunction_info tmp_disj; |
| 89848 | |
| 89849 | DUK_ASSERT(out_atom_info != NULL); |
| 89850 | |
| 89851 | duk_native_stack_check(re_ctx->thr); |
| 89852 | if (re_ctx->recursion_depth >= re_ctx->recursion_limit) { |
| 89853 | DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT); |
| 89854 | DUK_WO_NORETURN(return;); |
| 89855 | } |
| 89856 | re_ctx->recursion_depth++; |
| 89857 | |
| 89858 | #if 0 |
| 89859 | out_atom_info->start_captures = re_ctx->captures; |
| 89860 | #endif |
| 89861 | |
| 89862 | for (;;) { |
| 89863 | /* atom_char_length, atom_start_offset, atom_start_offset reflect the |
| 89864 | * atom matched on the previous loop. If a quantifier is encountered |
| 89865 | * on this loop, these are needed to handle the quantifier correctly. |
| 89866 | * new_atom_char_length etc are for the atom parsed on this round; |
| 89867 | * they're written to atom_char_length etc at the end of the round. |
| 89868 | */ |
| 89869 | duk_int32_t new_atom_char_length; /* char length of the atom parsed in this loop */ |
| 89870 | duk_int32_t new_atom_start_offset; /* bytecode start offset of the atom parsed in this loop |
| 89871 | * (allows quantifiers to copy the atom bytecode) |
| 89872 | */ |
| 89873 | duk_uint32_t new_atom_start_captures; /* re_ctx->captures at the start of the atom parsed in this loop */ |
| 89874 | |
| 89875 | duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token); |
| 89876 | |
| 89877 | DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)" , |
| 89878 | (long) re_ctx->curr_token.t, |
| 89879 | (long) re_ctx->curr_token.num, |
| 89880 | (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ? |
| 89881 | (int) re_ctx->curr_token.num : (int) '?')); |
| 89882 | |
| 89883 | /* set by atom case clauses */ |
| 89884 | new_atom_start_offset = -1; |
| 89885 | new_atom_char_length = -1; |
| 89886 | new_atom_start_captures = re_ctx->captures; |
| 89887 | |
| 89888 | switch (re_ctx->curr_token.t) { |
| 89889 | case DUK_RETOK_DISJUNCTION: { |
| 89890 | /* |
| 89891 | * The handling here is a bit tricky. If a previous '|' has been processed, |
| 89892 | * we have a pending split1 and a pending jump (for a previous match). These |
| 89893 | * need to be back-patched carefully. See docs for a detailed example. |
| 89894 | */ |
| 89895 | |
| 89896 | /* patch pending jump and split */ |
| 89897 | if (unpatched_disjunction_jump >= 0) { |
| 89898 | duk_uint32_t offset; |
| 89899 | |
| 89900 | DUK_ASSERT(unpatched_disjunction_split >= 0); |
| 89901 | offset = (duk_uint32_t) unpatched_disjunction_jump; |
| 89902 | offset += duk__insert_jump_offset(re_ctx, |
| 89903 | offset, |
| 89904 | (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset)); |
| 89905 | /* offset is now target of the pending split (right after jump) */ |
| 89906 | duk__insert_jump_offset(re_ctx, |
| 89907 | (duk_uint32_t) unpatched_disjunction_split, |
| 89908 | (duk_int32_t) offset - unpatched_disjunction_split); |
| 89909 | } |
| 89910 | |
| 89911 | /* add a new pending split to the beginning of the entire disjunction */ |
| 89912 | (void) duk__insert_u32(re_ctx, |
| 89913 | entry_offset, |
| 89914 | DUK_REOP_SPLIT1); /* prefer direct execution */ |
| 89915 | unpatched_disjunction_split = (duk_int32_t) (entry_offset + 1); /* +1 for opcode */ |
| 89916 | |
| 89917 | /* add a new pending match jump for latest finished alternative */ |
| 89918 | duk__append_reop(re_ctx, DUK_REOP_JUMP); |
| 89919 | unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 89920 | |
| 89921 | /* 'taint' result as complex */ |
| 89922 | res_charlen = -1; |
| 89923 | break; |
| 89924 | } |
| 89925 | case DUK_RETOK_QUANTIFIER: { |
| 89926 | if (atom_start_offset < 0) { |
| 89927 | DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM); |
| 89928 | DUK_WO_NORETURN(return;); |
| 89929 | } |
| 89930 | if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) { |
| 89931 | DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES); |
| 89932 | DUK_WO_NORETURN(return;); |
| 89933 | } |
| 89934 | if (atom_char_length >= 0) { |
| 89935 | /* |
| 89936 | * Simple atom |
| 89937 | * |
| 89938 | * If atom_char_length is zero, we'll have unbounded execution time for e.g. |
| 89939 | * /()*x/.exec('x'). We can't just skip the match because it might have some |
| 89940 | * side effects (for instance, if we allowed captures in simple atoms, the |
| 89941 | * capture needs to happen). The simple solution below is to force the |
| 89942 | * quantifier to match at most once, since the additional matches have no effect. |
| 89943 | * |
| 89944 | * With a simple atom there can be no capture groups, so no captures need |
| 89945 | * to be reset. |
| 89946 | */ |
| 89947 | duk_int32_t atom_code_length; |
| 89948 | duk_uint32_t offset; |
| 89949 | duk_uint32_t qmin, qmax; |
| 89950 | |
| 89951 | qmin = re_ctx->curr_token.qmin; |
| 89952 | qmax = re_ctx->curr_token.qmax; |
| 89953 | if (atom_char_length == 0) { |
| 89954 | /* qmin and qmax will be 0 or 1 */ |
| 89955 | if (qmin > 1) { |
| 89956 | qmin = 1; |
| 89957 | } |
| 89958 | if (qmax > 1) { |
| 89959 | qmax = 1; |
| 89960 | } |
| 89961 | } |
| 89962 | |
| 89963 | duk__append_reop(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */ |
| 89964 | atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (duk_size_t) atom_start_offset); |
| 89965 | |
| 89966 | offset = (duk_uint32_t) atom_start_offset; |
| 89967 | if (re_ctx->curr_token.greedy) { |
| 89968 | offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY); |
| 89969 | offset += duk__insert_u32(re_ctx, offset, qmin); |
| 89970 | offset += duk__insert_u32(re_ctx, offset, qmax); |
| 89971 | offset += duk__insert_u32(re_ctx, offset, (duk_uint32_t) atom_char_length); |
| 89972 | offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length); |
| 89973 | } else { |
| 89974 | offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL); |
| 89975 | offset += duk__insert_u32(re_ctx, offset, qmin); |
| 89976 | offset += duk__insert_u32(re_ctx, offset, qmax); |
| 89977 | offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length); |
| 89978 | } |
| 89979 | DUK_UNREF(offset); /* silence scan-build warning */ |
| 89980 | } else { |
| 89981 | /* |
| 89982 | * Complex atom |
| 89983 | * |
| 89984 | * The original code is used as a template, and removed at the end |
| 89985 | * (this differs from the handling of simple quantifiers). |
| 89986 | * |
| 89987 | * NOTE: there is no current solution for empty atoms in complex |
| 89988 | * quantifiers. This would need some sort of a 'progress' instruction. |
| 89989 | * |
| 89990 | * XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies? |
| 89991 | */ |
| 89992 | duk_int32_t atom_code_length; |
| 89993 | duk_uint32_t atom_copies; |
| 89994 | duk_uint32_t tmp_qmin, tmp_qmax; |
| 89995 | |
| 89996 | /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */ |
| 89997 | atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ? |
| 89998 | re_ctx->curr_token.qmin : re_ctx->curr_token.qmax; |
| 89999 | if (atom_copies > DUK_RE_MAX_ATOM_COPIES) { |
| 90000 | DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES); |
| 90001 | DUK_WO_NORETURN(return;); |
| 90002 | } |
| 90003 | |
| 90004 | /* wipe the capture range made by the atom (if any) */ |
| 90005 | DUK_ASSERT(atom_start_captures <= re_ctx->captures); |
| 90006 | if (atom_start_captures != re_ctx->captures) { |
| 90007 | DUK_ASSERT(atom_start_captures < re_ctx->captures); |
| 90008 | DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]" , |
| 90009 | (long) atom_start_captures, (long) re_ctx->captures)); |
| 90010 | |
| 90011 | /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */ |
| 90012 | duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (re_ctx->captures - atom_start_captures) * 2U); |
| 90013 | duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (atom_start_captures + 1) * 2); |
| 90014 | duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, DUK_REOP_WIPERANGE); |
| 90015 | } else { |
| 90016 | DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld" , |
| 90017 | (long) atom_start_captures)); |
| 90018 | } |
| 90019 | |
| 90020 | atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset; |
| 90021 | |
| 90022 | /* insert the required matches (qmin) by copying the atom */ |
| 90023 | tmp_qmin = re_ctx->curr_token.qmin; |
| 90024 | tmp_qmax = re_ctx->curr_token.qmax; |
| 90025 | while (tmp_qmin > 0) { |
| 90026 | duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); |
| 90027 | tmp_qmin--; |
| 90028 | if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) { |
| 90029 | tmp_qmax--; |
| 90030 | } |
| 90031 | } |
| 90032 | DUK_ASSERT(tmp_qmin == 0); |
| 90033 | |
| 90034 | /* insert code for matching the remainder - infinite or finite */ |
| 90035 | if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) { |
| 90036 | /* reuse last emitted atom for remaining 'infinite' quantifier */ |
| 90037 | |
| 90038 | if (re_ctx->curr_token.qmin == 0) { |
| 90039 | /* Special case: original qmin was zero so there is nothing |
| 90040 | * to repeat. Emit an atom copy but jump over it here. |
| 90041 | */ |
| 90042 | duk__append_reop(re_ctx, DUK_REOP_JUMP); |
| 90043 | duk__append_jump_offset(re_ctx, atom_code_length); |
| 90044 | duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); |
| 90045 | } |
| 90046 | if (re_ctx->curr_token.greedy) { |
| 90047 | duk__append_reop(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */ |
| 90048 | } else { |
| 90049 | duk__append_reop(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */ |
| 90050 | } |
| 90051 | duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */ |
| 90052 | } else { |
| 90053 | /* |
| 90054 | * The remaining matches are emitted as sequence of SPLITs and atom |
| 90055 | * copies; the SPLITs skip the remaining copies and match the sequel. |
| 90056 | * This sequence needs to be emitted starting from the last copy |
| 90057 | * because the SPLITs are variable length due to the variable length |
| 90058 | * skip offset. This causes a lot of memory copying now. |
| 90059 | * |
| 90060 | * Example structure (greedy, match maximum # atoms): |
| 90061 | * |
| 90062 | * SPLIT1 LSEQ |
| 90063 | * (atom) |
| 90064 | * SPLIT1 LSEQ ; <- the byte length of this instruction is needed |
| 90065 | * (atom) ; to encode the above SPLIT1 correctly |
| 90066 | * ... |
| 90067 | * LSEQ: |
| 90068 | */ |
| 90069 | duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); |
| 90070 | while (tmp_qmax > 0) { |
| 90071 | duk__insert_slice(re_ctx, offset, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); |
| 90072 | if (re_ctx->curr_token.greedy) { |
| 90073 | duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */ |
| 90074 | } else { |
| 90075 | duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2); /* prefer jump */ |
| 90076 | } |
| 90077 | duk__insert_jump_offset(re_ctx, |
| 90078 | offset + 1, /* +1 for opcode */ |
| 90079 | (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1))); |
| 90080 | tmp_qmax--; |
| 90081 | } |
| 90082 | } |
| 90083 | |
| 90084 | /* remove the original 'template' atom */ |
| 90085 | duk__remove_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length); |
| 90086 | } |
| 90087 | |
| 90088 | /* 'taint' result as complex */ |
| 90089 | res_charlen = -1; |
| 90090 | break; |
| 90091 | } |
| 90092 | case DUK_RETOK_ASSERT_START: { |
| 90093 | duk__append_reop(re_ctx, DUK_REOP_ASSERT_START); |
| 90094 | break; |
| 90095 | } |
| 90096 | case DUK_RETOK_ASSERT_END: { |
| 90097 | duk__append_reop(re_ctx, DUK_REOP_ASSERT_END); |
| 90098 | break; |
| 90099 | } |
| 90100 | case DUK_RETOK_ASSERT_WORD_BOUNDARY: { |
| 90101 | duk__append_reop(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY); |
| 90102 | break; |
| 90103 | } |
| 90104 | case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: { |
| 90105 | duk__append_reop(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY); |
| 90106 | break; |
| 90107 | } |
| 90108 | case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD: |
| 90109 | case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: { |
| 90110 | duk_uint32_t offset; |
| 90111 | duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ? |
| 90112 | DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG; |
| 90113 | |
| 90114 | offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); |
| 90115 | duk__parse_disjunction(re_ctx, 0, &tmp_disj); |
| 90116 | duk__append_reop(re_ctx, DUK_REOP_MATCH); |
| 90117 | |
| 90118 | (void) duk__insert_u32(re_ctx, offset, opcode); |
| 90119 | (void) duk__insert_jump_offset(re_ctx, |
| 90120 | offset + 1, /* +1 for opcode */ |
| 90121 | (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1))); |
| 90122 | |
| 90123 | /* 'taint' result as complex -- this is conservative, |
| 90124 | * as lookaheads do not backtrack. |
| 90125 | */ |
| 90126 | res_charlen = -1; |
| 90127 | break; |
| 90128 | } |
| 90129 | case DUK_RETOK_ATOM_PERIOD: { |
| 90130 | new_atom_char_length = 1; |
| 90131 | new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 90132 | duk__append_reop(re_ctx, DUK_REOP_PERIOD); |
| 90133 | break; |
| 90134 | } |
| 90135 | case DUK_RETOK_ATOM_CHAR: { |
| 90136 | /* Note: successive characters could be joined into string matches |
| 90137 | * but this is not trivial (consider e.g. '/xyz+/); see docs for |
| 90138 | * more discussion. |
| 90139 | * |
| 90140 | * No support for \u{H+} yet. While only BMP Unicode escapes are |
| 90141 | * supported for RegExps at present, 'ch' may still be a non-BMP |
| 90142 | * codepoint if it is decoded straight from source text UTF-8. |
| 90143 | * There's no non-BMP support yet so this is handled simply by |
| 90144 | * matching the non-BMP character (which is custom behavior). |
| 90145 | */ |
| 90146 | duk_uint32_t ch; |
| 90147 | |
| 90148 | new_atom_char_length = 1; |
| 90149 | new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 90150 | duk__append_reop(re_ctx, DUK_REOP_CHAR); |
| 90151 | ch = re_ctx->curr_token.num; |
| 90152 | if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) { |
| 90153 | ch = (duk_uint32_t) duk_unicode_re_canonicalize_char(re_ctx->thr, (duk_codepoint_t) ch); |
| 90154 | } |
| 90155 | duk__append_u32(re_ctx, ch); |
| 90156 | break; |
| 90157 | } |
| 90158 | case DUK_RETOK_ATOM_DIGIT: |
| 90159 | case DUK_RETOK_ATOM_NOT_DIGIT: |
| 90160 | case DUK_RETOK_ATOM_WHITE: |
| 90161 | case DUK_RETOK_ATOM_NOT_WHITE: |
| 90162 | case DUK_RETOK_ATOM_WORD_CHAR: |
| 90163 | case DUK_RETOK_ATOM_NOT_WORD_CHAR: { |
| 90164 | duk_small_uint_t re_op; |
| 90165 | duk_small_uint_t idx; |
| 90166 | |
| 90167 | new_atom_char_length = 1; |
| 90168 | new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 90169 | |
| 90170 | DUK_ASSERT((DUK_RETOK_ATOM_DIGIT & 0x01) != 0); |
| 90171 | DUK_ASSERT((DUK_RETOK_ATOM_WHITE & 0x01) != 0); |
| 90172 | DUK_ASSERT((DUK_RETOK_ATOM_WORD_CHAR & 0x01) != 0); |
| 90173 | DUK_ASSERT((DUK_RETOK_ATOM_NOT_DIGIT & 0x01) == 0); |
| 90174 | DUK_ASSERT((DUK_RETOK_ATOM_NOT_WHITE & 0x01) == 0); |
| 90175 | DUK_ASSERT((DUK_RETOK_ATOM_NOT_WORD_CHAR & 0x01) == 0); |
| 90176 | re_op = (re_ctx->curr_token.t & 0x01) ? DUK_REOP_RANGES : DUK_REOP_INVRANGES; |
| 90177 | |
| 90178 | DUK_ASSERT(DUK_RETOK_ATOM_WHITE == DUK_RETOK_ATOM_DIGIT + 2); |
| 90179 | DUK_ASSERT(DUK_RETOK_ATOM_WORD_CHAR == DUK_RETOK_ATOM_DIGIT + 4); |
| 90180 | idx = (duk_small_uint_t) ((re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1U); |
| 90181 | DUK_ASSERT(idx <= 2U); /* Assume continuous token numbers; also checks negative underflow. */ |
| 90182 | |
| 90183 | duk__append_range_atom_matcher(re_ctx, re_op, duk__re_range_lookup1[idx], duk__re_range_lookup2[idx]); |
| 90184 | break; |
| 90185 | } |
| 90186 | case DUK_RETOK_ATOM_BACKREFERENCE: { |
| 90187 | duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num; |
| 90188 | if (backref > re_ctx->highest_backref) { |
| 90189 | re_ctx->highest_backref = backref; |
| 90190 | } |
| 90191 | new_atom_char_length = -1; /* mark as complex */ |
| 90192 | new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 90193 | duk__append_reop(re_ctx, DUK_REOP_BACKREFERENCE); |
| 90194 | duk__append_u32(re_ctx, backref); |
| 90195 | break; |
| 90196 | } |
| 90197 | case DUK_RETOK_ATOM_START_CAPTURE_GROUP: { |
| 90198 | duk_uint32_t cap; |
| 90199 | |
| 90200 | new_atom_char_length = -1; /* mark as complex (capture handling) */ |
| 90201 | new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 90202 | cap = ++re_ctx->captures; |
| 90203 | duk__append_reop(re_ctx, DUK_REOP_SAVE); |
| 90204 | duk__append_u32(re_ctx, cap * 2); |
| 90205 | duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */ |
| 90206 | duk__append_reop(re_ctx, DUK_REOP_SAVE); |
| 90207 | duk__append_u32(re_ctx, cap * 2 + 1); |
| 90208 | break; |
| 90209 | } |
| 90210 | case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: { |
| 90211 | new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 90212 | duk__parse_disjunction(re_ctx, 0, &tmp_disj); |
| 90213 | new_atom_char_length = tmp_disj.charlen; |
| 90214 | break; |
| 90215 | } |
| 90216 | case DUK_RETOK_ATOM_START_CHARCLASS: |
| 90217 | case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: { |
| 90218 | /* |
| 90219 | * Range parsing is done with a special lexer function which calls |
| 90220 | * us for every range parsed. This is different from how rest of |
| 90221 | * the parsing works, but avoids a heavy, arbitrary size intermediate |
| 90222 | * value type to hold the ranges. |
| 90223 | * |
| 90224 | * Another complication is the handling of character ranges when |
| 90225 | * case insensitive matching is used (see docs for discussion). |
| 90226 | * The range handler callback given to the lexer takes care of this |
| 90227 | * as well. |
| 90228 | * |
| 90229 | * Note that duplicate ranges are not eliminated when parsing character |
| 90230 | * classes, so that canonicalization of |
| 90231 | * |
| 90232 | * [0-9a-fA-Fx-{] |
| 90233 | * |
| 90234 | * creates the result (note the duplicate ranges): |
| 90235 | * |
| 90236 | * [0-9A-FA-FX-Z{-{] |
| 90237 | * |
| 90238 | * where [x-{] is split as a result of canonicalization. The duplicate |
| 90239 | * ranges are not a semantics issue: they work correctly. |
| 90240 | */ |
| 90241 | |
| 90242 | duk_uint32_t offset; |
| 90243 | |
| 90244 | DUK_DD(DUK_DDPRINT("character class" )); |
| 90245 | |
| 90246 | /* insert ranges instruction, range count patched in later */ |
| 90247 | new_atom_char_length = 1; |
| 90248 | new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx); |
| 90249 | duk__append_reop(re_ctx, |
| 90250 | (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ? |
| 90251 | DUK_REOP_RANGES : DUK_REOP_INVRANGES); |
| 90252 | offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */ |
| 90253 | |
| 90254 | /* parse ranges until character class ends */ |
| 90255 | re_ctx->nranges = 0; /* note: ctx-wide temporary */ |
| 90256 | duk_lexer_parse_re_ranges(&re_ctx->lex, duk__regexp_generate_ranges, (void *) re_ctx); |
| 90257 | |
| 90258 | /* insert range count */ |
| 90259 | duk__insert_u32(re_ctx, offset, re_ctx->nranges); |
| 90260 | break; |
| 90261 | } |
| 90262 | case DUK_RETOK_ATOM_END_GROUP: { |
| 90263 | if (expect_eof) { |
| 90264 | DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN); |
| 90265 | DUK_WO_NORETURN(return;); |
| 90266 | } |
| 90267 | goto done; |
| 90268 | } |
| 90269 | case DUK_RETOK_EOF: { |
| 90270 | if (!expect_eof) { |
| 90271 | DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN); |
| 90272 | DUK_WO_NORETURN(return;); |
| 90273 | } |
| 90274 | goto done; |
| 90275 | } |
| 90276 | default: { |
| 90277 | DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN); |
| 90278 | DUK_WO_NORETURN(return;); |
| 90279 | } |
| 90280 | } |
| 90281 | |
| 90282 | /* a complex (new) atom taints the result */ |
| 90283 | if (new_atom_start_offset >= 0) { |
| 90284 | if (new_atom_char_length < 0) { |
| 90285 | res_charlen = -1; |
| 90286 | } else if (res_charlen >= 0) { |
| 90287 | /* only advance if not tainted */ |
| 90288 | res_charlen += new_atom_char_length; |
| 90289 | } |
| 90290 | } |
| 90291 | |
| 90292 | /* record previous atom info in case next token is a quantifier */ |
| 90293 | atom_start_offset = new_atom_start_offset; |
| 90294 | atom_char_length = new_atom_char_length; |
| 90295 | atom_start_captures = new_atom_start_captures; |
| 90296 | } |
| 90297 | |
| 90298 | done: |
| 90299 | |
| 90300 | /* finish up pending jump and split for last alternative */ |
| 90301 | if (unpatched_disjunction_jump >= 0) { |
| 90302 | duk_uint32_t offset; |
| 90303 | |
| 90304 | DUK_ASSERT(unpatched_disjunction_split >= 0); |
| 90305 | offset = (duk_uint32_t) unpatched_disjunction_jump; |
| 90306 | offset += duk__insert_jump_offset(re_ctx, |
| 90307 | offset, |
| 90308 | (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset)); |
| 90309 | /* offset is now target of the pending split (right after jump) */ |
| 90310 | duk__insert_jump_offset(re_ctx, |
| 90311 | (duk_uint32_t) unpatched_disjunction_split, |
| 90312 | (duk_int32_t) offset - unpatched_disjunction_split); |
| 90313 | } |
| 90314 | |
| 90315 | #if 0 |
| 90316 | out_atom_info->end_captures = re_ctx->captures; |
| 90317 | #endif |
| 90318 | out_atom_info->charlen = res_charlen; |
| 90319 | DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld" , |
| 90320 | (long) out_atom_info->charlen)); |
| 90321 | |
| 90322 | re_ctx->recursion_depth--; |
| 90323 | } |
| 90324 | |
| 90325 | /* |
| 90326 | * Flags parsing (see E5 Section 15.10.4.1). |
| 90327 | */ |
| 90328 | |
| 90329 | DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) { |
| 90330 | const duk_uint8_t *p; |
| 90331 | const duk_uint8_t *p_end; |
| 90332 | duk_uint32_t flags = 0; |
| 90333 | |
| 90334 | p = DUK_HSTRING_GET_DATA(h); |
| 90335 | p_end = p + DUK_HSTRING_GET_BYTELEN(h); |
| 90336 | |
| 90337 | /* Note: can be safely scanned as bytes (undecoded) */ |
| 90338 | |
| 90339 | while (p < p_end) { |
| 90340 | duk_uint8_t c = *p++; |
| 90341 | switch (c) { |
| 90342 | case (duk_uint8_t) 'g': { |
| 90343 | if (flags & DUK_RE_FLAG_GLOBAL) { |
| 90344 | goto flags_error; |
| 90345 | } |
| 90346 | flags |= DUK_RE_FLAG_GLOBAL; |
| 90347 | break; |
| 90348 | } |
| 90349 | case (duk_uint8_t) 'i': { |
| 90350 | if (flags & DUK_RE_FLAG_IGNORE_CASE) { |
| 90351 | goto flags_error; |
| 90352 | } |
| 90353 | flags |= DUK_RE_FLAG_IGNORE_CASE; |
| 90354 | break; |
| 90355 | } |
| 90356 | case (duk_uint8_t) 'm': { |
| 90357 | if (flags & DUK_RE_FLAG_MULTILINE) { |
| 90358 | goto flags_error; |
| 90359 | } |
| 90360 | flags |= DUK_RE_FLAG_MULTILINE; |
| 90361 | break; |
| 90362 | } |
| 90363 | default: { |
| 90364 | goto flags_error; |
| 90365 | } |
| 90366 | } |
| 90367 | } |
| 90368 | |
| 90369 | return flags; |
| 90370 | |
| 90371 | flags_error: |
| 90372 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS); |
| 90373 | DUK_WO_NORETURN(return 0U;); |
| 90374 | } |
| 90375 | |
| 90376 | /* |
| 90377 | * Create escaped RegExp source (E5 Section 15.10.3). |
| 90378 | * |
| 90379 | * The current approach is to special case the empty RegExp |
| 90380 | * ('' -> '(?:)') and otherwise replace unescaped '/' characters |
| 90381 | * with '\/' regardless of where they occur in the regexp. |
| 90382 | * |
| 90383 | * Note that normalization does not seem to be necessary for |
| 90384 | * RegExp literals (e.g. '/foo/') because to be acceptable as |
| 90385 | * a RegExp literal, the text between forward slashes must |
| 90386 | * already match the escaping requirements (e.g. must not contain |
| 90387 | * unescaped forward slashes or be empty). Escaping IS needed |
| 90388 | * for expressions like 'new Regexp("...", "")' however. |
| 90389 | * Currently, we re-escape in either case. |
| 90390 | * |
| 90391 | * Also note that we process the source here in UTF-8 encoded |
| 90392 | * form. This is correct, because any non-ASCII characters are |
| 90393 | * passed through without change. |
| 90394 | */ |
| 90395 | |
| 90396 | DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) { |
| 90397 | duk_hstring *h; |
| 90398 | const duk_uint8_t *p; |
| 90399 | duk_bufwriter_ctx bw_alloc; |
| 90400 | duk_bufwriter_ctx *bw; |
| 90401 | duk_uint8_t *q; |
| 90402 | duk_size_t i, n; |
| 90403 | duk_uint_fast8_t c_prev, c; |
| 90404 | |
| 90405 | h = duk_known_hstring(thr, idx_pattern); |
| 90406 | p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); |
| 90407 | n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); |
| 90408 | |
| 90409 | if (n == 0) { |
| 90410 | duk_push_literal(thr, "(?:)" ); |
| 90411 | return; |
| 90412 | } |
| 90413 | |
| 90414 | bw = &bw_alloc; |
| 90415 | DUK_BW_INIT_PUSHBUF(thr, bw, n); |
| 90416 | q = DUK_BW_GET_PTR(thr, bw); |
| 90417 | |
| 90418 | c_prev = (duk_uint_fast8_t) 0; |
| 90419 | |
| 90420 | for (i = 0; i < n; i++) { |
| 90421 | c = p[i]; |
| 90422 | |
| 90423 | q = DUK_BW_ENSURE_RAW(thr, bw, 2, q); |
| 90424 | |
| 90425 | if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') { |
| 90426 | /* Unescaped '/' ANYWHERE in the regexp (in disjunction, |
| 90427 | * inside a character class, ...) => same escape works. |
| 90428 | */ |
| 90429 | *q++ = DUK_ASC_BACKSLASH; |
| 90430 | } |
| 90431 | *q++ = (duk_uint8_t) c; |
| 90432 | |
| 90433 | c_prev = c; |
| 90434 | } |
| 90435 | |
| 90436 | DUK_BW_SETPTR_AND_COMPACT(thr, bw, q); |
| 90437 | (void) duk_buffer_to_string(thr, -1); /* Safe if input is safe. */ |
| 90438 | |
| 90439 | /* [ ... escaped_source ] */ |
| 90440 | } |
| 90441 | |
| 90442 | /* |
| 90443 | * Exposed regexp compilation primitive. |
| 90444 | * |
| 90445 | * Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the |
| 90446 | * actual parsing. Handles generation of the compiled regexp header and the |
| 90447 | * "boilerplate" capture of the matching substring (save 0 and 1). Also does some |
| 90448 | * global level regexp checks after recursive compilation has finished. |
| 90449 | * |
| 90450 | * An escaped version of the regexp source, suitable for use as a RegExp instance |
| 90451 | * 'source' property (see E5 Section 15.10.3), is also left on the stack. |
| 90452 | * |
| 90453 | * Input stack: [ pattern flags ] |
| 90454 | * Output stack: [ bytecode escaped_source ] (both as strings) |
| 90455 | */ |
| 90456 | |
| 90457 | DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) { |
| 90458 | duk_re_compiler_ctx re_ctx; |
| 90459 | duk_lexer_point lex_point; |
| 90460 | duk_hstring *h_pattern; |
| 90461 | duk_hstring *h_flags; |
| 90462 | duk__re_disjunction_info ign_disj; |
| 90463 | |
| 90464 | DUK_ASSERT(thr != NULL); |
| 90465 | |
| 90466 | /* |
| 90467 | * Args validation |
| 90468 | */ |
| 90469 | |
| 90470 | /* TypeError if fails */ |
| 90471 | h_pattern = duk_require_hstring_notsymbol(thr, -2); |
| 90472 | h_flags = duk_require_hstring_notsymbol(thr, -1); |
| 90473 | |
| 90474 | /* |
| 90475 | * Create normalized 'source' property (E5 Section 15.10.3). |
| 90476 | */ |
| 90477 | |
| 90478 | /* [ ... pattern flags ] */ |
| 90479 | |
| 90480 | duk__create_escaped_source(thr, -2); |
| 90481 | |
| 90482 | /* [ ... pattern flags escaped_source ] */ |
| 90483 | |
| 90484 | /* |
| 90485 | * Init compilation context |
| 90486 | */ |
| 90487 | |
| 90488 | /* [ ... pattern flags escaped_source buffer ] */ |
| 90489 | |
| 90490 | duk_memzero(&re_ctx, sizeof(re_ctx)); |
| 90491 | DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */ |
| 90492 | re_ctx.thr = thr; |
| 90493 | re_ctx.lex.thr = thr; |
| 90494 | re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern); |
| 90495 | re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern); |
| 90496 | re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT; |
| 90497 | re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT; |
| 90498 | re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags); |
| 90499 | |
| 90500 | DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE); |
| 90501 | |
| 90502 | DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld" , |
| 90503 | (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit)); |
| 90504 | |
| 90505 | /* |
| 90506 | * Init lexer |
| 90507 | */ |
| 90508 | |
| 90509 | lex_point.offset = 0; /* expensive init, just want to fill window */ |
| 90510 | lex_point.line = 1; |
| 90511 | DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point); |
| 90512 | |
| 90513 | /* |
| 90514 | * Compilation |
| 90515 | */ |
| 90516 | |
| 90517 | DUK_DD(DUK_DDPRINT("starting regexp compilation" )); |
| 90518 | |
| 90519 | duk__append_reop(&re_ctx, DUK_REOP_SAVE); |
| 90520 | duk__append_7bit(&re_ctx, 0); |
| 90521 | duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj); |
| 90522 | duk__append_reop(&re_ctx, DUK_REOP_SAVE); |
| 90523 | duk__append_7bit(&re_ctx, 1); |
| 90524 | duk__append_reop(&re_ctx, DUK_REOP_MATCH); |
| 90525 | |
| 90526 | /* |
| 90527 | * Check for invalid backreferences; note that it is NOT an error |
| 90528 | * to back-reference a capture group which has not yet been introduced |
| 90529 | * in the pattern (as in /\1(foo)/); in fact, the backreference will |
| 90530 | * always match! It IS an error to back-reference a capture group |
| 90531 | * which will never be introduced in the pattern. Thus, we can check |
| 90532 | * for such references only after parsing is complete. |
| 90533 | */ |
| 90534 | |
| 90535 | if (re_ctx.highest_backref > re_ctx.captures) { |
| 90536 | DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS); |
| 90537 | DUK_WO_NORETURN(return;); |
| 90538 | } |
| 90539 | |
| 90540 | /* |
| 90541 | * Emit compiled regexp header: flags, ncaptures |
| 90542 | * (insertion order inverted on purpose) |
| 90543 | */ |
| 90544 | |
| 90545 | duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2); |
| 90546 | duk__insert_u32(&re_ctx, 0, re_ctx.re_flags); |
| 90547 | |
| 90548 | /* [ ... pattern flags escaped_source buffer ] */ |
| 90549 | |
| 90550 | DUK_BW_COMPACT(thr, &re_ctx.bw); |
| 90551 | (void) duk_buffer_to_string(thr, -1); /* Safe because flags is at most 7 bit. */ |
| 90552 | |
| 90553 | /* [ ... pattern flags escaped_source bytecode ] */ |
| 90554 | |
| 90555 | /* |
| 90556 | * Finalize stack |
| 90557 | */ |
| 90558 | |
| 90559 | duk_remove(thr, -4); /* -> [ ... flags escaped_source bytecode ] */ |
| 90560 | duk_remove(thr, -3); /* -> [ ... escaped_source bytecode ] */ |
| 90561 | |
| 90562 | DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T" , |
| 90563 | (duk_tval *) duk_get_tval(thr, -1), (duk_tval *) duk_get_tval(thr, -2))); |
| 90564 | } |
| 90565 | |
| 90566 | /* |
| 90567 | * Create a RegExp instance (E5 Section 15.10.7). |
| 90568 | * |
| 90569 | * Note: the output stack left by duk_regexp_compile() is directly compatible |
| 90570 | * with the input here. |
| 90571 | * |
| 90572 | * Input stack: [ escaped_source bytecode ] (both as strings) |
| 90573 | * Output stack: [ RegExp ] |
| 90574 | */ |
| 90575 | |
| 90576 | DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) { |
| 90577 | duk_hobject *h; |
| 90578 | |
| 90579 | /* [ ... escaped_source bytecode ] */ |
| 90580 | |
| 90581 | duk_push_object(thr); |
| 90582 | h = duk_known_hobject(thr, -1); |
| 90583 | duk_insert(thr, -3); |
| 90584 | |
| 90585 | /* [ ... regexp_object escaped_source bytecode ] */ |
| 90586 | |
| 90587 | DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP); |
| 90588 | DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]); |
| 90589 | |
| 90590 | duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE); |
| 90591 | |
| 90592 | /* [ ... regexp_object escaped_source ] */ |
| 90593 | |
| 90594 | /* In ES2015 .source, and the .global, .multiline, etc flags are |
| 90595 | * inherited getters. Store the escaped source as an internal |
| 90596 | * property for the getter. |
| 90597 | */ |
| 90598 | |
| 90599 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE); |
| 90600 | |
| 90601 | /* [ ... regexp_object ] */ |
| 90602 | |
| 90603 | duk_push_int(thr, 0); |
| 90604 | duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W); |
| 90605 | |
| 90606 | /* [ ... regexp_object ] */ |
| 90607 | } |
| 90608 | |
| 90609 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 90610 | |
| 90611 | /* regexp support disabled */ |
| 90612 | |
| 90613 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 90614 | |
| 90615 | /* automatic undefs */ |
| 90616 | #undef DUK__RE_BUFLEN |
| 90617 | #undef DUK__RE_INITIAL_BUFSIZE |
| 90618 | #line 1 "duk_regexp_executor.c" |
| 90619 | /* |
| 90620 | * Regexp executor. |
| 90621 | * |
| 90622 | * Safety: the ECMAScript executor should prevent user from reading and |
| 90623 | * replacing regexp bytecode. Even so, the executor must validate all |
| 90624 | * memory accesses etc. When an invalid access is detected (e.g. a 'save' |
| 90625 | * opcode to invalid, unallocated index) it should fail with an internal |
| 90626 | * error but not cause a segmentation fault. |
| 90627 | * |
| 90628 | * Notes: |
| 90629 | * |
| 90630 | * - Backtrack counts are limited to unsigned 32 bits but should |
| 90631 | * technically be duk_size_t for strings longer than 4G chars. |
| 90632 | * This also requires a regexp bytecode change. |
| 90633 | */ |
| 90634 | |
| 90635 | /* #include duk_internal.h -> already included */ |
| 90636 | |
| 90637 | #if defined(DUK_USE_REGEXP_SUPPORT) |
| 90638 | |
| 90639 | /* |
| 90640 | * Helpers for UTF-8 handling |
| 90641 | * |
| 90642 | * For bytecode readers the duk_uint32_t and duk_int32_t types are correct |
| 90643 | * because they're used for more than just codepoints. |
| 90644 | */ |
| 90645 | |
| 90646 | DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) { |
| 90647 | return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end); |
| 90648 | } |
| 90649 | |
| 90650 | DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) { |
| 90651 | duk_uint32_t t; |
| 90652 | |
| 90653 | /* signed integer encoding needed to work with UTF-8 */ |
| 90654 | t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end); |
| 90655 | if (t & 1) { |
| 90656 | return -((duk_int32_t) (t >> 1)); |
| 90657 | } else { |
| 90658 | return (duk_int32_t) (t >> 1); |
| 90659 | } |
| 90660 | } |
| 90661 | |
| 90662 | DUK_LOCAL const duk_uint8_t *duk__utf8_backtrack(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) { |
| 90663 | const duk_uint8_t *p; |
| 90664 | |
| 90665 | /* Note: allow backtracking from p == ptr_end */ |
| 90666 | p = *ptr; |
| 90667 | if (p < ptr_start || p > ptr_end) { |
| 90668 | goto fail; |
| 90669 | } |
| 90670 | |
| 90671 | while (count > 0) { |
| 90672 | for (;;) { |
| 90673 | p--; |
| 90674 | if (p < ptr_start) { |
| 90675 | goto fail; |
| 90676 | } |
| 90677 | if ((*p & 0xc0) != 0x80) { |
| 90678 | /* utf-8 continuation bytes have the form 10xx xxxx */ |
| 90679 | break; |
| 90680 | } |
| 90681 | } |
| 90682 | count--; |
| 90683 | } |
| 90684 | *ptr = p; |
| 90685 | return p; |
| 90686 | |
| 90687 | fail: |
| 90688 | DUK_ERROR_INTERNAL(thr); |
| 90689 | DUK_WO_NORETURN(return NULL;); |
| 90690 | } |
| 90691 | |
| 90692 | DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) { |
| 90693 | const duk_uint8_t *p; |
| 90694 | |
| 90695 | p = *ptr; |
| 90696 | if (p < ptr_start || p >= ptr_end) { |
| 90697 | goto fail; |
| 90698 | } |
| 90699 | |
| 90700 | while (count > 0) { |
| 90701 | for (;;) { |
| 90702 | p++; |
| 90703 | |
| 90704 | /* Note: if encoding ends by hitting end of input, we don't check that |
| 90705 | * the encoding is valid, we just assume it is. |
| 90706 | */ |
| 90707 | if (p >= ptr_end || ((*p & 0xc0) != 0x80)) { |
| 90708 | /* utf-8 continuation bytes have the form 10xx xxxx */ |
| 90709 | break; |
| 90710 | } |
| 90711 | } |
| 90712 | count--; |
| 90713 | } |
| 90714 | |
| 90715 | *ptr = p; |
| 90716 | return p; |
| 90717 | |
| 90718 | fail: |
| 90719 | DUK_ERROR_INTERNAL(thr); |
| 90720 | DUK_WO_NORETURN(return NULL;); |
| 90721 | } |
| 90722 | |
| 90723 | /* |
| 90724 | * Helpers for dealing with the input string |
| 90725 | */ |
| 90726 | |
| 90727 | /* Get a (possibly canonicalized) input character from current sp. The input |
| 90728 | * itself is never modified, and captures always record non-canonicalized |
| 90729 | * characters even in case-insensitive matching. Return <0 if out of input. |
| 90730 | */ |
| 90731 | DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) { |
| 90732 | duk_codepoint_t res; |
| 90733 | |
| 90734 | if (*sp >= re_ctx->input_end) { |
| 90735 | return -1; |
| 90736 | } |
| 90737 | res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end); |
| 90738 | if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) { |
| 90739 | res = duk_unicode_re_canonicalize_char(re_ctx->thr, res); |
| 90740 | } |
| 90741 | return res; |
| 90742 | } |
| 90743 | |
| 90744 | DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) { |
| 90745 | return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count); |
| 90746 | } |
| 90747 | |
| 90748 | /* Backtrack utf-8 input and return a (possibly canonicalized) input character. */ |
| 90749 | DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) { |
| 90750 | /* note: caller 'sp' is intentionally not updated here */ |
| 90751 | (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1); |
| 90752 | return duk__inp_get_cp(re_ctx, &sp); |
| 90753 | } |
| 90754 | |
| 90755 | /* |
| 90756 | * Regexp recursive matching function. |
| 90757 | * |
| 90758 | * Returns 'sp' on successful match (points to character after last matched one), |
| 90759 | * NULL otherwise. |
| 90760 | * |
| 90761 | * The C recursion depth limit check is only performed in this function, this |
| 90762 | * suffices because the function is present in all true recursion required by |
| 90763 | * regexp execution. |
| 90764 | */ |
| 90765 | |
| 90766 | DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) { |
| 90767 | duk_native_stack_check(re_ctx->thr); |
| 90768 | if (re_ctx->recursion_depth >= re_ctx->recursion_limit) { |
| 90769 | DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT); |
| 90770 | DUK_WO_NORETURN(return NULL;); |
| 90771 | } |
| 90772 | re_ctx->recursion_depth++; |
| 90773 | |
| 90774 | for (;;) { |
| 90775 | duk_small_int_t op; |
| 90776 | |
| 90777 | if (re_ctx->steps_count >= re_ctx->steps_limit) { |
| 90778 | DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT); |
| 90779 | DUK_WO_NORETURN(return NULL;); |
| 90780 | } |
| 90781 | re_ctx->steps_count++; |
| 90782 | |
| 90783 | /* Opcodes are at most 7 bits now so they encode to one byte. If this |
| 90784 | * were not the case or 'pc' is invalid here (due to a bug etc) we'll |
| 90785 | * still fail safely through the switch default case. |
| 90786 | */ |
| 90787 | DUK_ASSERT(pc[0] <= 0x7fU); |
| 90788 | #if 0 |
| 90789 | op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc); |
| 90790 | #endif |
| 90791 | op = *pc++; |
| 90792 | |
| 90793 | DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld" , |
| 90794 | (long) re_ctx->recursion_depth, |
| 90795 | (long) re_ctx->steps_count, |
| 90796 | (long) (pc - re_ctx->bytecode), |
| 90797 | (long) (sp - re_ctx->input), |
| 90798 | (long) op)); |
| 90799 | |
| 90800 | switch (op) { |
| 90801 | case DUK_REOP_MATCH: { |
| 90802 | goto match; |
| 90803 | } |
| 90804 | case DUK_REOP_CHAR: { |
| 90805 | /* |
| 90806 | * Byte-based matching would be possible for case-sensitive |
| 90807 | * matching but not for case-insensitive matching. So, we |
| 90808 | * match by decoding the input and bytecode character normally. |
| 90809 | * |
| 90810 | * Bytecode characters are assumed to be already canonicalized. |
| 90811 | * Input characters are canonicalized automatically by |
| 90812 | * duk__inp_get_cp() if necessary. |
| 90813 | * |
| 90814 | * There is no opcode for matching multiple characters. The |
| 90815 | * regexp compiler has trouble joining strings efficiently |
| 90816 | * during compilation. See doc/regexp.rst for more discussion. |
| 90817 | */ |
| 90818 | duk_codepoint_t c1, c2; |
| 90819 | |
| 90820 | c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc); |
| 90821 | DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) || |
| 90822 | c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */ |
| 90823 | c2 = duk__inp_get_cp(re_ctx, &sp); |
| 90824 | /* No need to check for c2 < 0 (end of input): because c1 >= 0, it |
| 90825 | * will fail the match below automatically and cause goto fail. |
| 90826 | */ |
| 90827 | #if 0 |
| 90828 | if (c2 < 0) { |
| 90829 | goto fail; |
| 90830 | } |
| 90831 | #endif |
| 90832 | DUK_ASSERT(c1 >= 0); |
| 90833 | |
| 90834 | DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld" , (long) c1, (long) c2)); |
| 90835 | if (c1 != c2) { |
| 90836 | goto fail; |
| 90837 | } |
| 90838 | break; |
| 90839 | } |
| 90840 | case DUK_REOP_PERIOD: { |
| 90841 | duk_codepoint_t c; |
| 90842 | |
| 90843 | c = duk__inp_get_cp(re_ctx, &sp); |
| 90844 | if (c < 0 || duk_unicode_is_line_terminator(c)) { |
| 90845 | /* E5 Sections 15.10.2.8, 7.3 */ |
| 90846 | goto fail; |
| 90847 | } |
| 90848 | break; |
| 90849 | } |
| 90850 | case DUK_REOP_RANGES: |
| 90851 | case DUK_REOP_INVRANGES: { |
| 90852 | duk_uint32_t n; |
| 90853 | duk_codepoint_t c; |
| 90854 | duk_small_int_t match; |
| 90855 | |
| 90856 | n = duk__bc_get_u32(re_ctx, &pc); |
| 90857 | c = duk__inp_get_cp(re_ctx, &sp); |
| 90858 | if (c < 0) { |
| 90859 | goto fail; |
| 90860 | } |
| 90861 | |
| 90862 | match = 0; |
| 90863 | while (n) { |
| 90864 | duk_codepoint_t r1, r2; |
| 90865 | r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc); |
| 90866 | r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc); |
| 90867 | DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld" , |
| 90868 | (long) n, (long) r1, (long) r2, (long) c)); |
| 90869 | if (c >= r1 && c <= r2) { |
| 90870 | /* Note: don't bail out early, we must read all the ranges from |
| 90871 | * bytecode. Another option is to skip them efficiently after |
| 90872 | * breaking out of here. Prefer smallest code. |
| 90873 | */ |
| 90874 | match = 1; |
| 90875 | } |
| 90876 | n--; |
| 90877 | } |
| 90878 | |
| 90879 | if (op == DUK_REOP_RANGES) { |
| 90880 | if (!match) { |
| 90881 | goto fail; |
| 90882 | } |
| 90883 | } else { |
| 90884 | DUK_ASSERT(op == DUK_REOP_INVRANGES); |
| 90885 | if (match) { |
| 90886 | goto fail; |
| 90887 | } |
| 90888 | } |
| 90889 | break; |
| 90890 | } |
| 90891 | case DUK_REOP_ASSERT_START: { |
| 90892 | duk_codepoint_t c; |
| 90893 | |
| 90894 | if (sp <= re_ctx->input) { |
| 90895 | break; |
| 90896 | } |
| 90897 | if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) { |
| 90898 | goto fail; |
| 90899 | } |
| 90900 | c = duk__inp_get_prev_cp(re_ctx, sp); |
| 90901 | if (duk_unicode_is_line_terminator(c)) { |
| 90902 | /* E5 Sections 15.10.2.8, 7.3 */ |
| 90903 | break; |
| 90904 | } |
| 90905 | goto fail; |
| 90906 | } |
| 90907 | case DUK_REOP_ASSERT_END: { |
| 90908 | duk_codepoint_t c; |
| 90909 | const duk_uint8_t *tmp_sp; |
| 90910 | |
| 90911 | tmp_sp = sp; |
| 90912 | c = duk__inp_get_cp(re_ctx, &tmp_sp); |
| 90913 | if (c < 0) { |
| 90914 | break; |
| 90915 | } |
| 90916 | if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) { |
| 90917 | goto fail; |
| 90918 | } |
| 90919 | if (duk_unicode_is_line_terminator(c)) { |
| 90920 | /* E5 Sections 15.10.2.8, 7.3 */ |
| 90921 | break; |
| 90922 | } |
| 90923 | goto fail; |
| 90924 | } |
| 90925 | case DUK_REOP_ASSERT_WORD_BOUNDARY: |
| 90926 | case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: { |
| 90927 | /* |
| 90928 | * E5 Section 15.10.2.6. The previous and current character |
| 90929 | * should -not- be canonicalized as they are now. However, |
| 90930 | * canonicalization does not affect the result of IsWordChar() |
| 90931 | * (which depends on Unicode characters never canonicalizing |
| 90932 | * into ASCII characters) so this does not matter. |
| 90933 | */ |
| 90934 | duk_small_int_t w1, w2; |
| 90935 | |
| 90936 | if (sp <= re_ctx->input) { |
| 90937 | w1 = 0; /* not a wordchar */ |
| 90938 | } else { |
| 90939 | duk_codepoint_t c; |
| 90940 | c = duk__inp_get_prev_cp(re_ctx, sp); |
| 90941 | w1 = duk_unicode_re_is_wordchar(c); |
| 90942 | } |
| 90943 | if (sp >= re_ctx->input_end) { |
| 90944 | w2 = 0; /* not a wordchar */ |
| 90945 | } else { |
| 90946 | const duk_uint8_t *tmp_sp = sp; /* dummy so sp won't get updated */ |
| 90947 | duk_codepoint_t c; |
| 90948 | c = duk__inp_get_cp(re_ctx, &tmp_sp); |
| 90949 | w2 = duk_unicode_re_is_wordchar(c); |
| 90950 | } |
| 90951 | |
| 90952 | if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) { |
| 90953 | if (w1 == w2) { |
| 90954 | goto fail; |
| 90955 | } |
| 90956 | } else { |
| 90957 | DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY); |
| 90958 | if (w1 != w2) { |
| 90959 | goto fail; |
| 90960 | } |
| 90961 | } |
| 90962 | break; |
| 90963 | } |
| 90964 | case DUK_REOP_JUMP: { |
| 90965 | duk_int32_t skip; |
| 90966 | |
| 90967 | skip = duk__bc_get_i32(re_ctx, &pc); |
| 90968 | pc += skip; |
| 90969 | break; |
| 90970 | } |
| 90971 | case DUK_REOP_SPLIT1: { |
| 90972 | /* split1: prefer direct execution (no jump) */ |
| 90973 | const duk_uint8_t *sub_sp; |
| 90974 | duk_int32_t skip; |
| 90975 | |
| 90976 | skip = duk__bc_get_i32(re_ctx, &pc); |
| 90977 | sub_sp = duk__match_regexp(re_ctx, pc, sp); |
| 90978 | if (sub_sp) { |
| 90979 | sp = sub_sp; |
| 90980 | goto match; |
| 90981 | } |
| 90982 | pc += skip; |
| 90983 | break; |
| 90984 | } |
| 90985 | case DUK_REOP_SPLIT2: { |
| 90986 | /* split2: prefer jump execution (not direct) */ |
| 90987 | const duk_uint8_t *sub_sp; |
| 90988 | duk_int32_t skip; |
| 90989 | |
| 90990 | skip = duk__bc_get_i32(re_ctx, &pc); |
| 90991 | sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); |
| 90992 | if (sub_sp) { |
| 90993 | sp = sub_sp; |
| 90994 | goto match; |
| 90995 | } |
| 90996 | break; |
| 90997 | } |
| 90998 | case DUK_REOP_SQMINIMAL: { |
| 90999 | duk_uint32_t q, qmin, qmax; |
| 91000 | duk_int32_t skip; |
| 91001 | const duk_uint8_t *sub_sp; |
| 91002 | |
| 91003 | qmin = duk__bc_get_u32(re_ctx, &pc); |
| 91004 | qmax = duk__bc_get_u32(re_ctx, &pc); |
| 91005 | skip = duk__bc_get_i32(re_ctx, &pc); |
| 91006 | DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld" , |
| 91007 | (unsigned long) qmin, (unsigned long) qmax, (long) skip)); |
| 91008 | |
| 91009 | q = 0; |
| 91010 | while (q <= qmax) { |
| 91011 | if (q >= qmin) { |
| 91012 | sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); |
| 91013 | if (sub_sp) { |
| 91014 | sp = sub_sp; |
| 91015 | goto match; |
| 91016 | } |
| 91017 | } |
| 91018 | sub_sp = duk__match_regexp(re_ctx, pc, sp); |
| 91019 | if (!sub_sp) { |
| 91020 | break; |
| 91021 | } |
| 91022 | sp = sub_sp; |
| 91023 | q++; |
| 91024 | } |
| 91025 | goto fail; |
| 91026 | } |
| 91027 | case DUK_REOP_SQGREEDY: { |
| 91028 | duk_uint32_t q, qmin, qmax, atomlen; |
| 91029 | duk_int32_t skip; |
| 91030 | const duk_uint8_t *sub_sp; |
| 91031 | |
| 91032 | qmin = duk__bc_get_u32(re_ctx, &pc); |
| 91033 | qmax = duk__bc_get_u32(re_ctx, &pc); |
| 91034 | atomlen = duk__bc_get_u32(re_ctx, &pc); |
| 91035 | skip = duk__bc_get_i32(re_ctx, &pc); |
| 91036 | DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld" , |
| 91037 | (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip)); |
| 91038 | |
| 91039 | q = 0; |
| 91040 | while (q < qmax) { |
| 91041 | sub_sp = duk__match_regexp(re_ctx, pc, sp); |
| 91042 | if (!sub_sp) { |
| 91043 | break; |
| 91044 | } |
| 91045 | sp = sub_sp; |
| 91046 | q++; |
| 91047 | } |
| 91048 | while (q >= qmin) { |
| 91049 | sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); |
| 91050 | if (sub_sp) { |
| 91051 | sp = sub_sp; |
| 91052 | goto match; |
| 91053 | } |
| 91054 | if (q == qmin) { |
| 91055 | break; |
| 91056 | } |
| 91057 | |
| 91058 | /* Note: if atom were to contain e.g. captures, we would need to |
| 91059 | * re-match the atom to get correct captures. Simply quantifiers |
| 91060 | * do not allow captures in their atom now, so this is not an issue. |
| 91061 | */ |
| 91062 | |
| 91063 | DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)" , |
| 91064 | (long) atomlen)); |
| 91065 | sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen); |
| 91066 | q--; |
| 91067 | } |
| 91068 | goto fail; |
| 91069 | } |
| 91070 | case DUK_REOP_SAVE: { |
| 91071 | duk_uint32_t idx; |
| 91072 | const duk_uint8_t *old; |
| 91073 | const duk_uint8_t *sub_sp; |
| 91074 | |
| 91075 | idx = duk__bc_get_u32(re_ctx, &pc); |
| 91076 | if (idx >= re_ctx->nsaved) { |
| 91077 | /* idx is unsigned, < 0 check is not necessary */ |
| 91078 | DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld" , (long) idx)); |
| 91079 | goto internal_error; |
| 91080 | } |
| 91081 | old = re_ctx->saved[idx]; |
| 91082 | re_ctx->saved[idx] = sp; |
| 91083 | sub_sp = duk__match_regexp(re_ctx, pc, sp); |
| 91084 | if (sub_sp) { |
| 91085 | sp = sub_sp; |
| 91086 | goto match; |
| 91087 | } |
| 91088 | re_ctx->saved[idx] = old; |
| 91089 | goto fail; |
| 91090 | } |
| 91091 | case DUK_REOP_WIPERANGE: { |
| 91092 | /* Wipe capture range and save old values for backtracking. |
| 91093 | * |
| 91094 | * XXX: this typically happens with a relatively small idx_count. |
| 91095 | * It might be useful to handle cases where the count is small |
| 91096 | * (say <= 8) by saving the values in stack instead. This would |
| 91097 | * reduce memory churn and improve performance, at the cost of a |
| 91098 | * slightly higher code footprint. |
| 91099 | */ |
| 91100 | duk_uint32_t idx_start, idx_count; |
| 91101 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 91102 | duk_uint32_t idx_end, idx; |
| 91103 | #endif |
| 91104 | duk_uint8_t **range_save; |
| 91105 | const duk_uint8_t *sub_sp; |
| 91106 | |
| 91107 | idx_start = duk__bc_get_u32(re_ctx, &pc); |
| 91108 | idx_count = duk__bc_get_u32(re_ctx, &pc); |
| 91109 | DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])" , |
| 91110 | (long) idx_start, (long) idx_count, |
| 91111 | (long) idx_start, (long) (idx_start + idx_count - 1), |
| 91112 | (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2))); |
| 91113 | if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) { |
| 91114 | /* idx is unsigned, < 0 check is not necessary */ |
| 91115 | DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld" , |
| 91116 | (long) idx_start, (long) idx_count)); |
| 91117 | goto internal_error; |
| 91118 | } |
| 91119 | DUK_ASSERT(idx_count > 0); |
| 91120 | |
| 91121 | duk_require_stack(re_ctx->thr, 1); |
| 91122 | range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr, |
| 91123 | sizeof(duk_uint8_t *) * idx_count); |
| 91124 | DUK_ASSERT(range_save != NULL); |
| 91125 | duk_memcpy(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count); |
| 91126 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 91127 | idx_end = idx_start + idx_count; |
| 91128 | for (idx = idx_start; idx < idx_end; idx++) { |
| 91129 | re_ctx->saved[idx] = NULL; |
| 91130 | } |
| 91131 | #else |
| 91132 | duk_memzero((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count); |
| 91133 | #endif |
| 91134 | |
| 91135 | sub_sp = duk__match_regexp(re_ctx, pc, sp); |
| 91136 | if (sub_sp) { |
| 91137 | /* match: keep wiped/resaved values */ |
| 91138 | DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])" , |
| 91139 | (long) idx_start, (long) (idx_start + idx_count - 1), |
| 91140 | (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2))); |
| 91141 | duk_pop_unsafe(re_ctx->thr); |
| 91142 | sp = sub_sp; |
| 91143 | goto match; |
| 91144 | } |
| 91145 | |
| 91146 | /* fail: restore saves */ |
| 91147 | DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])" , |
| 91148 | (long) idx_start, (long) (idx_start + idx_count - 1), |
| 91149 | (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2))); |
| 91150 | duk_memcpy((void *) (re_ctx->saved + idx_start), |
| 91151 | (const void *) range_save, |
| 91152 | sizeof(duk_uint8_t *) * idx_count); |
| 91153 | duk_pop_unsafe(re_ctx->thr); |
| 91154 | goto fail; |
| 91155 | } |
| 91156 | case DUK_REOP_LOOKPOS: |
| 91157 | case DUK_REOP_LOOKNEG: { |
| 91158 | /* |
| 91159 | * Needs a save of multiple saved[] entries depending on what range |
| 91160 | * may be overwritten. Because the regexp parser does no such analysis, |
| 91161 | * we currently save the entire saved array here. Lookaheads are thus |
| 91162 | * a bit expensive. Note that the saved array is not needed for just |
| 91163 | * the lookahead sub-match, but for the matching of the entire sequel. |
| 91164 | * |
| 91165 | * The temporary save buffer is pushed on to the valstack to handle |
| 91166 | * errors correctly. Each lookahead causes a C recursion and pushes |
| 91167 | * more stuff on the value stack. If the C recursion limit is less |
| 91168 | * than the value stack slack, there is no need to check the stack. |
| 91169 | * We do so regardless, just in case. |
| 91170 | */ |
| 91171 | |
| 91172 | duk_int32_t skip; |
| 91173 | duk_uint8_t **full_save; |
| 91174 | const duk_uint8_t *sub_sp; |
| 91175 | |
| 91176 | DUK_ASSERT(re_ctx->nsaved > 0); |
| 91177 | |
| 91178 | duk_require_stack(re_ctx->thr, 1); |
| 91179 | full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr, |
| 91180 | sizeof(duk_uint8_t *) * re_ctx->nsaved); |
| 91181 | DUK_ASSERT(full_save != NULL); |
| 91182 | duk_memcpy(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved); |
| 91183 | |
| 91184 | skip = duk__bc_get_i32(re_ctx, &pc); |
| 91185 | sub_sp = duk__match_regexp(re_ctx, pc, sp); |
| 91186 | if (op == DUK_REOP_LOOKPOS) { |
| 91187 | if (!sub_sp) { |
| 91188 | goto lookahead_fail; |
| 91189 | } |
| 91190 | } else { |
| 91191 | if (sub_sp) { |
| 91192 | goto lookahead_fail; |
| 91193 | } |
| 91194 | } |
| 91195 | sub_sp = duk__match_regexp(re_ctx, pc + skip, sp); |
| 91196 | if (sub_sp) { |
| 91197 | /* match: keep saves */ |
| 91198 | duk_pop_unsafe(re_ctx->thr); |
| 91199 | sp = sub_sp; |
| 91200 | goto match; |
| 91201 | } |
| 91202 | |
| 91203 | /* fall through */ |
| 91204 | |
| 91205 | lookahead_fail: |
| 91206 | /* fail: restore saves */ |
| 91207 | duk_memcpy((void *) re_ctx->saved, |
| 91208 | (const void *) full_save, |
| 91209 | sizeof(duk_uint8_t *) * re_ctx->nsaved); |
| 91210 | duk_pop_unsafe(re_ctx->thr); |
| 91211 | goto fail; |
| 91212 | } |
| 91213 | case DUK_REOP_BACKREFERENCE: { |
| 91214 | /* |
| 91215 | * Byte matching for back-references would be OK in case- |
| 91216 | * sensitive matching. In case-insensitive matching we need |
| 91217 | * to canonicalize characters, so back-reference matching needs |
| 91218 | * to be done with codepoints instead. So, we just decode |
| 91219 | * everything normally here, too. |
| 91220 | * |
| 91221 | * Note: back-reference index which is 0 or higher than |
| 91222 | * NCapturingParens (= number of capturing parens in the |
| 91223 | * -entire- regexp) is a compile time error. However, a |
| 91224 | * backreference referring to a valid capture which has |
| 91225 | * not matched anything always succeeds! See E5 Section |
| 91226 | * 15.10.2.9, step 5, sub-step 3. |
| 91227 | */ |
| 91228 | duk_uint32_t idx; |
| 91229 | const duk_uint8_t *p; |
| 91230 | |
| 91231 | idx = duk__bc_get_u32(re_ctx, &pc); |
| 91232 | idx = idx << 1; /* backref n -> saved indices [n*2, n*2+1] */ |
| 91233 | if (idx < 2 || idx + 1 >= re_ctx->nsaved) { |
| 91234 | /* regexp compiler should catch these */ |
| 91235 | DUK_D(DUK_DPRINT("internal error, backreference index insane" )); |
| 91236 | goto internal_error; |
| 91237 | } |
| 91238 | if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) { |
| 91239 | /* capture is 'undefined', always matches! */ |
| 91240 | DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match" , |
| 91241 | (long) idx, (long) (idx + 1))); |
| 91242 | break; |
| 91243 | } |
| 91244 | DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]" , (long) idx, (long) (idx + 1))); |
| 91245 | |
| 91246 | p = re_ctx->saved[idx]; |
| 91247 | while (p < re_ctx->saved[idx+1]) { |
| 91248 | duk_codepoint_t c1, c2; |
| 91249 | |
| 91250 | /* Note: not necessary to check p against re_ctx->input_end: |
| 91251 | * the memory access is checked by duk__inp_get_cp(), while |
| 91252 | * valid compiled regexps cannot write a saved[] entry |
| 91253 | * which points to outside the string. |
| 91254 | */ |
| 91255 | c1 = duk__inp_get_cp(re_ctx, &p); |
| 91256 | DUK_ASSERT(c1 >= 0); |
| 91257 | c2 = duk__inp_get_cp(re_ctx, &sp); |
| 91258 | /* No need for an explicit c2 < 0 check: because c1 >= 0, |
| 91259 | * the comparison will always fail if c2 < 0. |
| 91260 | */ |
| 91261 | #if 0 |
| 91262 | if (c2 < 0) { |
| 91263 | goto fail; |
| 91264 | } |
| 91265 | #endif |
| 91266 | if (c1 != c2) { |
| 91267 | goto fail; |
| 91268 | } |
| 91269 | } |
| 91270 | break; |
| 91271 | } |
| 91272 | default: { |
| 91273 | DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld" , (long) op)); |
| 91274 | goto internal_error; |
| 91275 | } |
| 91276 | } |
| 91277 | } |
| 91278 | |
| 91279 | match: |
| 91280 | re_ctx->recursion_depth--; |
| 91281 | return sp; |
| 91282 | |
| 91283 | fail: |
| 91284 | re_ctx->recursion_depth--; |
| 91285 | return NULL; |
| 91286 | |
| 91287 | internal_error: |
| 91288 | DUK_ERROR_INTERNAL(re_ctx->thr); |
| 91289 | DUK_WO_NORETURN(return NULL;); |
| 91290 | } |
| 91291 | |
| 91292 | /* |
| 91293 | * Exposed matcher function which provides the semantics of RegExp.prototype.exec(). |
| 91294 | * |
| 91295 | * RegExp.prototype.test() has the same semantics as exec() but does not return the |
| 91296 | * result object (which contains the matching string and capture groups). Currently |
| 91297 | * there is no separate test() helper, so a temporary result object is created and |
| 91298 | * discarded if test() is needed. This is intentional, to save code space. |
| 91299 | * |
| 91300 | * Input stack: [ ... re_obj input ] |
| 91301 | * Output stack: [ ... result ] |
| 91302 | */ |
| 91303 | |
| 91304 | DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) { |
| 91305 | duk_re_matcher_ctx re_ctx; |
| 91306 | duk_hobject *h_regexp; |
| 91307 | duk_hstring *h_bytecode; |
| 91308 | duk_hstring *h_input; |
| 91309 | duk_uint8_t *p_buf; |
| 91310 | const duk_uint8_t *pc; |
| 91311 | const duk_uint8_t *sp; |
| 91312 | duk_small_int_t match = 0; |
| 91313 | duk_small_int_t global; |
| 91314 | duk_uint_fast32_t i; |
| 91315 | double d; |
| 91316 | duk_uint32_t char_offset; |
| 91317 | |
| 91318 | DUK_ASSERT(thr != NULL); |
| 91319 | |
| 91320 | DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T" , |
| 91321 | (duk_tval *) duk_get_tval(thr, -2), |
| 91322 | (duk_tval *) duk_get_tval(thr, -1))); |
| 91323 | |
| 91324 | /* |
| 91325 | * Regexp instance check, bytecode check, input coercion. |
| 91326 | * |
| 91327 | * See E5 Section 15.10.6. |
| 91328 | */ |
| 91329 | |
| 91330 | /* TypeError if wrong; class check, see E5 Section 15.10.6 */ |
| 91331 | h_regexp = duk_require_hobject_with_class(thr, -2, DUK_HOBJECT_CLASS_REGEXP); |
| 91332 | DUK_ASSERT(h_regexp != NULL); |
| 91333 | DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP); |
| 91334 | DUK_UNREF(h_regexp); |
| 91335 | |
| 91336 | h_input = duk_to_hstring(thr, -1); |
| 91337 | DUK_ASSERT(h_input != NULL); |
| 91338 | |
| 91339 | duk_xget_owndataprop_stridx_short(thr, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */ |
| 91340 | h_bytecode = duk_require_hstring(thr, -1); /* no regexp instance should exist without a non-configurable bytecode property */ |
| 91341 | DUK_ASSERT(h_bytecode != NULL); |
| 91342 | |
| 91343 | /* |
| 91344 | * Basic context initialization. |
| 91345 | * |
| 91346 | * Some init values are read from the bytecode header |
| 91347 | * whose format is (UTF-8 codepoints): |
| 91348 | * |
| 91349 | * uint flags |
| 91350 | * uint nsaved (even, 2n+2 where n = num captures) |
| 91351 | */ |
| 91352 | |
| 91353 | /* [ ... re_obj input bc ] */ |
| 91354 | |
| 91355 | duk_memzero(&re_ctx, sizeof(re_ctx)); |
| 91356 | |
| 91357 | re_ctx.thr = thr; |
| 91358 | re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input); |
| 91359 | re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input); |
| 91360 | re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode); |
| 91361 | re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode); |
| 91362 | re_ctx.saved = NULL; |
| 91363 | re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT; |
| 91364 | re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT; |
| 91365 | |
| 91366 | /* read header */ |
| 91367 | pc = re_ctx.bytecode; |
| 91368 | re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc); |
| 91369 | re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc); |
| 91370 | re_ctx.bytecode = pc; |
| 91371 | |
| 91372 | DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */ |
| 91373 | global = (duk_small_int_t) (force_global | (duk_small_int_t) (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL)); |
| 91374 | |
| 91375 | DUK_ASSERT(re_ctx.nsaved >= 2); |
| 91376 | DUK_ASSERT((re_ctx.nsaved % 2) == 0); |
| 91377 | |
| 91378 | p_buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, sizeof(duk_uint8_t *) * re_ctx.nsaved); /* rely on zeroing */ |
| 91379 | DUK_UNREF(p_buf); |
| 91380 | re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(thr, -1, NULL); |
| 91381 | DUK_ASSERT(re_ctx.saved != NULL); |
| 91382 | |
| 91383 | /* [ ... re_obj input bc saved_buf ] */ |
| 91384 | |
| 91385 | #if defined(DUK_USE_EXPLICIT_NULL_INIT) |
| 91386 | for (i = 0; i < re_ctx.nsaved; i++) { |
| 91387 | re_ctx.saved[i] = (duk_uint8_t *) NULL; |
| 91388 | } |
| 91389 | #elif defined(DUK_USE_ZERO_BUFFER_DATA) |
| 91390 | /* buffer is automatically zeroed */ |
| 91391 | #else |
| 91392 | duk_memzero((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved); |
| 91393 | #endif |
| 91394 | |
| 91395 | DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld" , |
| 91396 | (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit, |
| 91397 | (long) re_ctx.steps_limit)); |
| 91398 | |
| 91399 | /* |
| 91400 | * Get starting character offset for match, and initialize 'sp' based on it. |
| 91401 | * |
| 91402 | * Note: lastIndex is non-configurable so it must be present (we check the |
| 91403 | * internal class of the object above, so we know it is). User code can set |
| 91404 | * its value to an arbitrary (garbage) value though; E5 requires that lastIndex |
| 91405 | * be coerced to a number before using. The code below works even if the |
| 91406 | * property is missing: the value will then be coerced to zero. |
| 91407 | * |
| 91408 | * Note: lastIndex may be outside Uint32 range even after ToInteger() coercion. |
| 91409 | * For instance, ToInteger(+Infinity) = +Infinity. We track the match offset |
| 91410 | * as an integer, but pre-check it to be inside the 32-bit range before the loop. |
| 91411 | * If not, the check in E5 Section 15.10.6.2, step 9.a applies. |
| 91412 | */ |
| 91413 | |
| 91414 | /* XXX: lastIndex handling produces a lot of asm */ |
| 91415 | |
| 91416 | /* [ ... re_obj input bc saved_buf ] */ |
| 91417 | |
| 91418 | duk_get_prop_stridx_short(thr, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */ |
| 91419 | (void) duk_to_int(thr, -1); /* ToInteger(lastIndex) */ |
| 91420 | d = duk_get_number(thr, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */ |
| 91421 | duk_pop_nodecref_unsafe(thr); |
| 91422 | |
| 91423 | if (global) { |
| 91424 | if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) { |
| 91425 | /* match fail */ |
| 91426 | char_offset = 0; /* not really necessary */ |
| 91427 | DUK_ASSERT(match == 0); |
| 91428 | goto match_over; |
| 91429 | } |
| 91430 | char_offset = (duk_uint32_t) d; |
| 91431 | } else { |
| 91432 | /* lastIndex must be ignored for non-global regexps, but get the |
| 91433 | * value for (theoretical) side effects. No side effects can |
| 91434 | * really occur, because lastIndex is a normal property and is |
| 91435 | * always non-configurable for RegExp instances. |
| 91436 | */ |
| 91437 | char_offset = (duk_uint32_t) 0; |
| 91438 | } |
| 91439 | |
| 91440 | DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); |
| 91441 | sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset); |
| 91442 | |
| 91443 | /* |
| 91444 | * Match loop. |
| 91445 | * |
| 91446 | * Try matching at different offsets until match found or input exhausted. |
| 91447 | */ |
| 91448 | |
| 91449 | /* [ ... re_obj input bc saved_buf ] */ |
| 91450 | |
| 91451 | DUK_ASSERT(match == 0); |
| 91452 | |
| 91453 | for (;;) { |
| 91454 | /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */ |
| 91455 | DUK_ASSERT_DISABLE(char_offset >= 0); |
| 91456 | DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input)); |
| 91457 | |
| 91458 | /* Note: re_ctx.steps is intentionally not reset, it applies to the entire unanchored match */ |
| 91459 | DUK_ASSERT(re_ctx.recursion_depth == 0); |
| 91460 | |
| 91461 | DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]" , |
| 91462 | (long) char_offset, (const void *) sp, |
| 91463 | (const void *) re_ctx.input, (const void *) re_ctx.input_end)); |
| 91464 | |
| 91465 | /* |
| 91466 | * Note: |
| 91467 | * |
| 91468 | * - duk__match_regexp() is required not to longjmp() in ordinary "non-match" |
| 91469 | * conditions; a longjmp() will terminate the entire matching process. |
| 91470 | * |
| 91471 | * - Clearing saved[] is not necessary because backtracking does it |
| 91472 | * |
| 91473 | * - Backtracking also rewinds re_ctx.recursion back to zero, unless an |
| 91474 | * internal/limit error occurs (which causes a longjmp()) |
| 91475 | * |
| 91476 | * - If we supported anchored matches, we would break out here |
| 91477 | * unconditionally; however, ECMAScript regexps don't have anchored |
| 91478 | * matches. It might make sense to implement a fast bail-out if |
| 91479 | * the regexp begins with '^' and sp is not 0: currently we'll just |
| 91480 | * run through the entire input string, trivially failing the match |
| 91481 | * at every non-zero offset. |
| 91482 | */ |
| 91483 | |
| 91484 | if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) { |
| 91485 | DUK_DDD(DUK_DDDPRINT("match at offset %ld" , (long) char_offset)); |
| 91486 | match = 1; |
| 91487 | break; |
| 91488 | } |
| 91489 | |
| 91490 | /* advance by one character (code point) and one char_offset */ |
| 91491 | char_offset++; |
| 91492 | if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) { |
| 91493 | /* |
| 91494 | * Note: |
| 91495 | * |
| 91496 | * - Intentionally attempt (empty) match at char_offset == k_input->clen |
| 91497 | * |
| 91498 | * - Negative char_offsets have been eliminated and char_offset is duk_uint32_t |
| 91499 | * -> no need or use for a negative check |
| 91500 | */ |
| 91501 | |
| 91502 | DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets" )); |
| 91503 | break; |
| 91504 | } |
| 91505 | |
| 91506 | /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */ |
| 91507 | (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1); |
| 91508 | } |
| 91509 | |
| 91510 | match_over: |
| 91511 | |
| 91512 | /* |
| 91513 | * Matching complete, create result array or return a 'null'. Update lastIndex |
| 91514 | * if necessary. See E5 Section 15.10.6.2. |
| 91515 | * |
| 91516 | * Because lastIndex is a character (not byte) offset, we need the character |
| 91517 | * length of the match which we conveniently get as a side effect of interning |
| 91518 | * the matching substring (0th index of result array). |
| 91519 | * |
| 91520 | * saved[0] start pointer (~ byte offset) of current match |
| 91521 | * saved[1] end pointer (~ byte offset) of current match (exclusive) |
| 91522 | * char_offset start character offset of current match (-> .index of result) |
| 91523 | * char_end_offset end character offset (computed below) |
| 91524 | */ |
| 91525 | |
| 91526 | /* [ ... re_obj input bc saved_buf ] */ |
| 91527 | |
| 91528 | if (match) { |
| 91529 | #if defined(DUK_USE_ASSERTIONS) |
| 91530 | duk_hobject *h_res; |
| 91531 | #endif |
| 91532 | duk_uint32_t char_end_offset = 0; |
| 91533 | |
| 91534 | DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld" , (long) char_offset)); |
| 91535 | |
| 91536 | DUK_ASSERT(re_ctx.nsaved >= 2); /* must have start and end */ |
| 91537 | DUK_ASSERT((re_ctx.nsaved % 2) == 0); /* and even number */ |
| 91538 | |
| 91539 | /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken |
| 91540 | * advantage of now. The array is not compacted either, as regexp match |
| 91541 | * objects are usually short lived. |
| 91542 | */ |
| 91543 | |
| 91544 | duk_push_array(thr); |
| 91545 | |
| 91546 | #if defined(DUK_USE_ASSERTIONS) |
| 91547 | h_res = duk_require_hobject(thr, -1); |
| 91548 | DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res)); |
| 91549 | DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res)); |
| 91550 | DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY); |
| 91551 | #endif |
| 91552 | |
| 91553 | /* [ ... re_obj input bc saved_buf res_obj ] */ |
| 91554 | |
| 91555 | duk_push_u32(thr, char_offset); |
| 91556 | duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INDEX); |
| 91557 | |
| 91558 | duk_dup_m4(thr); |
| 91559 | duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INPUT); |
| 91560 | |
| 91561 | for (i = 0; i < re_ctx.nsaved; i += 2) { |
| 91562 | /* Captures which are undefined have NULL pointers and are returned |
| 91563 | * as 'undefined'. The same is done when saved[] pointers are insane |
| 91564 | * (this should, of course, never happen in practice). |
| 91565 | */ |
| 91566 | duk_push_uarridx(thr, (duk_uarridx_t) (i / 2)); |
| 91567 | |
| 91568 | if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) { |
| 91569 | duk_push_lstring(thr, |
| 91570 | (const char *) re_ctx.saved[i], |
| 91571 | (duk_size_t) (re_ctx.saved[i + 1] - re_ctx.saved[i])); |
| 91572 | if (i == 0) { |
| 91573 | /* Assumes that saved[0] and saved[1] are always |
| 91574 | * set by regexp bytecode (if not, char_end_offset |
| 91575 | * will be zero). Also assumes clen reflects the |
| 91576 | * correct char length. |
| 91577 | */ |
| 91578 | char_end_offset = char_offset + (duk_uint32_t) duk_get_length(thr, -1); /* add charlen */ |
| 91579 | } |
| 91580 | } else { |
| 91581 | duk_push_undefined(thr); |
| 91582 | } |
| 91583 | |
| 91584 | /* [ ... re_obj input bc saved_buf res_obj idx val ] */ |
| 91585 | duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WEC); |
| 91586 | } |
| 91587 | |
| 91588 | /* [ ... re_obj input bc saved_buf res_obj ] */ |
| 91589 | |
| 91590 | /* NB: 'length' property is automatically updated by the array setup loop */ |
| 91591 | |
| 91592 | if (global) { |
| 91593 | /* global regexp: lastIndex updated on match */ |
| 91594 | duk_push_u32(thr, char_end_offset); |
| 91595 | duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX); |
| 91596 | } else { |
| 91597 | /* non-global regexp: lastIndex never updated on match */ |
| 91598 | ; |
| 91599 | } |
| 91600 | } else { |
| 91601 | /* |
| 91602 | * No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless |
| 91603 | * of 'global' flag of the RegExp. In particular, if lastIndex is invalid |
| 91604 | * initially, it is reset to zero. |
| 91605 | */ |
| 91606 | |
| 91607 | DUK_DDD(DUK_DDDPRINT("regexp does not match" )); |
| 91608 | |
| 91609 | duk_push_null(thr); |
| 91610 | |
| 91611 | /* [ ... re_obj input bc saved_buf res_obj ] */ |
| 91612 | |
| 91613 | duk_push_int(thr, 0); |
| 91614 | duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX); |
| 91615 | } |
| 91616 | |
| 91617 | /* [ ... re_obj input bc saved_buf res_obj ] */ |
| 91618 | |
| 91619 | duk_insert(thr, -5); |
| 91620 | |
| 91621 | /* [ ... res_obj re_obj input bc saved_buf ] */ |
| 91622 | |
| 91623 | duk_pop_n_unsafe(thr, 4); |
| 91624 | |
| 91625 | /* [ ... res_obj ] */ |
| 91626 | |
| 91627 | /* XXX: these last tricks are unnecessary if the function is made |
| 91628 | * a genuine native function. |
| 91629 | */ |
| 91630 | } |
| 91631 | |
| 91632 | DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) { |
| 91633 | duk__regexp_match_helper(thr, 0 /*force_global*/); |
| 91634 | } |
| 91635 | |
| 91636 | /* This variant is needed by String.prototype.split(); it needs to perform |
| 91637 | * global-style matching on a cloned RegExp which is potentially non-global. |
| 91638 | */ |
| 91639 | DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) { |
| 91640 | duk__regexp_match_helper(thr, 1 /*force_global*/); |
| 91641 | } |
| 91642 | |
| 91643 | #else /* DUK_USE_REGEXP_SUPPORT */ |
| 91644 | |
| 91645 | /* regexp support disabled */ |
| 91646 | |
| 91647 | #endif /* DUK_USE_REGEXP_SUPPORT */ |
| 91648 | #line 1 "duk_selftest.c" |
| 91649 | /* |
| 91650 | * Self tests to ensure execution environment is sane. Intended to catch |
| 91651 | * compiler/platform problems which cannot be detected at compile time. |
| 91652 | */ |
| 91653 | |
| 91654 | /* #include duk_internal.h -> already included */ |
| 91655 | |
| 91656 | #if defined(DUK_USE_SELF_TESTS) |
| 91657 | |
| 91658 | /* |
| 91659 | * Unions and structs for self tests |
| 91660 | */ |
| 91661 | |
| 91662 | typedef union { |
| 91663 | double d; |
| 91664 | duk_uint8_t x[8]; |
| 91665 | } duk__test_double_union; |
| 91666 | |
| 91667 | /* Self test failed. Expects a local variable 'error_count' to exist. */ |
| 91668 | #define DUK__FAILED(msg) do { \ |
| 91669 | DUK_D(DUK_DPRINT("self test failed: " #msg " at " DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO))); \ |
| 91670 | error_count++; \ |
| 91671 | } while (0) |
| 91672 | |
| 91673 | #define DUK__DBLUNION_CMP_TRUE(a,b) do { \ |
| 91674 | if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \ |
| 91675 | DUK__FAILED("double union compares false (expected true)"); \ |
| 91676 | } \ |
| 91677 | } while (0) |
| 91678 | |
| 91679 | #define DUK__DBLUNION_CMP_FALSE(a,b) do { \ |
| 91680 | if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \ |
| 91681 | DUK__FAILED("double union compares true (expected false)"); \ |
| 91682 | } \ |
| 91683 | } while (0) |
| 91684 | |
| 91685 | typedef union { |
| 91686 | duk_uint32_t i; |
| 91687 | duk_uint8_t x[8]; |
| 91688 | } duk__test_u32_union; |
| 91689 | |
| 91690 | #if defined(DUK_USE_INTEGER_LE) |
| 91691 | #define DUK__U32_INIT(u, a, b, c, d) do { \ |
| 91692 | (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \ |
| 91693 | } while (0) |
| 91694 | #elif defined(DUK_USE_INTEGER_ME) |
| 91695 | #error integer mixed endian not supported now |
| 91696 | #elif defined(DUK_USE_INTEGER_BE) |
| 91697 | #define DUK__U32_INIT(u, a, b, c, d) do { \ |
| 91698 | (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \ |
| 91699 | } while (0) |
| 91700 | #else |
| 91701 | #error unknown integer endianness |
| 91702 | #endif |
| 91703 | |
| 91704 | #if defined(DUK_USE_DOUBLE_LE) |
| 91705 | #define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \ |
| 91706 | (u)->x[0] = (h); (u)->x[1] = (g); (u)->x[2] = (f); (u)->x[3] = (e); \ |
| 91707 | (u)->x[4] = (d); (u)->x[5] = (c); (u)->x[6] = (b); (u)->x[7] = (a); \ |
| 91708 | } while (0) |
| 91709 | #define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \ |
| 91710 | ((u)->x[0] == (h) && (u)->x[1] == (g) && (u)->x[2] == (f) && (u)->x[3] == (e) && \ |
| 91711 | (u)->x[4] == (d) && (u)->x[5] == (c) && (u)->x[6] == (b) && (u)->x[7] == (a)) |
| 91712 | #elif defined(DUK_USE_DOUBLE_ME) |
| 91713 | #define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \ |
| 91714 | (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \ |
| 91715 | (u)->x[4] = (h); (u)->x[5] = (g); (u)->x[6] = (f); (u)->x[7] = (e); \ |
| 91716 | } while (0) |
| 91717 | #define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \ |
| 91718 | ((u)->x[0] == (d) && (u)->x[1] == (c) && (u)->x[2] == (b) && (u)->x[3] == (a) && \ |
| 91719 | (u)->x[4] == (h) && (u)->x[5] == (g) && (u)->x[6] == (f) && (u)->x[7] == (e)) |
| 91720 | #elif defined(DUK_USE_DOUBLE_BE) |
| 91721 | #define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \ |
| 91722 | (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \ |
| 91723 | (u)->x[4] = (e); (u)->x[5] = (f); (u)->x[6] = (g); (u)->x[7] = (h); \ |
| 91724 | } while (0) |
| 91725 | #define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \ |
| 91726 | ((u)->x[0] == (a) && (u)->x[1] == (b) && (u)->x[2] == (c) && (u)->x[3] == (d) && \ |
| 91727 | (u)->x[4] == (e) && (u)->x[5] == (f) && (u)->x[6] == (g) && (u)->x[7] == (h)) |
| 91728 | #else |
| 91729 | #error unknown double endianness |
| 91730 | #endif |
| 91731 | |
| 91732 | /* |
| 91733 | * Various sanity checks for typing |
| 91734 | */ |
| 91735 | |
| 91736 | DUK_LOCAL duk_uint_t duk__selftest_types(void) { |
| 91737 | duk_uint_t error_count = 0; |
| 91738 | |
| 91739 | if (!(sizeof(duk_int8_t) == 1 && |
| 91740 | sizeof(duk_uint8_t) == 1 && |
| 91741 | sizeof(duk_int16_t) == 2 && |
| 91742 | sizeof(duk_uint16_t) == 2 && |
| 91743 | sizeof(duk_int32_t) == 4 && |
| 91744 | sizeof(duk_uint32_t) == 4)) { |
| 91745 | DUK__FAILED("duk_(u)int{8,16,32}_t size" ); |
| 91746 | } |
| 91747 | #if defined(DUK_USE_64BIT_OPS) |
| 91748 | if (!(sizeof(duk_int64_t) == 8 && |
| 91749 | sizeof(duk_uint64_t) == 8)) { |
| 91750 | DUK__FAILED("duk_(u)int64_t size" ); |
| 91751 | } |
| 91752 | #endif |
| 91753 | |
| 91754 | if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) { |
| 91755 | /* Some internal code now assumes that all duk_uint_t values |
| 91756 | * can be expressed with a duk_size_t. |
| 91757 | */ |
| 91758 | DUK__FAILED("duk_size_t is smaller than duk_uint_t" ); |
| 91759 | } |
| 91760 | if (!(sizeof(duk_int_t) >= 4)) { |
| 91761 | DUK__FAILED("duk_int_t is not 32 bits" ); |
| 91762 | } |
| 91763 | |
| 91764 | return error_count; |
| 91765 | } |
| 91766 | |
| 91767 | /* |
| 91768 | * Packed tval sanity |
| 91769 | */ |
| 91770 | |
| 91771 | DUK_LOCAL duk_uint_t duk__selftest_packed_tval(void) { |
| 91772 | duk_uint_t error_count = 0; |
| 91773 | |
| 91774 | #if defined(DUK_USE_PACKED_TVAL) |
| 91775 | if (sizeof(void *) > 4) { |
| 91776 | DUK__FAILED("packed duk_tval in use but sizeof(void *) > 4" ); |
| 91777 | } |
| 91778 | #endif |
| 91779 | |
| 91780 | return error_count; |
| 91781 | } |
| 91782 | |
| 91783 | /* |
| 91784 | * Two's complement arithmetic. |
| 91785 | */ |
| 91786 | |
| 91787 | DUK_LOCAL duk_uint_t duk__selftest_twos_complement(void) { |
| 91788 | duk_uint_t error_count = 0; |
| 91789 | volatile int test; |
| 91790 | test = -1; |
| 91791 | |
| 91792 | /* Note that byte order doesn't affect this test: all bytes in |
| 91793 | * 'test' will be 0xFF for two's complement. |
| 91794 | */ |
| 91795 | if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) { |
| 91796 | DUK__FAILED("two's complement arithmetic" ); |
| 91797 | } |
| 91798 | |
| 91799 | return error_count; |
| 91800 | } |
| 91801 | |
| 91802 | /* |
| 91803 | * Byte order. Important to self check, because on some exotic platforms |
| 91804 | * there is no actual detection but rather assumption based on platform |
| 91805 | * defines. |
| 91806 | */ |
| 91807 | |
| 91808 | DUK_LOCAL duk_uint_t duk__selftest_byte_order(void) { |
| 91809 | duk_uint_t error_count = 0; |
| 91810 | duk__test_u32_union u1; |
| 91811 | duk__test_double_union u2; |
| 91812 | |
| 91813 | /* |
| 91814 | * >>> struct.pack('>d', 102030405060).encode('hex') |
| 91815 | * '4237c17c6dc40000' |
| 91816 | */ |
| 91817 | |
| 91818 | DUK__U32_INIT(&u1, 0xde, 0xad, 0xbe, 0xef); |
| 91819 | DUK__DOUBLE_INIT(&u2, 0x42, 0x37, 0xc1, 0x7c, 0x6d, 0xc4, 0x00, 0x00); |
| 91820 | |
| 91821 | if (u1.i != (duk_uint32_t) 0xdeadbeefUL) { |
| 91822 | DUK__FAILED("duk_uint32_t byte order" ); |
| 91823 | } |
| 91824 | |
| 91825 | if (!duk_double_equals(u2.d, 102030405060.0)) { |
| 91826 | DUK__FAILED("double byte order" ); |
| 91827 | } |
| 91828 | |
| 91829 | return error_count; |
| 91830 | } |
| 91831 | |
| 91832 | /* |
| 91833 | * DUK_BSWAP macros |
| 91834 | */ |
| 91835 | |
| 91836 | DUK_LOCAL duk_uint_t duk__selftest_bswap_macros(void) { |
| 91837 | duk_uint_t error_count = 0; |
| 91838 | volatile duk_uint32_t x32_input, x32_output; |
| 91839 | duk_uint32_t x32; |
| 91840 | volatile duk_uint16_t x16_input, x16_output; |
| 91841 | duk_uint16_t x16; |
| 91842 | duk_double_union du; |
| 91843 | duk_double_t du_diff; |
| 91844 | #if defined(DUK_BSWAP64) |
| 91845 | volatile duk_uint64_t x64_input, x64_output; |
| 91846 | duk_uint64_t x64; |
| 91847 | #endif |
| 91848 | |
| 91849 | /* Cover both compile time and runtime bswap operations, as these |
| 91850 | * may have different bugs. |
| 91851 | */ |
| 91852 | |
| 91853 | x16_input = 0xbeefUL; |
| 91854 | x16 = x16_input; |
| 91855 | x16 = DUK_BSWAP16(x16); |
| 91856 | x16_output = x16; |
| 91857 | if (x16_output != (duk_uint16_t) 0xefbeUL) { |
| 91858 | DUK__FAILED("DUK_BSWAP16" ); |
| 91859 | } |
| 91860 | |
| 91861 | x16 = 0xbeefUL; |
| 91862 | x16 = DUK_BSWAP16(x16); |
| 91863 | if (x16 != (duk_uint16_t) 0xefbeUL) { |
| 91864 | DUK__FAILED("DUK_BSWAP16" ); |
| 91865 | } |
| 91866 | |
| 91867 | x32_input = 0xdeadbeefUL; |
| 91868 | x32 = x32_input; |
| 91869 | x32 = DUK_BSWAP32(x32); |
| 91870 | x32_output = x32; |
| 91871 | if (x32_output != (duk_uint32_t) 0xefbeaddeUL) { |
| 91872 | DUK__FAILED("DUK_BSWAP32" ); |
| 91873 | } |
| 91874 | |
| 91875 | x32 = 0xdeadbeefUL; |
| 91876 | x32 = DUK_BSWAP32(x32); |
| 91877 | if (x32 != (duk_uint32_t) 0xefbeaddeUL) { |
| 91878 | DUK__FAILED("DUK_BSWAP32" ); |
| 91879 | } |
| 91880 | |
| 91881 | #if defined(DUK_BSWAP64) |
| 91882 | x64_input = DUK_U64_CONSTANT(0x8899aabbccddeeff); |
| 91883 | x64 = x64_input; |
| 91884 | x64 = DUK_BSWAP64(x64); |
| 91885 | x64_output = x64; |
| 91886 | if (x64_output != (duk_uint64_t) DUK_U64_CONSTANT(0xffeeddccbbaa9988)) { |
| 91887 | DUK__FAILED("DUK_BSWAP64" ); |
| 91888 | } |
| 91889 | |
| 91890 | x64 = DUK_U64_CONSTANT(0x8899aabbccddeeff); |
| 91891 | x64 = DUK_BSWAP64(x64); |
| 91892 | if (x64 != (duk_uint64_t) DUK_U64_CONSTANT(0xffeeddccbbaa9988)) { |
| 91893 | DUK__FAILED("DUK_BSWAP64" ); |
| 91894 | } |
| 91895 | #endif |
| 91896 | |
| 91897 | /* >>> struct.unpack('>d', '4000112233445566'.decode('hex')) |
| 91898 | * (2.008366013071895,) |
| 91899 | */ |
| 91900 | |
| 91901 | du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22; |
| 91902 | du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66; |
| 91903 | DUK_DBLUNION_DOUBLE_NTOH(&du); |
| 91904 | du_diff = du.d - 2.008366013071895; |
| 91905 | #if 0 |
| 91906 | DUK_D(DUK_DPRINT("du_diff: %lg\n" , (double) du_diff)); |
| 91907 | #endif |
| 91908 | if (du_diff > 1e-15) { |
| 91909 | /* Allow very small lenience because some compilers won't parse |
| 91910 | * exact IEEE double constants (happened in matrix testing with |
| 91911 | * Linux gcc-4.8 -m32 at least). |
| 91912 | */ |
| 91913 | #if 0 |
| 91914 | DUK_D(DUK_DPRINT("Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n" , |
| 91915 | (unsigned int) du.uc[0], (unsigned int) du.uc[1], |
| 91916 | (unsigned int) du.uc[2], (unsigned int) du.uc[3], |
| 91917 | (unsigned int) du.uc[4], (unsigned int) du.uc[5], |
| 91918 | (unsigned int) du.uc[6], (unsigned int) du.uc[7])); |
| 91919 | #endif |
| 91920 | DUK__FAILED("DUK_DBLUNION_DOUBLE_NTOH" ); |
| 91921 | } |
| 91922 | |
| 91923 | return error_count; |
| 91924 | } |
| 91925 | |
| 91926 | /* |
| 91927 | * Basic double / byte union memory layout. |
| 91928 | */ |
| 91929 | |
| 91930 | DUK_LOCAL duk_uint_t duk__selftest_double_union_size(void) { |
| 91931 | duk_uint_t error_count = 0; |
| 91932 | |
| 91933 | if (sizeof(duk__test_double_union) != 8) { |
| 91934 | DUK__FAILED("invalid union size" ); |
| 91935 | } |
| 91936 | |
| 91937 | return error_count; |
| 91938 | } |
| 91939 | |
| 91940 | /* |
| 91941 | * Union aliasing, see misc/clang_aliasing.c. |
| 91942 | */ |
| 91943 | |
| 91944 | DUK_LOCAL duk_uint_t duk__selftest_double_aliasing(void) { |
| 91945 | /* This testcase fails when Emscripten-generated code runs on Firefox. |
| 91946 | * It's not an issue because the failure should only affect packed |
| 91947 | * duk_tval representation, which is not used with Emscripten. |
| 91948 | */ |
| 91949 | #if defined(DUK_USE_PACKED_TVAL) |
| 91950 | duk_uint_t error_count = 0; |
| 91951 | duk__test_double_union a, b; |
| 91952 | |
| 91953 | /* Test signaling NaN and alias assignment in all endianness combinations. |
| 91954 | */ |
| 91955 | |
| 91956 | /* little endian */ |
| 91957 | a.x[0] = 0x11; a.x[1] = 0x22; a.x[2] = 0x33; a.x[3] = 0x44; |
| 91958 | a.x[4] = 0x00; a.x[5] = 0x00; a.x[6] = 0xf1; a.x[7] = 0xff; |
| 91959 | b = a; |
| 91960 | DUK__DBLUNION_CMP_TRUE(&a, &b); |
| 91961 | |
| 91962 | /* big endian */ |
| 91963 | a.x[0] = 0xff; a.x[1] = 0xf1; a.x[2] = 0x00; a.x[3] = 0x00; |
| 91964 | a.x[4] = 0x44; a.x[5] = 0x33; a.x[6] = 0x22; a.x[7] = 0x11; |
| 91965 | b = a; |
| 91966 | DUK__DBLUNION_CMP_TRUE(&a, &b); |
| 91967 | |
| 91968 | /* mixed endian */ |
| 91969 | a.x[0] = 0x00; a.x[1] = 0x00; a.x[2] = 0xf1; a.x[3] = 0xff; |
| 91970 | a.x[4] = 0x11; a.x[5] = 0x22; a.x[6] = 0x33; a.x[7] = 0x44; |
| 91971 | b = a; |
| 91972 | DUK__DBLUNION_CMP_TRUE(&a, &b); |
| 91973 | |
| 91974 | return error_count; |
| 91975 | #else |
| 91976 | DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed" )); |
| 91977 | return 0; |
| 91978 | #endif |
| 91979 | } |
| 91980 | |
| 91981 | /* |
| 91982 | * Zero sign, see misc/tcc_zerosign2.c. |
| 91983 | */ |
| 91984 | |
| 91985 | DUK_LOCAL duk_uint_t duk__selftest_double_zero_sign(void) { |
| 91986 | duk_uint_t error_count = 0; |
| 91987 | duk__test_double_union a, b; |
| 91988 | |
| 91989 | a.d = 0.0; |
| 91990 | b.d = -a.d; |
| 91991 | DUK__DBLUNION_CMP_FALSE(&a, &b); |
| 91992 | |
| 91993 | return error_count; |
| 91994 | } |
| 91995 | |
| 91996 | /* |
| 91997 | * Rounding mode: Duktape assumes round-to-nearest, check that this is true. |
| 91998 | * If we had C99 fenv.h we could check that fegetround() == FE_TONEAREST, |
| 91999 | * but we don't want to rely on that header; and even if we did, it's good |
| 92000 | * to ensure the rounding actually works. |
| 92001 | */ |
| 92002 | |
| 92003 | DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) { |
| 92004 | duk_uint_t error_count = 0; |
| 92005 | duk__test_double_union a, b, c; |
| 92006 | |
| 92007 | #if 0 |
| 92008 | /* Include <fenv.h> and test manually; these trigger failures: */ |
| 92009 | fesetround(FE_UPWARD); |
| 92010 | fesetround(FE_DOWNWARD); |
| 92011 | fesetround(FE_TOWARDZERO); |
| 92012 | |
| 92013 | /* This is the default and passes. */ |
| 92014 | fesetround(FE_TONEAREST); |
| 92015 | #endif |
| 92016 | |
| 92017 | /* Rounding tests check that none of the other modes (round to |
| 92018 | * +Inf, round to -Inf, round to zero) can be active: |
| 92019 | * http://www.gnu.org/software/libc/manual/html_node/Rounding.html |
| 92020 | */ |
| 92021 | |
| 92022 | /* 1.0 + 2^(-53): result is midway between 1.0 and 1.0 + ulp. |
| 92023 | * Round to nearest: 1.0 |
| 92024 | * Round to +Inf: 1.0 + ulp |
| 92025 | * Round to -Inf: 1.0 |
| 92026 | * Round to zero: 1.0 |
| 92027 | * => Correct result eliminates round to +Inf. |
| 92028 | */ |
| 92029 | DUK__DOUBLE_INIT(&a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
| 92030 | DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
| 92031 | duk_memset((void *) &c, 0, sizeof(c)); |
| 92032 | c.d = a.d + b.d; |
| 92033 | if (!DUK__DOUBLE_COMPARE(&c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)) { |
| 92034 | DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x" , |
| 92035 | (unsigned int) c.x[0], (unsigned int) c.x[1], |
| 92036 | (unsigned int) c.x[2], (unsigned int) c.x[3], |
| 92037 | (unsigned int) c.x[4], (unsigned int) c.x[5], |
| 92038 | (unsigned int) c.x[6], (unsigned int) c.x[7])); |
| 92039 | DUK__FAILED("invalid result from 1.0 + 0.5ulp" ); |
| 92040 | } |
| 92041 | |
| 92042 | /* (1.0 + ulp) + 2^(-53): result is midway between 1.0 + ulp and 1.0 + 2*ulp. |
| 92043 | * Round to nearest: 1.0 + 2*ulp (round to even mantissa) |
| 92044 | * Round to +Inf: 1.0 + 2*ulp |
| 92045 | * Round to -Inf: 1.0 + ulp |
| 92046 | * Round to zero: 1.0 + ulp |
| 92047 | * => Correct result eliminates round to -Inf and round to zero. |
| 92048 | */ |
| 92049 | DUK__DOUBLE_INIT(&a, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01); |
| 92050 | DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); |
| 92051 | duk_memset((void *) &c, 0, sizeof(c)); |
| 92052 | c.d = a.d + b.d; |
| 92053 | if (!DUK__DOUBLE_COMPARE(&c, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02)) { |
| 92054 | DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x" , |
| 92055 | (unsigned int) c.x[0], (unsigned int) c.x[1], |
| 92056 | (unsigned int) c.x[2], (unsigned int) c.x[3], |
| 92057 | (unsigned int) c.x[4], (unsigned int) c.x[5], |
| 92058 | (unsigned int) c.x[6], (unsigned int) c.x[7])); |
| 92059 | DUK__FAILED("invalid result from (1.0 + ulp) + 0.5ulp" ); |
| 92060 | } |
| 92061 | |
| 92062 | /* Could do negative number testing too, but the tests above should |
| 92063 | * differentiate between IEEE 754 rounding modes. |
| 92064 | */ |
| 92065 | return error_count; |
| 92066 | } |
| 92067 | |
| 92068 | /* |
| 92069 | * fmod(): often a portability issue in embedded or bare platform targets. |
| 92070 | * Check for at least minimally correct behavior. Unlike some other math |
| 92071 | * functions (like cos()) Duktape relies on fmod() internally too. |
| 92072 | */ |
| 92073 | |
| 92074 | DUK_LOCAL duk_uint_t duk__selftest_fmod(void) { |
| 92075 | duk_uint_t error_count = 0; |
| 92076 | duk__test_double_union u1, u2; |
| 92077 | volatile duk_double_t t1, t2, t3; |
| 92078 | |
| 92079 | /* fmod() with integer argument and exponent 2^32 is used by e.g. |
| 92080 | * ToUint32() and some Duktape internals. |
| 92081 | */ |
| 92082 | u1.d = DUK_FMOD(10.0, 4294967296.0); |
| 92083 | u2.d = 10.0; |
| 92084 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92085 | |
| 92086 | u1.d = DUK_FMOD(4294967306.0, 4294967296.0); |
| 92087 | u2.d = 10.0; |
| 92088 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92089 | |
| 92090 | u1.d = DUK_FMOD(73014444042.0, 4294967296.0); |
| 92091 | u2.d = 10.0; |
| 92092 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92093 | |
| 92094 | /* 52-bit integer split into two parts: |
| 92095 | * >>> 0x1fedcba9876543 |
| 92096 | * 8987183256397123 |
| 92097 | * >>> float(0x1fedcba9876543) / float(2**53) |
| 92098 | * 0.9977777777777778 |
| 92099 | */ |
| 92100 | u1.d = DUK_FMOD(8987183256397123.0, 4294967296.0); |
| 92101 | u2.d = (duk_double_t) 0xa9876543UL; |
| 92102 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92103 | t1 = 8987183256397123.0; |
| 92104 | t2 = 4294967296.0; |
| 92105 | t3 = t1 / t2; |
| 92106 | u1.d = DUK_FLOOR(t3); |
| 92107 | u2.d = (duk_double_t) 0x1fedcbUL; |
| 92108 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92109 | |
| 92110 | /* C99 behavior is for fmod() result sign to mathc argument sign. */ |
| 92111 | u1.d = DUK_FMOD(-10.0, 4294967296.0); |
| 92112 | u2.d = -10.0; |
| 92113 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92114 | |
| 92115 | u1.d = DUK_FMOD(-4294967306.0, 4294967296.0); |
| 92116 | u2.d = -10.0; |
| 92117 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92118 | |
| 92119 | u1.d = DUK_FMOD(-73014444042.0, 4294967296.0); |
| 92120 | u2.d = -10.0; |
| 92121 | DUK__DBLUNION_CMP_TRUE(&u1, &u2); |
| 92122 | |
| 92123 | return error_count; |
| 92124 | } |
| 92125 | |
| 92126 | /* |
| 92127 | * Struct size/alignment if platform requires it |
| 92128 | * |
| 92129 | * There are some compiler specific struct padding pragmas etc in use, this |
| 92130 | * selftest ensures they're correctly detected and used. |
| 92131 | */ |
| 92132 | |
| 92133 | DUK_LOCAL duk_uint_t duk__selftest_struct_align(void) { |
| 92134 | duk_uint_t error_count = 0; |
| 92135 | |
| 92136 | #if (DUK_USE_ALIGN_BY == 4) |
| 92137 | if ((sizeof(duk_hbuffer_fixed) % 4) != 0) { |
| 92138 | DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 4" ); |
| 92139 | } |
| 92140 | #elif (DUK_USE_ALIGN_BY == 8) |
| 92141 | if ((sizeof(duk_hbuffer_fixed) % 8) != 0) { |
| 92142 | DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 8" ); |
| 92143 | } |
| 92144 | #elif (DUK_USE_ALIGN_BY == 1) |
| 92145 | /* no check */ |
| 92146 | #else |
| 92147 | #error invalid DUK_USE_ALIGN_BY |
| 92148 | #endif |
| 92149 | return error_count; |
| 92150 | } |
| 92151 | |
| 92152 | /* |
| 92153 | * 64-bit arithmetic |
| 92154 | * |
| 92155 | * There are some platforms/compilers where 64-bit types are available |
| 92156 | * but don't work correctly. Test for known cases. |
| 92157 | */ |
| 92158 | |
| 92159 | DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) { |
| 92160 | duk_uint_t error_count = 0; |
| 92161 | #if defined(DUK_USE_64BIT_OPS) |
| 92162 | volatile duk_int64_t i; |
| 92163 | volatile duk_double_t d; |
| 92164 | |
| 92165 | /* Catch a double-to-int64 cast issue encountered in practice. */ |
| 92166 | d = 2147483648.0; |
| 92167 | i = (duk_int64_t) d; |
| 92168 | if (i != DUK_I64_CONSTANT(0x80000000)) { |
| 92169 | DUK__FAILED("casting 2147483648.0 to duk_int64_t failed" ); |
| 92170 | } |
| 92171 | #else |
| 92172 | /* nop */ |
| 92173 | #endif |
| 92174 | return error_count; |
| 92175 | } |
| 92176 | |
| 92177 | /* |
| 92178 | * Casting |
| 92179 | */ |
| 92180 | |
| 92181 | DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_small_uint(void) { |
| 92182 | /* |
| 92183 | * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473 |
| 92184 | */ |
| 92185 | |
| 92186 | duk_uint_t error_count = 0; |
| 92187 | |
| 92188 | duk_double_t d1, d2; |
| 92189 | duk_small_uint_t u; |
| 92190 | |
| 92191 | duk_double_t d1v, d2v; |
| 92192 | duk_small_uint_t uv; |
| 92193 | |
| 92194 | /* Test without volatiles */ |
| 92195 | |
| 92196 | d1 = 1.0; |
| 92197 | u = (duk_small_uint_t) d1; |
| 92198 | d2 = (duk_double_t) u; |
| 92199 | |
| 92200 | if (!(duk_double_equals(d1, 1.0) && u == 1 && duk_double_equals(d2, 1.0) && duk_double_equals(d1, d2))) { |
| 92201 | DUK__FAILED("double to duk_small_uint_t cast failed" ); |
| 92202 | } |
| 92203 | |
| 92204 | /* Same test with volatiles */ |
| 92205 | |
| 92206 | d1v = 1.0; |
| 92207 | uv = (duk_small_uint_t) d1v; |
| 92208 | d2v = (duk_double_t) uv; |
| 92209 | |
| 92210 | if (!(duk_double_equals(d1v, 1.0) && uv == 1 && duk_double_equals(d2v, 1.0) && duk_double_equals(d1v, d2v))) { |
| 92211 | DUK__FAILED("double to duk_small_uint_t cast failed" ); |
| 92212 | } |
| 92213 | |
| 92214 | return error_count; |
| 92215 | } |
| 92216 | |
| 92217 | DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) { |
| 92218 | /* |
| 92219 | * This test fails on an exotic ARM target; double-to-uint |
| 92220 | * cast is incorrectly clamped to -signed- int highest value. |
| 92221 | * |
| 92222 | * https://github.com/svaarala/duktape/issues/336 |
| 92223 | */ |
| 92224 | |
| 92225 | duk_uint_t error_count = 0; |
| 92226 | duk_double_t dv; |
| 92227 | duk_uint32_t uv; |
| 92228 | |
| 92229 | dv = 3735928559.0; /* 0xdeadbeef in decimal */ |
| 92230 | uv = (duk_uint32_t) dv; |
| 92231 | |
| 92232 | if (uv != 0xdeadbeefUL) { |
| 92233 | DUK__FAILED("double to duk_uint32_t cast failed" ); |
| 92234 | } |
| 92235 | |
| 92236 | return error_count; |
| 92237 | } |
| 92238 | |
| 92239 | /* |
| 92240 | * Minimal test of user supplied allocation functions |
| 92241 | * |
| 92242 | * - Basic alloc + realloc + free cycle |
| 92243 | * |
| 92244 | * - Realloc to significantly larger size to (hopefully) trigger a |
| 92245 | * relocation and check that relocation copying works |
| 92246 | */ |
| 92247 | |
| 92248 | DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func, |
| 92249 | duk_realloc_function realloc_func, |
| 92250 | duk_free_function free_func, |
| 92251 | void *udata) { |
| 92252 | duk_uint_t error_count = 0; |
| 92253 | void *ptr; |
| 92254 | void *new_ptr; |
| 92255 | duk_small_int_t i, j; |
| 92256 | unsigned char x; |
| 92257 | |
| 92258 | if (alloc_func == NULL || realloc_func == NULL || free_func == NULL) { |
| 92259 | return 0; |
| 92260 | } |
| 92261 | |
| 92262 | for (i = 1; i <= 256; i++) { |
| 92263 | ptr = alloc_func(udata, (duk_size_t) i); |
| 92264 | if (ptr == NULL) { |
| 92265 | DUK_D(DUK_DPRINT("alloc failed, ignore" )); |
| 92266 | continue; /* alloc failed, ignore */ |
| 92267 | } |
| 92268 | for (j = 0; j < i; j++) { |
| 92269 | ((unsigned char *) ptr)[j] = (unsigned char) (0x80 + j); |
| 92270 | } |
| 92271 | new_ptr = realloc_func(udata, ptr, 1024); |
| 92272 | if (new_ptr == NULL) { |
| 92273 | DUK_D(DUK_DPRINT("realloc failed, ignore" )); |
| 92274 | free_func(udata, ptr); |
| 92275 | continue; /* realloc failed, ignore */ |
| 92276 | } |
| 92277 | ptr = new_ptr; |
| 92278 | for (j = 0; j < i; j++) { |
| 92279 | x = ((unsigned char *) ptr)[j]; |
| 92280 | if (x != (unsigned char) (0x80 + j)) { |
| 92281 | DUK_D(DUK_DPRINT("byte at index %ld doesn't match after realloc: %02lx" , |
| 92282 | (long) j, (unsigned long) x)); |
| 92283 | DUK__FAILED("byte compare after realloc" ); |
| 92284 | break; |
| 92285 | } |
| 92286 | } |
| 92287 | free_func(udata, ptr); |
| 92288 | } |
| 92289 | |
| 92290 | return error_count; |
| 92291 | } |
| 92292 | |
| 92293 | /* |
| 92294 | * Self test main |
| 92295 | */ |
| 92296 | |
| 92297 | DUK_INTERNAL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func, |
| 92298 | duk_realloc_function realloc_func, |
| 92299 | duk_free_function free_func, |
| 92300 | void *udata) { |
| 92301 | duk_uint_t error_count = 0; |
| 92302 | |
| 92303 | DUK_D(DUK_DPRINT("self test starting" )); |
| 92304 | |
| 92305 | error_count += duk__selftest_types(); |
| 92306 | error_count += duk__selftest_packed_tval(); |
| 92307 | error_count += duk__selftest_twos_complement(); |
| 92308 | error_count += duk__selftest_byte_order(); |
| 92309 | error_count += duk__selftest_bswap_macros(); |
| 92310 | error_count += duk__selftest_double_union_size(); |
| 92311 | error_count += duk__selftest_double_aliasing(); |
| 92312 | error_count += duk__selftest_double_zero_sign(); |
| 92313 | error_count += duk__selftest_double_rounding(); |
| 92314 | error_count += duk__selftest_fmod(); |
| 92315 | error_count += duk__selftest_struct_align(); |
| 92316 | error_count += duk__selftest_64bit_arithmetic(); |
| 92317 | error_count += duk__selftest_cast_double_to_small_uint(); |
| 92318 | error_count += duk__selftest_cast_double_to_uint32(); |
| 92319 | error_count += duk__selftest_alloc_funcs(alloc_func, realloc_func, free_func, udata); |
| 92320 | |
| 92321 | DUK_D(DUK_DPRINT("self test complete, total error count: %ld" , (long) error_count)); |
| 92322 | |
| 92323 | return error_count; |
| 92324 | } |
| 92325 | |
| 92326 | #endif /* DUK_USE_SELF_TESTS */ |
| 92327 | |
| 92328 | /* automatic undefs */ |
| 92329 | #undef DUK__DBLUNION_CMP_FALSE |
| 92330 | #undef DUK__DBLUNION_CMP_TRUE |
| 92331 | #undef DUK__DOUBLE_COMPARE |
| 92332 | #undef DUK__DOUBLE_INIT |
| 92333 | #undef DUK__FAILED |
| 92334 | #undef DUK__U32_INIT |
| 92335 | /* #include duk_internal.h -> already included */ |
| 92336 | #line 2 "duk_tval.c" |
| 92337 | |
| 92338 | #if defined(DUK_USE_FASTINT) |
| 92339 | |
| 92340 | /* |
| 92341 | * Manually optimized double-to-fastint downgrade check. |
| 92342 | * |
| 92343 | * This check has a large impact on performance, especially for fastint |
| 92344 | * slow paths, so must be changed carefully. The code should probably be |
| 92345 | * optimized for the case where the result does not fit into a fastint, |
| 92346 | * to minimize the penalty for "slow path code" dealing with fractions etc. |
| 92347 | * |
| 92348 | * At least on one tested soft float ARM platform double-to-int64 coercion |
| 92349 | * is very slow (and sometimes produces incorrect results, see self tests). |
| 92350 | * This algorithm combines a fastint compatibility check and extracting the |
| 92351 | * integer value from an IEEE double for setting the tagged fastint. For |
| 92352 | * other platforms a more naive approach might be better. |
| 92353 | * |
| 92354 | * See doc/fastint.rst for details. |
| 92355 | */ |
| 92356 | |
| 92357 | DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) { |
| 92358 | duk_double_union du; |
| 92359 | duk_int64_t i; |
| 92360 | duk_small_int_t expt; |
| 92361 | duk_small_int_t shift; |
| 92362 | |
| 92363 | /* XXX: optimize for packed duk_tval directly? */ |
| 92364 | |
| 92365 | du.d = x; |
| 92366 | i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du); |
| 92367 | expt = (duk_small_int_t) ((i >> 52) & 0x07ff); |
| 92368 | shift = expt - 1023; |
| 92369 | |
| 92370 | if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */ |
| 92371 | duk_int64_t t; |
| 92372 | |
| 92373 | if (((DUK_I64_CONSTANT(0x000fffffffffffff) >> shift) & i) == 0) { |
| 92374 | t = i | DUK_I64_CONSTANT(0x0010000000000000); /* implicit leading one */ |
| 92375 | t = t & DUK_I64_CONSTANT(0x001fffffffffffff); |
| 92376 | t = t >> (52 - shift); |
| 92377 | if (i < 0) { |
| 92378 | t = -t; |
| 92379 | } |
| 92380 | DUK_TVAL_SET_FASTINT(tv, t); |
| 92381 | return; |
| 92382 | } |
| 92383 | } else if (shift == -1023) { /* exponent 0 */ |
| 92384 | if (i >= 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) { |
| 92385 | /* Note: reject negative zero. */ |
| 92386 | DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0); |
| 92387 | return; |
| 92388 | } |
| 92389 | } else if (shift == 47) { /* exponent 1070 */ |
| 92390 | if (i < 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) { |
| 92391 | DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN); |
| 92392 | return; |
| 92393 | } |
| 92394 | } |
| 92395 | |
| 92396 | DUK_TVAL_SET_DOUBLE(tv, x); |
| 92397 | return; |
| 92398 | } |
| 92399 | |
| 92400 | DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) { |
| 92401 | duk_tval_set_number_chkfast_fast(tv, x); |
| 92402 | } |
| 92403 | |
| 92404 | /* |
| 92405 | * Manually optimized number-to-double conversion |
| 92406 | */ |
| 92407 | |
| 92408 | #if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL) |
| 92409 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) { |
| 92410 | duk_double_union du; |
| 92411 | duk_uint64_t t; |
| 92412 | |
| 92413 | t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv); |
| 92414 | if ((t >> 48) != DUK_TAG_FASTINT) { |
| 92415 | return tv->d; |
| 92416 | } else if (t & DUK_U64_CONSTANT(0x0000800000000000)) { |
| 92417 | t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */ |
| 92418 | t = t & DUK_U64_CONSTANT(0x0000ffffffffffff); /* negative */ |
| 92419 | t |= DUK_U64_CONSTANT(0xc330000000000000); |
| 92420 | DUK_DBLUNION_SET_UINT64(&du, t); |
| 92421 | return du.d + 4503599627370496.0; /* 1 << 52 */ |
| 92422 | } else if (t != 0) { |
| 92423 | t &= DUK_U64_CONSTANT(0x0000ffffffffffff); /* positive */ |
| 92424 | t |= DUK_U64_CONSTANT(0x4330000000000000); |
| 92425 | DUK_DBLUNION_SET_UINT64(&du, t); |
| 92426 | return du.d - 4503599627370496.0; /* 1 << 52 */ |
| 92427 | } else { |
| 92428 | return 0.0; /* zero */ |
| 92429 | } |
| 92430 | } |
| 92431 | #endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */ |
| 92432 | |
| 92433 | #if 0 /* unused */ |
| 92434 | #if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL) |
| 92435 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) { |
| 92436 | duk_double_union du; |
| 92437 | duk_uint64_t t; |
| 92438 | |
| 92439 | DUK_ASSERT(tv->t == DUK_TAG_NUMBER || tv->t == DUK_TAG_FASTINT); |
| 92440 | |
| 92441 | if (tv->t == DUK_TAG_FASTINT) { |
| 92442 | if (tv->v.fi >= 0) { |
| 92443 | t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi; |
| 92444 | DUK_DBLUNION_SET_UINT64(&du, t); |
| 92445 | return du.d - 4503599627370496.0; /* 1 << 52 */ |
| 92446 | } else { |
| 92447 | t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi); |
| 92448 | DUK_DBLUNION_SET_UINT64(&du, t); |
| 92449 | return du.d + 4503599627370496.0; /* 1 << 52 */ |
| 92450 | } |
| 92451 | } else { |
| 92452 | return tv->v.d; |
| 92453 | } |
| 92454 | } |
| 92455 | #endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */ |
| 92456 | #endif /* 0 */ |
| 92457 | |
| 92458 | #if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL) |
| 92459 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) { |
| 92460 | duk_double_union du; |
| 92461 | duk_uint64_t t; |
| 92462 | |
| 92463 | DUK_ASSERT(tv->t == DUK_TAG_FASTINT); |
| 92464 | |
| 92465 | if (tv->v.fi >= 0) { |
| 92466 | t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi; |
| 92467 | DUK_DBLUNION_SET_UINT64(&du, t); |
| 92468 | return du.d - 4503599627370496.0; /* 1 << 52 */ |
| 92469 | } else { |
| 92470 | t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi); |
| 92471 | DUK_DBLUNION_SET_UINT64(&du, t); |
| 92472 | return du.d + 4503599627370496.0; /* 1 << 52 */ |
| 92473 | } |
| 92474 | } |
| 92475 | #endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */ |
| 92476 | |
| 92477 | #endif /* DUK_USE_FASTINT */ |
| 92478 | |
| 92479 | /* |
| 92480 | * Assertion helpers. |
| 92481 | */ |
| 92482 | |
| 92483 | #if defined(DUK_USE_ASSERTIONS) |
| 92484 | DUK_INTERNAL void duk_tval_assert_valid(duk_tval *tv) { |
| 92485 | DUK_ASSERT(tv != NULL); |
| 92486 | } |
| 92487 | #endif |
| 92488 | #line 1 "duk_unicode_tables.c" |
| 92489 | /* |
| 92490 | * Unicode support tables automatically generated during build. |
| 92491 | */ |
| 92492 | |
| 92493 | /* #include duk_internal.h -> already included */ |
| 92494 | |
| 92495 | /* |
| 92496 | * Unicode tables containing ranges of Unicode characters in a |
| 92497 | * packed format. These tables are used to match non-ASCII |
| 92498 | * characters of complex productions by resorting to a linear |
| 92499 | * range-by-range comparison. This is very slow, but is expected |
| 92500 | * to be very rare in practical ECMAScript source code, and thus |
| 92501 | * compactness is most important. |
| 92502 | * |
| 92503 | * The tables are matched using uni_range_match() and the format |
| 92504 | * is described in tools/extract_chars.py. |
| 92505 | */ |
| 92506 | |
| 92507 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 92508 | /* IdentifierStart production with ASCII excluded */ |
| 92509 | /* duk_unicode_ids_noa[] */ |
| 92510 | /* |
| 92511 | * Automatically generated by extract_chars.py, do not edit! |
| 92512 | */ |
| 92513 | |
| 92514 | const duk_uint8_t duk_unicode_ids_noa[1116] = { |
| 92515 | 249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34, |
| 92516 | 2,240,66,244,50,247,185,249,98,241,99,7,241,159,57,240,181,63,31,241,191, |
| 92517 | 21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240, |
| 92518 | 101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115, |
| 92519 | 19,240,98,98,4,52,15,2,14,18,47,0,27,9,85,19,240,98,98,18,18,31,17,50,15,5, |
| 92520 | 47,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16, |
| 92521 | 18,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15, |
| 92522 | 12,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2, |
| 92523 | 6,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,2,66,240,130, |
| 92524 | 2,146,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4, |
| 92525 | 24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,63,17,35, |
| 92526 | 54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,240,18,240, |
| 92527 | 166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244, |
| 92528 | 152,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,240,122, |
| 92529 | 242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,43,241,67, |
| 92530 | 136,241,179,47,27,50,82,20,6,251,15,50,255,224,8,53,63,22,53,55,32,32,32, |
| 92531 | 47,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32, |
| 92532 | 68,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87, |
| 92533 | 52,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254, |
| 92534 | 12,146,240,184,132,52,95,70,114,47,74,35,111,27,47,78,240,63,11,242,127,0, |
| 92535 | 255,224,244,255,240,0,138,143,60,255,240,4,14,47,2,255,227,127,243,95,30, |
| 92536 | 63,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,37,52,242,42, |
| 92537 | 34,35,47,7,240,255,36,240,15,34,243,5,64,33,207,12,191,7,240,191,13,143,31, |
| 92538 | 240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32, |
| 92539 | 240,162,58,130,213,53,53,166,38,47,27,43,159,99,240,255,255,0,26,150,223,7, |
| 92540 | 95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245, |
| 92541 | 207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10, |
| 92542 | 207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37,255, |
| 92543 | 223,13,79,33,242,31,16,239,14,111,22,191,14,63,20,87,36,241,207,142,240,79, |
| 92544 | 20,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241,194,20,3, |
| 92545 | 240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135,31,50,15,1, |
| 92546 | 50,34,240,223,28,240,212,240,223,21,114,240,207,13,242,107,240,107,240,62, |
| 92547 | 240,47,96,243,159,41,242,62,242,62,241,79,254,13,15,13,176,159,6,248,207,7, |
| 92548 | 223,37,243,223,29,241,47,9,240,207,20,240,240,207,19,64,223,32,240,3,240, |
| 92549 | 112,32,241,95,2,47,9,244,102,32,35,46,41,143,31,241,135,49,63,6,38,33,36, |
| 92550 | 64,240,64,212,249,15,37,240,67,240,96,241,47,32,240,97,32,250,175,31,241, |
| 92551 | 179,241,111,32,240,96,242,223,27,224,243,159,11,253,127,28,246,111,48,241, |
| 92552 | 16,249,39,63,23,240,32,32,240,224,191,24,128,240,112,207,30,240,80,241,79, |
| 92553 | 41,255,152,47,21,240,48,242,63,14,246,38,33,47,22,240,112,240,181,33,47,16, |
| 92554 | 240,0,255,224,59,240,63,254,0,31,254,40,207,88,245,255,3,251,79,254,155,15, |
| 92555 | 254,50,31,254,236,95,254,19,159,255,0,16,173,255,225,43,143,15,246,63,14, |
| 92556 | 240,79,32,240,35,241,31,5,111,3,255,225,164,243,15,114,243,182,15,52,207, |
| 92557 | 50,18,15,14,255,240,0,110,169,255,225,229,255,240,1,64,31,254,1,31,35,47,3, |
| 92558 | 57,255,224,126,255,231,248,245,182,196,136,159,255,0,6,90,244,82,243,114, |
| 92559 | 19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,98,255,224,70,63,9,47, |
| 92560 | 9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,232,40,241,219,111,2, |
| 92561 | 15,254,6,95,28,255,228,8,251,95,45,243,72,15,254,58,131,47,11,33,32,48,41, |
| 92562 | 35,32,32,112,80,32,32,34,33,32,48,32,32,32,32,33,32,51,38,35,35,32,41,47,1, |
| 92563 | 98,36,47,1,255,240,0,3,143,255,0,149,201,241,191,254,242,124,252,227,255, |
| 92564 | 240,0,87,79,0,255,240,0,194,63,254,177,63,254,17,0, |
| 92565 | }; |
| 92566 | #else |
| 92567 | /* IdentifierStart production with ASCII and non-BMP excluded */ |
| 92568 | /* duk_unicode_ids_noabmp[] */ |
| 92569 | /* |
| 92570 | * Automatically generated by extract_chars.py, do not edit! |
| 92571 | */ |
| 92572 | |
| 92573 | const duk_uint8_t duk_unicode_ids_noabmp[625] = { |
| 92574 | 249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34, |
| 92575 | 2,240,66,244,50,247,185,249,98,241,99,7,241,159,57,240,181,63,31,241,191, |
| 92576 | 21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240, |
| 92577 | 101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115, |
| 92578 | 19,240,98,98,4,52,15,2,14,18,47,0,27,9,85,19,240,98,98,18,18,31,17,50,15,5, |
| 92579 | 47,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16, |
| 92580 | 18,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15, |
| 92581 | 12,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2, |
| 92582 | 6,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,2,66,240,130, |
| 92583 | 2,146,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4, |
| 92584 | 24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,63,17,35, |
| 92585 | 54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,240,18,240, |
| 92586 | 166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244, |
| 92587 | 152,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,240,122, |
| 92588 | 242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,43,241,67, |
| 92589 | 136,241,179,47,27,50,82,20,6,251,15,50,255,224,8,53,63,22,53,55,32,32,32, |
| 92590 | 47,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32, |
| 92591 | 68,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87, |
| 92592 | 52,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254, |
| 92593 | 12,146,240,184,132,52,95,70,114,47,74,35,111,27,47,78,240,63,11,242,127,0, |
| 92594 | 255,224,244,255,240,0,138,143,60,255,240,4,14,47,2,255,227,127,243,95,30, |
| 92595 | 63,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,37,52,242,42, |
| 92596 | 34,35,47,7,240,255,36,240,15,34,243,5,64,33,207,12,191,7,240,191,13,143,31, |
| 92597 | 240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32, |
| 92598 | 240,162,58,130,213,53,53,166,38,47,27,43,159,99,240,255,255,0,26,150,223,7, |
| 92599 | 95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245, |
| 92600 | 207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10, |
| 92601 | 207,73,69,53,53,50,0, |
| 92602 | }; |
| 92603 | #endif |
| 92604 | |
| 92605 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 92606 | /* IdentifierStart production with Letter and ASCII excluded */ |
| 92607 | /* duk_unicode_ids_m_let_noa[] */ |
| 92608 | /* |
| 92609 | * Automatically generated by extract_chars.py, do not edit! |
| 92610 | */ |
| 92611 | |
| 92612 | const duk_uint8_t duk_unicode_ids_m_let_noa[42] = { |
| 92613 | 255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89, |
| 92614 | 249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,240, |
| 92615 | }; |
| 92616 | #else |
| 92617 | /* IdentifierStart production with Letter, ASCII, and non-BMP excluded */ |
| 92618 | /* duk_unicode_ids_m_let_noabmp[] */ |
| 92619 | /* |
| 92620 | * Automatically generated by extract_chars.py, do not edit! |
| 92621 | */ |
| 92622 | |
| 92623 | const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = { |
| 92624 | 255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89, |
| 92625 | 249,0, |
| 92626 | }; |
| 92627 | #endif |
| 92628 | |
| 92629 | #if defined(DUK_USE_SOURCE_NONBMP) |
| 92630 | /* IdentifierPart production with IdentifierStart and ASCII excluded */ |
| 92631 | /* duk_unicode_idp_m_ids_noa[] */ |
| 92632 | /* |
| 92633 | * Automatically generated by extract_chars.py, do not edit! |
| 92634 | */ |
| 92635 | |
| 92636 | const duk_uint8_t duk_unicode_idp_m_ids_noa[576] = { |
| 92637 | 255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112, |
| 92638 | 245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,160,240,163,40, |
| 92639 | 34,36,241,210,246,158,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50, |
| 92640 | 160,177,57,240,0,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34, |
| 92641 | 240,97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240, |
| 92642 | 9,240,36,242,182,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240, |
| 92643 | 35,242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54, |
| 92644 | 215,41,244,144,56,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160, |
| 92645 | 245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240, |
| 92646 | 241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41, |
| 92647 | 242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12, |
| 92648 | 57,241,237,242,47,4,153,121,246,130,47,5,80,112,50,251,143,42,36,255,225,0, |
| 92649 | 31,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91, |
| 92650 | 31,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161, |
| 92651 | 242,79,2,185,127,2,234,240,231,240,188,241,227,242,29,240,25,192,185,242, |
| 92652 | 29,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, |
| 92653 | 225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,15,254,27,16,253,64, |
| 92654 | 248,116,255,224,25,159,254,68,178,33,99,241,162,80,249,113,255,225,49,57, |
| 92655 | 159,254,16,10,250,18,242,126,241,25,240,19,241,250,242,121,114,241,109,41, |
| 92656 | 97,241,224,210,242,45,147,73,244,75,112,249,43,105,115,242,145,38,49,50, |
| 92657 | 160,177,54,68,251,47,2,169,80,244,63,4,217,252,118,56,240,209,244,79,1,240, |
| 92658 | 25,244,60,153,244,94,89,254,78,249,121,253,150,54,64,240,233,241,166,35, |
| 92659 | 144,170,242,15,0,255,224,137,114,127,2,159,42,240,98,223,108,84,2,18,98,9, |
| 92660 | 159,34,66,18,73,159,254,3,211,255,240,3,165,217,247,132,242,214,240,185, |
| 92661 | 255,226,233,2,242,120,63,255,0,59,254,31,255,0,3,186,68,89,115,111,16,63, |
| 92662 | 134,47,254,71,223,34,255,224,244,242,117,242,41,15,0,15,8,66,239,254,68,70, |
| 92663 | 47,1,54,33,36,255,118,169,255,224,150,223,254,76,166,245,246,105,255,240, |
| 92664 | 192,105,175,224,0, |
| 92665 | }; |
| 92666 | #else |
| 92667 | /* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */ |
| 92668 | /* duk_unicode_idp_m_ids_noabmp[] */ |
| 92669 | /* |
| 92670 | * Automatically generated by extract_chars.py, do not edit! |
| 92671 | */ |
| 92672 | |
| 92673 | const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358] = { |
| 92674 | 255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112, |
| 92675 | 245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,160,240,163,40, |
| 92676 | 34,36,241,210,246,158,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50, |
| 92677 | 160,177,57,240,0,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34, |
| 92678 | 240,97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240, |
| 92679 | 9,240,36,242,182,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240, |
| 92680 | 35,242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54, |
| 92681 | 215,41,244,144,56,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160, |
| 92682 | 245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240, |
| 92683 | 241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41, |
| 92684 | 242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12, |
| 92685 | 57,241,237,242,47,4,153,121,246,130,47,5,80,112,50,251,143,42,36,255,225,0, |
| 92686 | 31,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91, |
| 92687 | 31,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161, |
| 92688 | 242,79,2,185,127,2,234,240,231,240,188,241,227,242,29,240,25,192,185,242, |
| 92689 | 29,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3, |
| 92690 | 225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,0, |
| 92691 | }; |
| 92692 | #endif |
| 92693 | |
| 92694 | /* |
| 92695 | * Case conversion tables generated using tools/extract_caseconv.py. |
| 92696 | */ |
| 92697 | |
| 92698 | /* duk_unicode_caseconv_uc[] */ |
| 92699 | /* duk_unicode_caseconv_lc[] */ |
| 92700 | |
| 92701 | /* |
| 92702 | * Automatically generated by extract_caseconv.py, do not edit! |
| 92703 | */ |
| 92704 | |
| 92705 | const duk_uint8_t duk_unicode_caseconv_uc[1411] = { |
| 92706 | 152,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162, |
| 92707 | 128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30, |
| 92708 | 104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,8,104,14,72,43,16,253, |
| 92709 | 28,189,6,39,240,39,224,24,114,12,16,132,16,248,0,248,64,129,241,1,241,128, |
| 92710 | 195,228,3,229,2,7,204,7,206,4,15,160,15,164,6,31,96,31,104,16,62,224,63, |
| 92711 | 116,8,125,200,127,32,32,251,176,254,208,33,247,129,255,128,67,239,67,253, |
| 92712 | 64,135,223,7,254,129,15,216,15,220,2,31,208,31,216,4,63,192,63,208,8,133, |
| 92713 | 192,133,128,129,38,129,37,177,162,195,2,192,5,229,160,2,20,9,170,220,4,232, |
| 92714 | 40,127,160,255,144,154,136,4,4,4,0,192,9,152,9,144,48,19,160,19,145,0,41, |
| 92715 | 96,41,69,192,94,128,94,65,128,193,128,193,2,1,161,1,160,6,3,104,3,102,8,7, |
| 92716 | 56,7,52,64,14,248,14,240,144,31,144,31,130,128,68,96,68,66,64,145,192,145, |
| 92717 | 130,129,184,129,184,2,3,217,3,216,24,8,194,8,192,68,18,44,18,40,216,38,16, |
| 92718 | 38,8,112,77,16,77,6,3,192,35,192,18,199,168,71,168,24,15,168,143,172,132, |
| 92719 | 44,104,44,103,6,89,2,89,0,200,179,176,179,172,21,50,13,50,1,122,104,26,104, |
| 92720 | 1,212,228,116,228,65,233,204,233,204,143,211,189,83,188,130,167,127,167, |
| 92721 | 126,11,79,35,79,32,10,158,94,158,88,85,61,173,61,160,97,192,107,64,107,1,0, |
| 92722 | 226,128,226,3,1,198,1,196,6,3,228,3,226,8,10,0,6,152,16,31,192,31,184,34, |
| 92723 | 199,50,199,32,65,128,196,0,195,130,1,185,1,184,4,4,205,79,84,8,0,192,143,0, |
| 92724 | 142,193,1,52,128,203,2,45,39,16,199,5,253,0,11,80,57,192,15,240,23,128,19, |
| 92725 | 16,4,144,23,240,5,48,24,0,36,48,25,32,25,16,25,80,31,96,25,144,25,128,25, |
| 92726 | 160,35,208,25,224,34,0,26,128,26,112,27,240,31,112,29,208,24,224,31,48,31, |
| 92727 | 16,37,2,198,240,37,18,198,208,37,34,199,0,37,48,24,16,37,64,24,96,37,144, |
| 92728 | 24,240,37,176,25,0,37,202,122,176,38,0,25,48,38,26,122,192,38,48,25,64,38, |
| 92729 | 90,120,208,38,128,25,112,38,178,198,32,38,202,122,208,39,18,198,224,39,32, |
| 92730 | 25,208,39,80,25,240,39,210,198,64,40,42,124,80,40,122,123,16,40,128,26,224, |
| 92731 | 40,144,36,64,40,192,36,80,41,32,27,112,41,218,123,32,41,234,123,0,52,80,57, |
| 92732 | 144,55,112,55,96,58,192,56,96,60,32,58,48,60,192,56,192,61,0,57,32,61,16, |
| 92733 | 57,128,61,80,58,96,61,96,58,0,61,112,60,240,63,0,57,160,63,16,58,16,63,32, |
| 92734 | 63,144,63,48,55,240,63,80,57,80,76,240,76,1,200,0,65,33,200,16,65,65,200, |
| 92735 | 32,65,225,200,80,66,33,200,96,66,161,200,112,70,33,200,138,100,161,215,154, |
| 92736 | 119,209,215,210,198,49,216,234,124,97,233,177,230,1,251,224,57,145,254,81, |
| 92737 | 254,194,20,226,19,34,24,66,24,50,198,18,198,2,198,80,35,162,198,96,35,226, |
| 92738 | 207,50,207,42,120,202,120,186,121,74,124,74,124,58,124,42,181,58,123,60, |
| 92739 | 192,27,240,2,152,2,152,10,76,5,120,0,156,3,225,0,37,1,134,1,200,96,115,32, |
| 92740 | 97,0,96,32,118,24,29,40,24,64,24,8,44,60,10,106,10,164,61,45,0,36,1,152, |
| 92741 | 143,75,192,10,128,97,3,211,16,2,184,24,80,244,204,0,178,6,20,61,53,0,32, |
| 92742 | 129,95,15,168,64,116,160,98,99,234,88,29,40,24,152,24,0,250,166,7,74,6,38, |
| 92743 | 6,2,62,173,129,210,129,137,129,161,15,192,67,225,0,115,35,240,48,248,72,28, |
| 92744 | 200,252,20,62,20,7,50,63,7,15,133,129,204,143,194,67,225,128,115,35,240, |
| 92745 | 176,248,104,28,200,252,52,62,28,7,50,63,15,15,135,129,204,143,196,67,225,0, |
| 92746 | 115,35,241,48,248,72,28,200,252,84,62,20,7,50,63,23,15,133,129,204,143,198, |
| 92747 | 67,225,128,115,35,241,176,248,104,28,200,252,116,62,28,7,50,63,31,15,135, |
| 92748 | 129,204,143,200,67,229,0,115,35,242,48,249,72,28,200,252,148,62,84,7,50,63, |
| 92749 | 39,15,149,129,204,143,202,67,229,128,115,35,242,176,249,104,28,200,252,180, |
| 92750 | 62,92,7,50,63,47,15,151,129,204,143,204,67,229,0,115,35,243,48,249,72,28, |
| 92751 | 200,252,212,62,84,7,50,63,55,15,149,129,204,143,206,67,229,128,115,35,243, |
| 92752 | 176,249,104,28,200,252,244,62,92,7,50,63,63,15,151,129,204,143,208,67,237, |
| 92753 | 0,115,35,244,48,251,72,28,200,253,20,62,212,7,50,63,71,15,181,129,204,143, |
| 92754 | 210,67,237,128,115,35,244,176,251,104,28,200,253,52,62,220,7,50,63,79,15, |
| 92755 | 183,129,204,143,212,67,237,0,115,35,245,48,251,72,28,200,253,84,62,212,7, |
| 92756 | 50,63,87,15,181,129,204,143,214,67,237,128,115,35,245,176,251,104,28,200, |
| 92757 | 253,116,62,220,7,50,63,95,15,183,129,204,143,217,67,247,64,115,35,246,112, |
| 92758 | 28,136,28,200,253,164,7,12,7,50,63,109,1,200,129,161,15,219,224,114,32,104, |
| 92759 | 64,115,35,247,144,28,136,28,200,254,20,63,148,7,50,63,135,1,203,129,204, |
| 92760 | 143,226,64,113,32,115,35,248,208,28,184,26,16,254,62,7,46,6,132,7,50,63, |
| 92761 | 153,1,203,129,204,143,233,96,115,32,97,0,96,3,250,120,28,200,24,64,24,8, |
| 92762 | 254,180,7,50,6,132,63,175,129,204,129,132,1,161,15,241,96,116,160,97,0,96, |
| 92763 | 3,252,120,29,40,24,64,24,8,255,36,7,66,6,38,63,205,1,210,129,161,15,243, |
| 92764 | 224,116,160,97,0,104,67,254,80,255,208,28,200,255,156,7,82,7,50,63,233,1, |
| 92765 | 199,129,204,143,251,64,117,32,104,67,254,248,29,72,26,16,28,200,255,228,7, |
| 92766 | 82,7,51,246,1,0,35,0,35,125,128,192,8,192,9,63,96,80,2,48,2,103,216,30,0, |
| 92767 | 140,0,140,0,147,246,9,128,35,0,35,0,38,125,130,192,10,96,10,159,96,208,2, |
| 92768 | 152,2,167,216,156,10,136,10,141,246,41,2,162,2,154,253,138,192,168,128,167, |
| 92769 | 127,98,208,42,112,42,55,216,188,10,136,10,122, |
| 92770 | }; |
| 92771 | const duk_uint8_t duk_unicode_caseconv_lc[706] = { |
| 92772 | 160,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0, |
| 92773 | 235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32, |
| 92774 | 0,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,9,208,85,184,80,19, |
| 92775 | 240,19,248,12,57,32,33,160,172,114,244,67,244,24,248,64,248,0,129,241,129, |
| 92776 | 241,0,195,229,3,228,2,7,206,7,204,4,15,164,15,160,6,31,104,31,96,16,63,16, |
| 92777 | 63,0,32,126,96,126,64,64,253,64,253,0,129,251,129,251,0,67,247,67,238,0, |
| 92778 | 135,242,7,220,130,15,236,15,232,2,31,218,31,118,4,63,208,63,192,8,127,168, |
| 92779 | 125,232,16,255,192,251,192,33,255,161,247,192,68,44,4,46,4,9,45,137,52,13, |
| 92780 | 22,0,22,24,47,44,126,2,63,5,254,67,254,130,106,48,16,0,16,19,0,38,64,38,96, |
| 92781 | 192,78,64,78,132,0,165,0,165,151,1,121,1,122,6,3,4,3,6,8,6,128,6,132,24,13, |
| 92782 | 152,13,160,32,28,176,28,193,32,59,192,59,226,64,124,128,124,193,0,252,0, |
| 92783 | 252,148,2,34,2,35,18,4,140,4,142,20,13,192,13,196,16,30,192,30,200,192,70, |
| 92784 | 0,70,18,32,145,64,145,102,193,48,65,48,131,130,104,2,104,176,30,0,30,1,150, |
| 92785 | 61,64,61,66,192,125,100,125,68,33,99,57,99,64,50,200,2,200,22,69,157,101, |
| 92786 | 157,128,169,144,41,144,75,211,64,83,64,142,167,34,167,35,15,78,101,78,102, |
| 92787 | 126,157,230,157,232,21,59,245,59,248,90,121,10,121,16,84,242,212,242,226, |
| 92788 | 169,237,41,237,67,12,3,76,5,0,8,6,176,6,180,16,14,32,14,48,48,28,80,28,96, |
| 92789 | 64,126,224,127,0,139,28,139,28,193,6,3,14,3,16,8,6,224,6,228,21,61,80,19, |
| 92790 | 48,32,3,1,150,2,105,4,4,118,4,120,8,67,28,180,156,23,240,192,94,0,63,192, |
| 92791 | 96,64,148,192,97,128,149,0,99,128,119,64,99,192,150,64,100,0,150,192,100, |
| 92792 | 64,100,128,100,192,152,0,101,0,152,192,101,192,154,0,102,0,102,64,103,64, |
| 92793 | 156,128,103,192,157,64,105,192,106,0,107,128,162,0,109,192,164,128,124,64, |
| 92794 | 124,192,125,128,101,64,125,192,111,192,136,0,103,128,142,139,25,64,143,64, |
| 92795 | 102,128,143,139,25,128,144,192,96,0,145,0,162,64,145,64,163,0,221,128,221, |
| 92796 | 192,223,192,252,192,225,128,235,0,227,0,243,0,243,192,245,192,253,0,238,0, |
| 92797 | 254,64,252,129,48,1,51,199,167,128,55,199,239,7,236,199,243,7,240,199,251, |
| 92798 | 7,249,71,255,7,252,200,73,128,242,72,74,128,26,200,74,192,57,72,76,136,83, |
| 92799 | 136,96,200,97,11,24,11,24,75,24,128,154,203,24,199,95,75,25,0,159,75,27,64, |
| 92800 | 148,75,27,128,156,75,27,192,148,11,28,0,148,139,60,139,60,233,223,71,94, |
| 92801 | 105,226,233,227,41,227,64,153,105,234,192,151,41,235,0,152,105,235,64,155, |
| 92802 | 41,236,0,167,169,236,64,161,233,236,128,167,105,236,234,212,233,240,169, |
| 92803 | 240,233,241,41,229,41,241,64,160,169,241,135,99,128,128,152,64,13,32,96, |
| 92804 | 224, |
| 92805 | }; |
| 92806 | |
| 92807 | #if defined(DUK_USE_REGEXP_CANON_WORKAROUND) |
| 92808 | /* |
| 92809 | * Automatically generated by extract_caseconv.py, do not edit! |
| 92810 | */ |
| 92811 | |
| 92812 | const duk_uint16_t duk_unicode_re_canon_lookup[65536] = { |
| 92813 | 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, |
| 92814 | 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52, |
| 92815 | 53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77, |
| 92816 | 78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70, |
| 92817 | 71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,123,124,125, |
| 92818 | 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, |
| 92819 | 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161, |
| 92820 | 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179, |
| 92821 | 180,924,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197, |
| 92822 | 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215, |
| 92823 | 216,217,218,219,220,221,222,223,192,193,194,195,196,197,198,199,200,201, |
| 92824 | 202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219, |
| 92825 | 220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268, |
| 92826 | 270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286, |
| 92827 | 288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305, |
| 92828 | 306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323, |
| 92829 | 323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340, |
| 92830 | 342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358, |
| 92831 | 360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377, |
| 92832 | 377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395, |
| 92833 | 395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413, |
| 92834 | 544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431, |
| 92835 | 431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449, |
| 92836 | 450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467, |
| 92837 | 467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484, |
| 92838 | 486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503, |
| 92839 | 504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520, |
| 92840 | 522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538, |
| 92841 | 540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556, |
| 92842 | 558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390, |
| 92843 | 11391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375, |
| 92844 | 11373,11376,385,390,597,393,394,600,399,602,400,42923L,605,606,607,403, |
| 92845 | 42924L,610,404,612,42893L,42922L,615,407,406,42926L,11362,42925L,621,622, |
| 92846 | 412,624,11374,413,627,628,415,630,631,632,633,634,635,636,11364,638,639, |
| 92847 | 422,641,42949L,425,644,645,646,42929L,430,580,433,434,581,653,654,655,656, |
| 92848 | 657,439,659,660,661,662,663,664,665,666,667,668,42930L,42928L,671,672,673, |
| 92849 | 674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691, |
| 92850 | 692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709, |
| 92851 | 710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727, |
| 92852 | 728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745, |
| 92853 | 746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763, |
| 92854 | 764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781, |
| 92855 | 782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799, |
| 92856 | 800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817, |
| 92857 | 818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835, |
| 92858 | 836,921,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853, |
| 92859 | 854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871, |
| 92860 | 872,873,874,875,876,877,878,879,880,880,882,882,884,885,886,886,888,889, |
| 92861 | 890,1021,1022,1023,894,895,896,897,898,899,900,901,902,903,904,905,906,907, |
| 92862 | 908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925, |
| 92863 | 926,927,928,929,930,931,932,933,934,935,936,937,938,939,902,904,905,906, |
| 92864 | 944,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929, |
| 92865 | 931,931,932,933,934,935,936,937,938,939,908,910,911,975,914,920,978,979, |
| 92866 | 980,934,928,975,984,984,986,986,988,988,990,990,992,992,994,994,996,996, |
| 92867 | 998,998,1000,1000,1002,1002,1004,1004,1006,1006,922,929,1017,895,1012,917, |
| 92868 | 1014,1015,1015,1017,1018,1018,1020,1021,1022,1023,1024,1025,1026,1027,1028, |
| 92869 | 1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043, |
| 92870 | 1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058, |
| 92871 | 1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1040,1041, |
| 92872 | 1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056, |
| 92873 | 1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071, |
| 92874 | 1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038, |
| 92875 | 1039,1120,1120,1122,1122,1124,1124,1126,1126,1128,1128,1130,1130,1132,1132, |
| 92876 | 1134,1134,1136,1136,1138,1138,1140,1140,1142,1142,1144,1144,1146,1146,1148, |
| 92877 | 1148,1150,1150,1152,1152,1154,1155,1156,1157,1158,1159,1160,1161,1162,1162, |
| 92878 | 1164,1164,1166,1166,1168,1168,1170,1170,1172,1172,1174,1174,1176,1176,1178, |
| 92879 | 1178,1180,1180,1182,1182,1184,1184,1186,1186,1188,1188,1190,1190,1192,1192, |
| 92880 | 1194,1194,1196,1196,1198,1198,1200,1200,1202,1202,1204,1204,1206,1206,1208, |
| 92881 | 1208,1210,1210,1212,1212,1214,1214,1216,1217,1217,1219,1219,1221,1221,1223, |
| 92882 | 1223,1225,1225,1227,1227,1229,1229,1216,1232,1232,1234,1234,1236,1236,1238, |
| 92883 | 1238,1240,1240,1242,1242,1244,1244,1246,1246,1248,1248,1250,1250,1252,1252, |
| 92884 | 1254,1254,1256,1256,1258,1258,1260,1260,1262,1262,1264,1264,1266,1266,1268, |
| 92885 | 1268,1270,1270,1272,1272,1274,1274,1276,1276,1278,1278,1280,1280,1282,1282, |
| 92886 | 1284,1284,1286,1286,1288,1288,1290,1290,1292,1292,1294,1294,1296,1296,1298, |
| 92887 | 1298,1300,1300,1302,1302,1304,1304,1306,1306,1308,1308,1310,1310,1312,1312, |
| 92888 | 1314,1314,1316,1316,1318,1318,1320,1320,1322,1322,1324,1324,1326,1326,1328, |
| 92889 | 1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343, |
| 92890 | 1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358, |
| 92891 | 1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373, |
| 92892 | 1374,1375,1376,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340, |
| 92893 | 1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355, |
| 92894 | 1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1415,1416,1417,1418, |
| 92895 | 1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433, |
| 92896 | 1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448, |
| 92897 | 1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463, |
| 92898 | 1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478, |
| 92899 | 1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493, |
| 92900 | 1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508, |
| 92901 | 1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523, |
| 92902 | 1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538, |
| 92903 | 1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553, |
| 92904 | 1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568, |
| 92905 | 1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583, |
| 92906 | 1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598, |
| 92907 | 1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613, |
| 92908 | 1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628, |
| 92909 | 1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643, |
| 92910 | 1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658, |
| 92911 | 1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673, |
| 92912 | 1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688, |
| 92913 | 1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703, |
| 92914 | 1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718, |
| 92915 | 1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733, |
| 92916 | 1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748, |
| 92917 | 1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763, |
| 92918 | 1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778, |
| 92919 | 1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793, |
| 92920 | 1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808, |
| 92921 | 1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823, |
| 92922 | 1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838, |
| 92923 | 1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853, |
| 92924 | 1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868, |
| 92925 | 1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883, |
| 92926 | 1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898, |
| 92927 | 1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913, |
| 92928 | 1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928, |
| 92929 | 1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943, |
| 92930 | 1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958, |
| 92931 | 1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973, |
| 92932 | 1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988, |
| 92933 | 1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003, |
| 92934 | 2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018, |
| 92935 | 2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033, |
| 92936 | 2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048, |
| 92937 | 2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063, |
| 92938 | 2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078, |
| 92939 | 2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093, |
| 92940 | 2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108, |
| 92941 | 2109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123, |
| 92942 | 2124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138, |
| 92943 | 2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153, |
| 92944 | 2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168, |
| 92945 | 2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183, |
| 92946 | 2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198, |
| 92947 | 2199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213, |
| 92948 | 2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228, |
| 92949 | 2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243, |
| 92950 | 2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258, |
| 92951 | 2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273, |
| 92952 | 2274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288, |
| 92953 | 2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303, |
| 92954 | 2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318, |
| 92955 | 2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333, |
| 92956 | 2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348, |
| 92957 | 2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363, |
| 92958 | 2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378, |
| 92959 | 2379,2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393, |
| 92960 | 2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408, |
| 92961 | 2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423, |
| 92962 | 2424,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438, |
| 92963 | 2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453, |
| 92964 | 2454,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468, |
| 92965 | 2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483, |
| 92966 | 2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498, |
| 92967 | 2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513, |
| 92968 | 2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528, |
| 92969 | 2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543, |
| 92970 | 2544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558, |
| 92971 | 2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573, |
| 92972 | 2574,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588, |
| 92973 | 2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603, |
| 92974 | 2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618, |
| 92975 | 2619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633, |
| 92976 | 2634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648, |
| 92977 | 2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663, |
| 92978 | 2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678, |
| 92979 | 2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693, |
| 92980 | 2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708, |
| 92981 | 2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723, |
| 92982 | 2724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738, |
| 92983 | 2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753, |
| 92984 | 2754,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768, |
| 92985 | 2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783, |
| 92986 | 2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798, |
| 92987 | 2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813, |
| 92988 | 2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828, |
| 92989 | 2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843, |
| 92990 | 2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858, |
| 92991 | 2859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873, |
| 92992 | 2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888, |
| 92993 | 2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903, |
| 92994 | 2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918, |
| 92995 | 2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933, |
| 92996 | 2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948, |
| 92997 | 2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963, |
| 92998 | 2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978, |
| 92999 | 2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993, |
| 93000 | 2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008, |
| 93001 | 3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023, |
| 93002 | 3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038, |
| 93003 | 3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053, |
| 93004 | 3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068, |
| 93005 | 3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083, |
| 93006 | 3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098, |
| 93007 | 3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113, |
| 93008 | 3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128, |
| 93009 | 3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143, |
| 93010 | 3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158, |
| 93011 | 3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173, |
| 93012 | 3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188, |
| 93013 | 3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203, |
| 93014 | 3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218, |
| 93015 | 3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233, |
| 93016 | 3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248, |
| 93017 | 3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263, |
| 93018 | 3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278, |
| 93019 | 3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293, |
| 93020 | 3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308, |
| 93021 | 3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323, |
| 93022 | 3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338, |
| 93023 | 3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353, |
| 93024 | 3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368, |
| 93025 | 3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383, |
| 93026 | 3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398, |
| 93027 | 3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413, |
| 93028 | 3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428, |
| 93029 | 3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443, |
| 93030 | 3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458, |
| 93031 | 3459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473, |
| 93032 | 3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488, |
| 93033 | 3489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503, |
| 93034 | 3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518, |
| 93035 | 3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533, |
| 93036 | 3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548, |
| 93037 | 3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563, |
| 93038 | 3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578, |
| 93039 | 3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593, |
| 93040 | 3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608, |
| 93041 | 3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623, |
| 93042 | 3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638, |
| 93043 | 3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653, |
| 93044 | 3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668, |
| 93045 | 3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683, |
| 93046 | 3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698, |
| 93047 | 3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713, |
| 93048 | 3714,3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728, |
| 93049 | 3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743, |
| 93050 | 3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758, |
| 93051 | 3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773, |
| 93052 | 3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788, |
| 93053 | 3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803, |
| 93054 | 3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818, |
| 93055 | 3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833, |
| 93056 | 3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848, |
| 93057 | 3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863, |
| 93058 | 3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878, |
| 93059 | 3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893, |
| 93060 | 3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908, |
| 93061 | 3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923, |
| 93062 | 3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938, |
| 93063 | 3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953, |
| 93064 | 3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968, |
| 93065 | 3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983, |
| 93066 | 3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998, |
| 93067 | 3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013, |
| 93068 | 4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028, |
| 93069 | 4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043, |
| 93070 | 4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058, |
| 93071 | 4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073, |
| 93072 | 4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088, |
| 93073 | 4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103, |
| 93074 | 4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118, |
| 93075 | 4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133, |
| 93076 | 4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148, |
| 93077 | 4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163, |
| 93078 | 4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178, |
| 93079 | 4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193, |
| 93080 | 4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208, |
| 93081 | 4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223, |
| 93082 | 4224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238, |
| 93083 | 4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253, |
| 93084 | 4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268, |
| 93085 | 4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283, |
| 93086 | 4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298, |
| 93087 | 4299,4300,4301,4302,4303,7312,7313,7314,7315,7316,7317,7318,7319,7320,7321, |
| 93088 | 7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,7334,7335,7336, |
| 93089 | 7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351, |
| 93090 | 7352,7353,7354,4347,4348,7357,7358,7359,4352,4353,4354,4355,4356,4357,4358, |
| 93091 | 4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373, |
| 93092 | 4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388, |
| 93093 | 4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403, |
| 93094 | 4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418, |
| 93095 | 4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433, |
| 93096 | 4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448, |
| 93097 | 4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463, |
| 93098 | 4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478, |
| 93099 | 4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493, |
| 93100 | 4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508, |
| 93101 | 4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523, |
| 93102 | 4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538, |
| 93103 | 4539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553, |
| 93104 | 4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568, |
| 93105 | 4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583, |
| 93106 | 4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598, |
| 93107 | 4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613, |
| 93108 | 4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628, |
| 93109 | 4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643, |
| 93110 | 4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658, |
| 93111 | 4659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673, |
| 93112 | 4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688, |
| 93113 | 4689,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703, |
| 93114 | 4704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718, |
| 93115 | 4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733, |
| 93116 | 4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748, |
| 93117 | 4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763, |
| 93118 | 4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778, |
| 93119 | 4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793, |
| 93120 | 4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808, |
| 93121 | 4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823, |
| 93122 | 4824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838, |
| 93123 | 4839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853, |
| 93124 | 4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868, |
| 93125 | 4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883, |
| 93126 | 4884,4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898, |
| 93127 | 4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913, |
| 93128 | 4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928, |
| 93129 | 4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943, |
| 93130 | 4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958, |
| 93131 | 4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973, |
| 93132 | 4974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988, |
| 93133 | 4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003, |
| 93134 | 5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018, |
| 93135 | 5019,5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033, |
| 93136 | 5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048, |
| 93137 | 5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063, |
| 93138 | 5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078, |
| 93139 | 5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093, |
| 93140 | 5094,5095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108, |
| 93141 | 5109,5110,5111,5104,5105,5106,5107,5108,5109,5118,5119,5120,5121,5122,5123, |
| 93142 | 5124,5125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138, |
| 93143 | 5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153, |
| 93144 | 5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168, |
| 93145 | 5169,5170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183, |
| 93146 | 5184,5185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198, |
| 93147 | 5199,5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213, |
| 93148 | 5214,5215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228, |
| 93149 | 5229,5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243, |
| 93150 | 5244,5245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258, |
| 93151 | 5259,5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273, |
| 93152 | 5274,5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288, |
| 93153 | 5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303, |
| 93154 | 5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318, |
| 93155 | 5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333, |
| 93156 | 5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348, |
| 93157 | 5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, |
| 93158 | 5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378, |
| 93159 | 5379,5380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393, |
| 93160 | 5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, |
| 93161 | 5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423, |
| 93162 | 5424,5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438, |
| 93163 | 5439,5440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453, |
| 93164 | 5454,5455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468, |
| 93165 | 5469,5470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483, |
| 93166 | 5484,5485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498, |
| 93167 | 5499,5500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513, |
| 93168 | 5514,5515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528, |
| 93169 | 5529,5530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543, |
| 93170 | 5544,5545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558, |
| 93171 | 5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573, |
| 93172 | 5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588, |
| 93173 | 5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603, |
| 93174 | 5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618, |
| 93175 | 5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633, |
| 93176 | 5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, |
| 93177 | 5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663, |
| 93178 | 5664,5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678, |
| 93179 | 5679,5680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693, |
| 93180 | 5694,5695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708, |
| 93181 | 5709,5710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723, |
| 93182 | 5724,5725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738, |
| 93183 | 5739,5740,5741,5742,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753, |
| 93184 | 5754,5755,5756,5757,5758,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768, |
| 93185 | 5769,5770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783, |
| 93186 | 5784,5785,5786,5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798, |
| 93187 | 5799,5800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813, |
| 93188 | 5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828, |
| 93189 | 5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843, |
| 93190 | 5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858, |
| 93191 | 5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873, |
| 93192 | 5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, |
| 93193 | 5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903, |
| 93194 | 5904,5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918, |
| 93195 | 5919,5920,5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933, |
| 93196 | 5934,5935,5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948, |
| 93197 | 5949,5950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963, |
| 93198 | 5964,5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978, |
| 93199 | 5979,5980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993, |
| 93200 | 5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008, |
| 93201 | 6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023, |
| 93202 | 6024,6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038, |
| 93203 | 6039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053, |
| 93204 | 6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068, |
| 93205 | 6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083, |
| 93206 | 6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098, |
| 93207 | 6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113, |
| 93208 | 6114,6115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128, |
| 93209 | 6129,6130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143, |
| 93210 | 6144,6145,6146,6147,6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158, |
| 93211 | 6159,6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173, |
| 93212 | 6174,6175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188, |
| 93213 | 6189,6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203, |
| 93214 | 6204,6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218, |
| 93215 | 6219,6220,6221,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233, |
| 93216 | 6234,6235,6236,6237,6238,6239,6240,6241,6242,6243,6244,6245,6246,6247,6248, |
| 93217 | 6249,6250,6251,6252,6253,6254,6255,6256,6257,6258,6259,6260,6261,6262,6263, |
| 93218 | 6264,6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6276,6277,6278, |
| 93219 | 6279,6280,6281,6282,6283,6284,6285,6286,6287,6288,6289,6290,6291,6292,6293, |
| 93220 | 6294,6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305,6306,6307,6308, |
| 93221 | 6309,6310,6311,6312,6313,6314,6315,6316,6317,6318,6319,6320,6321,6322,6323, |
| 93222 | 6324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338, |
| 93223 | 6339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353, |
| 93224 | 6354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368, |
| 93225 | 6369,6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,6383, |
| 93226 | 6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398, |
| 93227 | 6399,6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411,6412,6413, |
| 93228 | 6414,6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,6426,6427,6428, |
| 93229 | 6429,6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443, |
| 93230 | 6444,6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458, |
| 93231 | 6459,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473, |
| 93232 | 6474,6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488, |
| 93233 | 6489,6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503, |
| 93234 | 6504,6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518, |
| 93235 | 6519,6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533, |
| 93236 | 6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548, |
| 93237 | 6549,6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563, |
| 93238 | 6564,6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578, |
| 93239 | 6579,6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593, |
| 93240 | 6594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608, |
| 93241 | 6609,6610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6620,6621,6622,6623, |
| 93242 | 6624,6625,6626,6627,6628,6629,6630,6631,6632,6633,6634,6635,6636,6637,6638, |
| 93243 | 6639,6640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6652,6653, |
| 93244 | 6654,6655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668, |
| 93245 | 6669,6670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683, |
| 93246 | 6684,6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,6698, |
| 93247 | 6699,6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713, |
| 93248 | 6714,6715,6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728, |
| 93249 | 6729,6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6741,6742,6743, |
| 93250 | 6744,6745,6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758, |
| 93251 | 6759,6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773, |
| 93252 | 6774,6775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788, |
| 93253 | 6789,6790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803, |
| 93254 | 6804,6805,6806,6807,6808,6809,6810,6811,6812,6813,6814,6815,6816,6817,6818, |
| 93255 | 6819,6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833, |
| 93256 | 6834,6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848, |
| 93257 | 6849,6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863, |
| 93258 | 6864,6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,6878, |
| 93259 | 6879,6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893, |
| 93260 | 6894,6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908, |
| 93261 | 6909,6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923, |
| 93262 | 6924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938, |
| 93263 | 6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953, |
| 93264 | 6954,6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968, |
| 93265 | 6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983, |
| 93266 | 6984,6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,6998, |
| 93267 | 6999,7000,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013, |
| 93268 | 7014,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028, |
| 93269 | 7029,7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042,7043, |
| 93270 | 7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058, |
| 93271 | 7059,7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073, |
| 93272 | 7074,7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088, |
| 93273 | 7089,7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103, |
| 93274 | 7104,7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118, |
| 93275 | 7119,7120,7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133, |
| 93276 | 7134,7135,7136,7137,7138,7139,7140,7141,7142,7143,7144,7145,7146,7147,7148, |
| 93277 | 7149,7150,7151,7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163, |
| 93278 | 7164,7165,7166,7167,7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178, |
| 93279 | 7179,7180,7181,7182,7183,7184,7185,7186,7187,7188,7189,7190,7191,7192,7193, |
| 93280 | 7194,7195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208, |
| 93281 | 7209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223, |
| 93282 | 7224,7225,7226,7227,7228,7229,7230,7231,7232,7233,7234,7235,7236,7237,7238, |
| 93283 | 7239,7240,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253, |
| 93284 | 7254,7255,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,7267,7268, |
| 93285 | 7269,7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283, |
| 93286 | 7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,1042,1044,1054, |
| 93287 | 1057,1058,1058,1066,1122,42570L,7305,7306,7307,7308,7309,7310,7311,7312, |
| 93288 | 7313,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327, |
| 93289 | 7328,7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342, |
| 93290 | 7343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357, |
| 93291 | 7358,7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372, |
| 93292 | 7373,7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387, |
| 93293 | 7388,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402, |
| 93294 | 7403,7404,7405,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415,7416,7417, |
| 93295 | 7418,7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431,7432, |
| 93296 | 7433,7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447, |
| 93297 | 7448,7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462, |
| 93298 | 7463,7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,7475,7476,7477, |
| 93299 | 7478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492, |
| 93300 | 7493,7494,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507, |
| 93301 | 7508,7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,7522, |
| 93302 | 7523,7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537, |
| 93303 | 7538,7539,7540,7541,7542,7543,7544,42877L,7546,7547,7548,11363,7550,7551, |
| 93304 | 7552,7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565, |
| 93305 | 42950L,7567,7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579, |
| 93306 | 7580,7581,7582,7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594, |
| 93307 | 7595,7596,7597,7598,7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609, |
| 93308 | 7610,7611,7612,7613,7614,7615,7616,7617,7618,7619,7620,7621,7622,7623,7624, |
| 93309 | 7625,7626,7627,7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639, |
| 93310 | 7640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654, |
| 93311 | 7655,7656,7657,7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669, |
| 93312 | 7670,7671,7672,7673,7674,7675,7676,7677,7678,7679,7680,7680,7682,7682,7684, |
| 93313 | 7684,7686,7686,7688,7688,7690,7690,7692,7692,7694,7694,7696,7696,7698,7698, |
| 93314 | 7700,7700,7702,7702,7704,7704,7706,7706,7708,7708,7710,7710,7712,7712,7714, |
| 93315 | 7714,7716,7716,7718,7718,7720,7720,7722,7722,7724,7724,7726,7726,7728,7728, |
| 93316 | 7730,7730,7732,7732,7734,7734,7736,7736,7738,7738,7740,7740,7742,7742,7744, |
| 93317 | 7744,7746,7746,7748,7748,7750,7750,7752,7752,7754,7754,7756,7756,7758,7758, |
| 93318 | 7760,7760,7762,7762,7764,7764,7766,7766,7768,7768,7770,7770,7772,7772,7774, |
| 93319 | 7774,7776,7776,7778,7778,7780,7780,7782,7782,7784,7784,7786,7786,7788,7788, |
| 93320 | 7790,7790,7792,7792,7794,7794,7796,7796,7798,7798,7800,7800,7802,7802,7804, |
| 93321 | 7804,7806,7806,7808,7808,7810,7810,7812,7812,7814,7814,7816,7816,7818,7818, |
| 93322 | 7820,7820,7822,7822,7824,7824,7826,7826,7828,7828,7830,7831,7832,7833,7834, |
| 93323 | 7776,7836,7837,7838,7839,7840,7840,7842,7842,7844,7844,7846,7846,7848,7848, |
| 93324 | 7850,7850,7852,7852,7854,7854,7856,7856,7858,7858,7860,7860,7862,7862,7864, |
| 93325 | 7864,7866,7866,7868,7868,7870,7870,7872,7872,7874,7874,7876,7876,7878,7878, |
| 93326 | 7880,7880,7882,7882,7884,7884,7886,7886,7888,7888,7890,7890,7892,7892,7894, |
| 93327 | 7894,7896,7896,7898,7898,7900,7900,7902,7902,7904,7904,7906,7906,7908,7908, |
| 93328 | 7910,7910,7912,7912,7914,7914,7916,7916,7918,7918,7920,7920,7922,7922,7924, |
| 93329 | 7924,7926,7926,7928,7928,7930,7930,7932,7932,7934,7934,7944,7945,7946,7947, |
| 93330 | 7948,7949,7950,7951,7944,7945,7946,7947,7948,7949,7950,7951,7960,7961,7962, |
| 93331 | 7963,7964,7965,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7976,7977, |
| 93332 | 7978,7979,7980,7981,7982,7983,7976,7977,7978,7979,7980,7981,7982,7983,7992, |
| 93333 | 7993,7994,7995,7996,7997,7998,7999,7992,7993,7994,7995,7996,7997,7998,7999, |
| 93334 | 8008,8009,8010,8011,8012,8013,8006,8007,8008,8009,8010,8011,8012,8013,8014, |
| 93335 | 8015,8016,8025,8018,8027,8020,8029,8022,8031,8024,8025,8026,8027,8028,8029, |
| 93336 | 8030,8031,8040,8041,8042,8043,8044,8045,8046,8047,8040,8041,8042,8043,8044, |
| 93337 | 8045,8046,8047,8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171, |
| 93338 | 8186,8187,8062,8063,8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074, |
| 93339 | 8075,8076,8077,8078,8079,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089, |
| 93340 | 8090,8091,8092,8093,8094,8095,8096,8097,8098,8099,8100,8101,8102,8103,8104, |
| 93341 | 8105,8106,8107,8108,8109,8110,8111,8120,8121,8114,8115,8116,8117,8118,8119, |
| 93342 | 8120,8121,8122,8123,8124,8125,921,8127,8128,8129,8130,8131,8132,8133,8134, |
| 93343 | 8135,8136,8137,8138,8139,8140,8141,8142,8143,8152,8153,8146,8147,8148,8149, |
| 93344 | 8150,8151,8152,8153,8154,8155,8156,8157,8158,8159,8168,8169,8162,8163,8164, |
| 93345 | 8172,8166,8167,8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179, |
| 93346 | 8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194, |
| 93347 | 8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209, |
| 93348 | 8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224, |
| 93349 | 8225,8226,8227,8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239, |
| 93350 | 8240,8241,8242,8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254, |
| 93351 | 8255,8256,8257,8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269, |
| 93352 | 8270,8271,8272,8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284, |
| 93353 | 8285,8286,8287,8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299, |
| 93354 | 8300,8301,8302,8303,8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314, |
| 93355 | 8315,8316,8317,8318,8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329, |
| 93356 | 8330,8331,8332,8333,8334,8335,8336,8337,8338,8339,8340,8341,8342,8343,8344, |
| 93357 | 8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359, |
| 93358 | 8360,8361,8362,8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373,8374, |
| 93359 | 8375,8376,8377,8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389, |
| 93360 | 8390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404, |
| 93361 | 8405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419, |
| 93362 | 8420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434, |
| 93363 | 8435,8436,8437,8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449, |
| 93364 | 8450,8451,8452,8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464, |
| 93365 | 8465,8466,8467,8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479, |
| 93366 | 8480,8481,8482,8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494, |
| 93367 | 8495,8496,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509, |
| 93368 | 8510,8511,8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524, |
| 93369 | 8525,8498,8527,8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539, |
| 93370 | 8540,8541,8542,8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554, |
| 93371 | 8555,8556,8557,8558,8559,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553, |
| 93372 | 8554,8555,8556,8557,8558,8559,8576,8577,8578,8579,8579,8581,8582,8583,8584, |
| 93373 | 8585,8586,8587,8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599, |
| 93374 | 8600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614, |
| 93375 | 8615,8616,8617,8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629, |
| 93376 | 8630,8631,8632,8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644, |
| 93377 | 8645,8646,8647,8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659, |
| 93378 | 8660,8661,8662,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674, |
| 93379 | 8675,8676,8677,8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689, |
| 93380 | 8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704, |
| 93381 | 8705,8706,8707,8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719, |
| 93382 | 8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734, |
| 93383 | 8735,8736,8737,8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749, |
| 93384 | 8750,8751,8752,8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,8764, |
| 93385 | 8765,8766,8767,8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779, |
| 93386 | 8780,8781,8782,8783,8784,8785,8786,8787,8788,8789,8790,8791,8792,8793,8794, |
| 93387 | 8795,8796,8797,8798,8799,8800,8801,8802,8803,8804,8805,8806,8807,8808,8809, |
| 93388 | 8810,8811,8812,8813,8814,8815,8816,8817,8818,8819,8820,8821,8822,8823,8824, |
| 93389 | 8825,8826,8827,8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839, |
| 93390 | 8840,8841,8842,8843,8844,8845,8846,8847,8848,8849,8850,8851,8852,8853,8854, |
| 93391 | 8855,8856,8857,8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869, |
| 93392 | 8870,8871,8872,8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884, |
| 93393 | 8885,8886,8887,8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899, |
| 93394 | 8900,8901,8902,8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914, |
| 93395 | 8915,8916,8917,8918,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929, |
| 93396 | 8930,8931,8932,8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,8944, |
| 93397 | 8945,8946,8947,8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959, |
| 93398 | 8960,8961,8962,8963,8964,8965,8966,8967,8968,8969,8970,8971,8972,8973,8974, |
| 93399 | 8975,8976,8977,8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989, |
| 93400 | 8990,8991,8992,8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004, |
| 93401 | 9005,9006,9007,9008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019, |
| 93402 | 9020,9021,9022,9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034, |
| 93403 | 9035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049, |
| 93404 | 9050,9051,9052,9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064, |
| 93405 | 9065,9066,9067,9068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079, |
| 93406 | 9080,9081,9082,9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094, |
| 93407 | 9095,9096,9097,9098,9099,9100,9101,9102,9103,9104,9105,9106,9107,9108,9109, |
| 93408 | 9110,9111,9112,9113,9114,9115,9116,9117,9118,9119,9120,9121,9122,9123,9124, |
| 93409 | 9125,9126,9127,9128,9129,9130,9131,9132,9133,9134,9135,9136,9137,9138,9139, |
| 93410 | 9140,9141,9142,9143,9144,9145,9146,9147,9148,9149,9150,9151,9152,9153,9154, |
| 93411 | 9155,9156,9157,9158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169, |
| 93412 | 9170,9171,9172,9173,9174,9175,9176,9177,9178,9179,9180,9181,9182,9183,9184, |
| 93413 | 9185,9186,9187,9188,9189,9190,9191,9192,9193,9194,9195,9196,9197,9198,9199, |
| 93414 | 9200,9201,9202,9203,9204,9205,9206,9207,9208,9209,9210,9211,9212,9213,9214, |
| 93415 | 9215,9216,9217,9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229, |
| 93416 | 9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244, |
| 93417 | 9245,9246,9247,9248,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259, |
| 93418 | 9260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274, |
| 93419 | 9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289, |
| 93420 | 9290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304, |
| 93421 | 9305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319, |
| 93422 | 9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,9334, |
| 93423 | 9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349, |
| 93424 | 9350,9351,9352,9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364, |
| 93425 | 9365,9366,9367,9368,9369,9370,9371,9372,9373,9374,9375,9376,9377,9378,9379, |
| 93426 | 9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394, |
| 93427 | 9395,9396,9397,9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409, |
| 93428 | 9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9398, |
| 93429 | 9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413, |
| 93430 | 9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9450,9451,9452,9453,9454, |
| 93431 | 9455,9456,9457,9458,9459,9460,9461,9462,9463,9464,9465,9466,9467,9468,9469, |
| 93432 | 9470,9471,9472,9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484, |
| 93433 | 9485,9486,9487,9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499, |
| 93434 | 9500,9501,9502,9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514, |
| 93435 | 9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529, |
| 93436 | 9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544, |
| 93437 | 9545,9546,9547,9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559, |
| 93438 | 9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574, |
| 93439 | 9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589, |
| 93440 | 9590,9591,9592,9593,9594,9595,9596,9597,9598,9599,9600,9601,9602,9603,9604, |
| 93441 | 9605,9606,9607,9608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619, |
| 93442 | 9620,9621,9622,9623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,9634, |
| 93443 | 9635,9636,9637,9638,9639,9640,9641,9642,9643,9644,9645,9646,9647,9648,9649, |
| 93444 | 9650,9651,9652,9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664, |
| 93445 | 9665,9666,9667,9668,9669,9670,9671,9672,9673,9674,9675,9676,9677,9678,9679, |
| 93446 | 9680,9681,9682,9683,9684,9685,9686,9687,9688,9689,9690,9691,9692,9693,9694, |
| 93447 | 9695,9696,9697,9698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709, |
| 93448 | 9710,9711,9712,9713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724, |
| 93449 | 9725,9726,9727,9728,9729,9730,9731,9732,9733,9734,9735,9736,9737,9738,9739, |
| 93450 | 9740,9741,9742,9743,9744,9745,9746,9747,9748,9749,9750,9751,9752,9753,9754, |
| 93451 | 9755,9756,9757,9758,9759,9760,9761,9762,9763,9764,9765,9766,9767,9768,9769, |
| 93452 | 9770,9771,9772,9773,9774,9775,9776,9777,9778,9779,9780,9781,9782,9783,9784, |
| 93453 | 9785,9786,9787,9788,9789,9790,9791,9792,9793,9794,9795,9796,9797,9798,9799, |
| 93454 | 9800,9801,9802,9803,9804,9805,9806,9807,9808,9809,9810,9811,9812,9813,9814, |
| 93455 | 9815,9816,9817,9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829, |
| 93456 | 9830,9831,9832,9833,9834,9835,9836,9837,9838,9839,9840,9841,9842,9843,9844, |
| 93457 | 9845,9846,9847,9848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859, |
| 93458 | 9860,9861,9862,9863,9864,9865,9866,9867,9868,9869,9870,9871,9872,9873,9874, |
| 93459 | 9875,9876,9877,9878,9879,9880,9881,9882,9883,9884,9885,9886,9887,9888,9889, |
| 93460 | 9890,9891,9892,9893,9894,9895,9896,9897,9898,9899,9900,9901,9902,9903,9904, |
| 93461 | 9905,9906,9907,9908,9909,9910,9911,9912,9913,9914,9915,9916,9917,9918,9919, |
| 93462 | 9920,9921,9922,9923,9924,9925,9926,9927,9928,9929,9930,9931,9932,9933,9934, |
| 93463 | 9935,9936,9937,9938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949, |
| 93464 | 9950,9951,9952,9953,9954,9955,9956,9957,9958,9959,9960,9961,9962,9963,9964, |
| 93465 | 9965,9966,9967,9968,9969,9970,9971,9972,9973,9974,9975,9976,9977,9978,9979, |
| 93466 | 9980,9981,9982,9983,9984,9985,9986,9987,9988,9989,9990,9991,9992,9993,9994, |
| 93467 | 9995,9996,9997,9998,9999,10000,10001,10002,10003,10004,10005,10006,10007, |
| 93468 | 10008,10009,10010,10011,10012,10013,10014,10015,10016,10017,10018,10019, |
| 93469 | 10020,10021,10022,10023,10024,10025,10026,10027,10028,10029,10030,10031, |
| 93470 | 10032,10033,10034,10035,10036,10037,10038,10039,10040,10041,10042,10043, |
| 93471 | 10044,10045,10046,10047,10048,10049,10050,10051,10052,10053,10054,10055, |
| 93472 | 10056,10057,10058,10059,10060,10061,10062,10063,10064,10065,10066,10067, |
| 93473 | 10068,10069,10070,10071,10072,10073,10074,10075,10076,10077,10078,10079, |
| 93474 | 10080,10081,10082,10083,10084,10085,10086,10087,10088,10089,10090,10091, |
| 93475 | 10092,10093,10094,10095,10096,10097,10098,10099,10100,10101,10102,10103, |
| 93476 | 10104,10105,10106,10107,10108,10109,10110,10111,10112,10113,10114,10115, |
| 93477 | 10116,10117,10118,10119,10120,10121,10122,10123,10124,10125,10126,10127, |
| 93478 | 10128,10129,10130,10131,10132,10133,10134,10135,10136,10137,10138,10139, |
| 93479 | 10140,10141,10142,10143,10144,10145,10146,10147,10148,10149,10150,10151, |
| 93480 | 10152,10153,10154,10155,10156,10157,10158,10159,10160,10161,10162,10163, |
| 93481 | 10164,10165,10166,10167,10168,10169,10170,10171,10172,10173,10174,10175, |
| 93482 | 10176,10177,10178,10179,10180,10181,10182,10183,10184,10185,10186,10187, |
| 93483 | 10188,10189,10190,10191,10192,10193,10194,10195,10196,10197,10198,10199, |
| 93484 | 10200,10201,10202,10203,10204,10205,10206,10207,10208,10209,10210,10211, |
| 93485 | 10212,10213,10214,10215,10216,10217,10218,10219,10220,10221,10222,10223, |
| 93486 | 10224,10225,10226,10227,10228,10229,10230,10231,10232,10233,10234,10235, |
| 93487 | 10236,10237,10238,10239,10240,10241,10242,10243,10244,10245,10246,10247, |
| 93488 | 10248,10249,10250,10251,10252,10253,10254,10255,10256,10257,10258,10259, |
| 93489 | 10260,10261,10262,10263,10264,10265,10266,10267,10268,10269,10270,10271, |
| 93490 | 10272,10273,10274,10275,10276,10277,10278,10279,10280,10281,10282,10283, |
| 93491 | 10284,10285,10286,10287,10288,10289,10290,10291,10292,10293,10294,10295, |
| 93492 | 10296,10297,10298,10299,10300,10301,10302,10303,10304,10305,10306,10307, |
| 93493 | 10308,10309,10310,10311,10312,10313,10314,10315,10316,10317,10318,10319, |
| 93494 | 10320,10321,10322,10323,10324,10325,10326,10327,10328,10329,10330,10331, |
| 93495 | 10332,10333,10334,10335,10336,10337,10338,10339,10340,10341,10342,10343, |
| 93496 | 10344,10345,10346,10347,10348,10349,10350,10351,10352,10353,10354,10355, |
| 93497 | 10356,10357,10358,10359,10360,10361,10362,10363,10364,10365,10366,10367, |
| 93498 | 10368,10369,10370,10371,10372,10373,10374,10375,10376,10377,10378,10379, |
| 93499 | 10380,10381,10382,10383,10384,10385,10386,10387,10388,10389,10390,10391, |
| 93500 | 10392,10393,10394,10395,10396,10397,10398,10399,10400,10401,10402,10403, |
| 93501 | 10404,10405,10406,10407,10408,10409,10410,10411,10412,10413,10414,10415, |
| 93502 | 10416,10417,10418,10419,10420,10421,10422,10423,10424,10425,10426,10427, |
| 93503 | 10428,10429,10430,10431,10432,10433,10434,10435,10436,10437,10438,10439, |
| 93504 | 10440,10441,10442,10443,10444,10445,10446,10447,10448,10449,10450,10451, |
| 93505 | 10452,10453,10454,10455,10456,10457,10458,10459,10460,10461,10462,10463, |
| 93506 | 10464,10465,10466,10467,10468,10469,10470,10471,10472,10473,10474,10475, |
| 93507 | 10476,10477,10478,10479,10480,10481,10482,10483,10484,10485,10486,10487, |
| 93508 | 10488,10489,10490,10491,10492,10493,10494,10495,10496,10497,10498,10499, |
| 93509 | 10500,10501,10502,10503,10504,10505,10506,10507,10508,10509,10510,10511, |
| 93510 | 10512,10513,10514,10515,10516,10517,10518,10519,10520,10521,10522,10523, |
| 93511 | 10524,10525,10526,10527,10528,10529,10530,10531,10532,10533,10534,10535, |
| 93512 | 10536,10537,10538,10539,10540,10541,10542,10543,10544,10545,10546,10547, |
| 93513 | 10548,10549,10550,10551,10552,10553,10554,10555,10556,10557,10558,10559, |
| 93514 | 10560,10561,10562,10563,10564,10565,10566,10567,10568,10569,10570,10571, |
| 93515 | 10572,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583, |
| 93516 | 10584,10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595, |
| 93517 | 10596,10597,10598,10599,10600,10601,10602,10603,10604,10605,10606,10607, |
| 93518 | 10608,10609,10610,10611,10612,10613,10614,10615,10616,10617,10618,10619, |
| 93519 | 10620,10621,10622,10623,10624,10625,10626,10627,10628,10629,10630,10631, |
| 93520 | 10632,10633,10634,10635,10636,10637,10638,10639,10640,10641,10642,10643, |
| 93521 | 10644,10645,10646,10647,10648,10649,10650,10651,10652,10653,10654,10655, |
| 93522 | 10656,10657,10658,10659,10660,10661,10662,10663,10664,10665,10666,10667, |
| 93523 | 10668,10669,10670,10671,10672,10673,10674,10675,10676,10677,10678,10679, |
| 93524 | 10680,10681,10682,10683,10684,10685,10686,10687,10688,10689,10690,10691, |
| 93525 | 10692,10693,10694,10695,10696,10697,10698,10699,10700,10701,10702,10703, |
| 93526 | 10704,10705,10706,10707,10708,10709,10710,10711,10712,10713,10714,10715, |
| 93527 | 10716,10717,10718,10719,10720,10721,10722,10723,10724,10725,10726,10727, |
| 93528 | 10728,10729,10730,10731,10732,10733,10734,10735,10736,10737,10738,10739, |
| 93529 | 10740,10741,10742,10743,10744,10745,10746,10747,10748,10749,10750,10751, |
| 93530 | 10752,10753,10754,10755,10756,10757,10758,10759,10760,10761,10762,10763, |
| 93531 | 10764,10765,10766,10767,10768,10769,10770,10771,10772,10773,10774,10775, |
| 93532 | 10776,10777,10778,10779,10780,10781,10782,10783,10784,10785,10786,10787, |
| 93533 | 10788,10789,10790,10791,10792,10793,10794,10795,10796,10797,10798,10799, |
| 93534 | 10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810,10811, |
| 93535 | 10812,10813,10814,10815,10816,10817,10818,10819,10820,10821,10822,10823, |
| 93536 | 10824,10825,10826,10827,10828,10829,10830,10831,10832,10833,10834,10835, |
| 93537 | 10836,10837,10838,10839,10840,10841,10842,10843,10844,10845,10846,10847, |
| 93538 | 10848,10849,10850,10851,10852,10853,10854,10855,10856,10857,10858,10859, |
| 93539 | 10860,10861,10862,10863,10864,10865,10866,10867,10868,10869,10870,10871, |
| 93540 | 10872,10873,10874,10875,10876,10877,10878,10879,10880,10881,10882,10883, |
| 93541 | 10884,10885,10886,10887,10888,10889,10890,10891,10892,10893,10894,10895, |
| 93542 | 10896,10897,10898,10899,10900,10901,10902,10903,10904,10905,10906,10907, |
| 93543 | 10908,10909,10910,10911,10912,10913,10914,10915,10916,10917,10918,10919, |
| 93544 | 10920,10921,10922,10923,10924,10925,10926,10927,10928,10929,10930,10931, |
| 93545 | 10932,10933,10934,10935,10936,10937,10938,10939,10940,10941,10942,10943, |
| 93546 | 10944,10945,10946,10947,10948,10949,10950,10951,10952,10953,10954,10955, |
| 93547 | 10956,10957,10958,10959,10960,10961,10962,10963,10964,10965,10966,10967, |
| 93548 | 10968,10969,10970,10971,10972,10973,10974,10975,10976,10977,10978,10979, |
| 93549 | 10980,10981,10982,10983,10984,10985,10986,10987,10988,10989,10990,10991, |
| 93550 | 10992,10993,10994,10995,10996,10997,10998,10999,11000,11001,11002,11003, |
| 93551 | 11004,11005,11006,11007,11008,11009,11010,11011,11012,11013,11014,11015, |
| 93552 | 11016,11017,11018,11019,11020,11021,11022,11023,11024,11025,11026,11027, |
| 93553 | 11028,11029,11030,11031,11032,11033,11034,11035,11036,11037,11038,11039, |
| 93554 | 11040,11041,11042,11043,11044,11045,11046,11047,11048,11049,11050,11051, |
| 93555 | 11052,11053,11054,11055,11056,11057,11058,11059,11060,11061,11062,11063, |
| 93556 | 11064,11065,11066,11067,11068,11069,11070,11071,11072,11073,11074,11075, |
| 93557 | 11076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087, |
| 93558 | 11088,11089,11090,11091,11092,11093,11094,11095,11096,11097,11098,11099, |
| 93559 | 11100,11101,11102,11103,11104,11105,11106,11107,11108,11109,11110,11111, |
| 93560 | 11112,11113,11114,11115,11116,11117,11118,11119,11120,11121,11122,11123, |
| 93561 | 11124,11125,11126,11127,11128,11129,11130,11131,11132,11133,11134,11135, |
| 93562 | 11136,11137,11138,11139,11140,11141,11142,11143,11144,11145,11146,11147, |
| 93563 | 11148,11149,11150,11151,11152,11153,11154,11155,11156,11157,11158,11159, |
| 93564 | 11160,11161,11162,11163,11164,11165,11166,11167,11168,11169,11170,11171, |
| 93565 | 11172,11173,11174,11175,11176,11177,11178,11179,11180,11181,11182,11183, |
| 93566 | 11184,11185,11186,11187,11188,11189,11190,11191,11192,11193,11194,11195, |
| 93567 | 11196,11197,11198,11199,11200,11201,11202,11203,11204,11205,11206,11207, |
| 93568 | 11208,11209,11210,11211,11212,11213,11214,11215,11216,11217,11218,11219, |
| 93569 | 11220,11221,11222,11223,11224,11225,11226,11227,11228,11229,11230,11231, |
| 93570 | 11232,11233,11234,11235,11236,11237,11238,11239,11240,11241,11242,11243, |
| 93571 | 11244,11245,11246,11247,11248,11249,11250,11251,11252,11253,11254,11255, |
| 93572 | 11256,11257,11258,11259,11260,11261,11262,11263,11264,11265,11266,11267, |
| 93573 | 11268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279, |
| 93574 | 11280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291, |
| 93575 | 11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303, |
| 93576 | 11304,11305,11306,11307,11308,11309,11310,11311,11264,11265,11266,11267, |
| 93577 | 11268,11269,11270,11271,11272,11273,11274,11275,11276,11277,11278,11279, |
| 93578 | 11280,11281,11282,11283,11284,11285,11286,11287,11288,11289,11290,11291, |
| 93579 | 11292,11293,11294,11295,11296,11297,11298,11299,11300,11301,11302,11303, |
| 93580 | 11304,11305,11306,11307,11308,11309,11310,11359,11360,11360,11362,11363, |
| 93581 | 11364,570,574,11367,11367,11369,11369,11371,11371,11373,11374,11375,11376, |
| 93582 | 11377,11378,11378,11380,11381,11381,11383,11384,11385,11386,11387,11388, |
| 93583 | 11389,11390,11391,11392,11392,11394,11394,11396,11396,11398,11398,11400, |
| 93584 | 11400,11402,11402,11404,11404,11406,11406,11408,11408,11410,11410,11412, |
| 93585 | 11412,11414,11414,11416,11416,11418,11418,11420,11420,11422,11422,11424, |
| 93586 | 11424,11426,11426,11428,11428,11430,11430,11432,11432,11434,11434,11436, |
| 93587 | 11436,11438,11438,11440,11440,11442,11442,11444,11444,11446,11446,11448, |
| 93588 | 11448,11450,11450,11452,11452,11454,11454,11456,11456,11458,11458,11460, |
| 93589 | 11460,11462,11462,11464,11464,11466,11466,11468,11468,11470,11470,11472, |
| 93590 | 11472,11474,11474,11476,11476,11478,11478,11480,11480,11482,11482,11484, |
| 93591 | 11484,11486,11486,11488,11488,11490,11490,11492,11493,11494,11495,11496, |
| 93592 | 11497,11498,11499,11499,11501,11501,11503,11504,11505,11506,11506,11508, |
| 93593 | 11509,11510,11511,11512,11513,11514,11515,11516,11517,11518,11519,4256, |
| 93594 | 4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271, |
| 93595 | 4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286, |
| 93596 | 4287,4288,4289,4290,4291,4292,4293,11558,4295,11560,11561,11562,11563, |
| 93597 | 11564,4301,11566,11567,11568,11569,11570,11571,11572,11573,11574,11575, |
| 93598 | 11576,11577,11578,11579,11580,11581,11582,11583,11584,11585,11586,11587, |
| 93599 | 11588,11589,11590,11591,11592,11593,11594,11595,11596,11597,11598,11599, |
| 93600 | 11600,11601,11602,11603,11604,11605,11606,11607,11608,11609,11610,11611, |
| 93601 | 11612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622,11623, |
| 93602 | 11624,11625,11626,11627,11628,11629,11630,11631,11632,11633,11634,11635, |
| 93603 | 11636,11637,11638,11639,11640,11641,11642,11643,11644,11645,11646,11647, |
| 93604 | 11648,11649,11650,11651,11652,11653,11654,11655,11656,11657,11658,11659, |
| 93605 | 11660,11661,11662,11663,11664,11665,11666,11667,11668,11669,11670,11671, |
| 93606 | 11672,11673,11674,11675,11676,11677,11678,11679,11680,11681,11682,11683, |
| 93607 | 11684,11685,11686,11687,11688,11689,11690,11691,11692,11693,11694,11695, |
| 93608 | 11696,11697,11698,11699,11700,11701,11702,11703,11704,11705,11706,11707, |
| 93609 | 11708,11709,11710,11711,11712,11713,11714,11715,11716,11717,11718,11719, |
| 93610 | 11720,11721,11722,11723,11724,11725,11726,11727,11728,11729,11730,11731, |
| 93611 | 11732,11733,11734,11735,11736,11737,11738,11739,11740,11741,11742,11743, |
| 93612 | 11744,11745,11746,11747,11748,11749,11750,11751,11752,11753,11754,11755, |
| 93613 | 11756,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767, |
| 93614 | 11768,11769,11770,11771,11772,11773,11774,11775,11776,11777,11778,11779, |
| 93615 | 11780,11781,11782,11783,11784,11785,11786,11787,11788,11789,11790,11791, |
| 93616 | 11792,11793,11794,11795,11796,11797,11798,11799,11800,11801,11802,11803, |
| 93617 | 11804,11805,11806,11807,11808,11809,11810,11811,11812,11813,11814,11815, |
| 93618 | 11816,11817,11818,11819,11820,11821,11822,11823,11824,11825,11826,11827, |
| 93619 | 11828,11829,11830,11831,11832,11833,11834,11835,11836,11837,11838,11839, |
| 93620 | 11840,11841,11842,11843,11844,11845,11846,11847,11848,11849,11850,11851, |
| 93621 | 11852,11853,11854,11855,11856,11857,11858,11859,11860,11861,11862,11863, |
| 93622 | 11864,11865,11866,11867,11868,11869,11870,11871,11872,11873,11874,11875, |
| 93623 | 11876,11877,11878,11879,11880,11881,11882,11883,11884,11885,11886,11887, |
| 93624 | 11888,11889,11890,11891,11892,11893,11894,11895,11896,11897,11898,11899, |
| 93625 | 11900,11901,11902,11903,11904,11905,11906,11907,11908,11909,11910,11911, |
| 93626 | 11912,11913,11914,11915,11916,11917,11918,11919,11920,11921,11922,11923, |
| 93627 | 11924,11925,11926,11927,11928,11929,11930,11931,11932,11933,11934,11935, |
| 93628 | 11936,11937,11938,11939,11940,11941,11942,11943,11944,11945,11946,11947, |
| 93629 | 11948,11949,11950,11951,11952,11953,11954,11955,11956,11957,11958,11959, |
| 93630 | 11960,11961,11962,11963,11964,11965,11966,11967,11968,11969,11970,11971, |
| 93631 | 11972,11973,11974,11975,11976,11977,11978,11979,11980,11981,11982,11983, |
| 93632 | 11984,11985,11986,11987,11988,11989,11990,11991,11992,11993,11994,11995, |
| 93633 | 11996,11997,11998,11999,12000,12001,12002,12003,12004,12005,12006,12007, |
| 93634 | 12008,12009,12010,12011,12012,12013,12014,12015,12016,12017,12018,12019, |
| 93635 | 12020,12021,12022,12023,12024,12025,12026,12027,12028,12029,12030,12031, |
| 93636 | 12032,12033,12034,12035,12036,12037,12038,12039,12040,12041,12042,12043, |
| 93637 | 12044,12045,12046,12047,12048,12049,12050,12051,12052,12053,12054,12055, |
| 93638 | 12056,12057,12058,12059,12060,12061,12062,12063,12064,12065,12066,12067, |
| 93639 | 12068,12069,12070,12071,12072,12073,12074,12075,12076,12077,12078,12079, |
| 93640 | 12080,12081,12082,12083,12084,12085,12086,12087,12088,12089,12090,12091, |
| 93641 | 12092,12093,12094,12095,12096,12097,12098,12099,12100,12101,12102,12103, |
| 93642 | 12104,12105,12106,12107,12108,12109,12110,12111,12112,12113,12114,12115, |
| 93643 | 12116,12117,12118,12119,12120,12121,12122,12123,12124,12125,12126,12127, |
| 93644 | 12128,12129,12130,12131,12132,12133,12134,12135,12136,12137,12138,12139, |
| 93645 | 12140,12141,12142,12143,12144,12145,12146,12147,12148,12149,12150,12151, |
| 93646 | 12152,12153,12154,12155,12156,12157,12158,12159,12160,12161,12162,12163, |
| 93647 | 12164,12165,12166,12167,12168,12169,12170,12171,12172,12173,12174,12175, |
| 93648 | 12176,12177,12178,12179,12180,12181,12182,12183,12184,12185,12186,12187, |
| 93649 | 12188,12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199, |
| 93650 | 12200,12201,12202,12203,12204,12205,12206,12207,12208,12209,12210,12211, |
| 93651 | 12212,12213,12214,12215,12216,12217,12218,12219,12220,12221,12222,12223, |
| 93652 | 12224,12225,12226,12227,12228,12229,12230,12231,12232,12233,12234,12235, |
| 93653 | 12236,12237,12238,12239,12240,12241,12242,12243,12244,12245,12246,12247, |
| 93654 | 12248,12249,12250,12251,12252,12253,12254,12255,12256,12257,12258,12259, |
| 93655 | 12260,12261,12262,12263,12264,12265,12266,12267,12268,12269,12270,12271, |
| 93656 | 12272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283, |
| 93657 | 12284,12285,12286,12287,12288,12289,12290,12291,12292,12293,12294,12295, |
| 93658 | 12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,12306,12307, |
| 93659 | 12308,12309,12310,12311,12312,12313,12314,12315,12316,12317,12318,12319, |
| 93660 | 12320,12321,12322,12323,12324,12325,12326,12327,12328,12329,12330,12331, |
| 93661 | 12332,12333,12334,12335,12336,12337,12338,12339,12340,12341,12342,12343, |
| 93662 | 12344,12345,12346,12347,12348,12349,12350,12351,12352,12353,12354,12355, |
| 93663 | 12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367, |
| 93664 | 12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379, |
| 93665 | 12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391, |
| 93666 | 12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403, |
| 93667 | 12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415, |
| 93668 | 12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427, |
| 93669 | 12428,12429,12430,12431,12432,12433,12434,12435,12436,12437,12438,12439, |
| 93670 | 12440,12441,12442,12443,12444,12445,12446,12447,12448,12449,12450,12451, |
| 93671 | 12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463, |
| 93672 | 12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475, |
| 93673 | 12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487, |
| 93674 | 12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499, |
| 93675 | 12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511, |
| 93676 | 12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523, |
| 93677 | 12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,12535, |
| 93678 | 12536,12537,12538,12539,12540,12541,12542,12543,12544,12545,12546,12547, |
| 93679 | 12548,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559, |
| 93680 | 12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571, |
| 93681 | 12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583, |
| 93682 | 12584,12585,12586,12587,12588,12589,12590,12591,12592,12593,12594,12595, |
| 93683 | 12596,12597,12598,12599,12600,12601,12602,12603,12604,12605,12606,12607, |
| 93684 | 12608,12609,12610,12611,12612,12613,12614,12615,12616,12617,12618,12619, |
| 93685 | 12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631, |
| 93686 | 12632,12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643, |
| 93687 | 12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654,12655, |
| 93688 | 12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667, |
| 93689 | 12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679, |
| 93690 | 12680,12681,12682,12683,12684,12685,12686,12687,12688,12689,12690,12691, |
| 93691 | 12692,12693,12694,12695,12696,12697,12698,12699,12700,12701,12702,12703, |
| 93692 | 12704,12705,12706,12707,12708,12709,12710,12711,12712,12713,12714,12715, |
| 93693 | 12716,12717,12718,12719,12720,12721,12722,12723,12724,12725,12726,12727, |
| 93694 | 12728,12729,12730,12731,12732,12733,12734,12735,12736,12737,12738,12739, |
| 93695 | 12740,12741,12742,12743,12744,12745,12746,12747,12748,12749,12750,12751, |
| 93696 | 12752,12753,12754,12755,12756,12757,12758,12759,12760,12761,12762,12763, |
| 93697 | 12764,12765,12766,12767,12768,12769,12770,12771,12772,12773,12774,12775, |
| 93698 | 12776,12777,12778,12779,12780,12781,12782,12783,12784,12785,12786,12787, |
| 93699 | 12788,12789,12790,12791,12792,12793,12794,12795,12796,12797,12798,12799, |
| 93700 | 12800,12801,12802,12803,12804,12805,12806,12807,12808,12809,12810,12811, |
| 93701 | 12812,12813,12814,12815,12816,12817,12818,12819,12820,12821,12822,12823, |
| 93702 | 12824,12825,12826,12827,12828,12829,12830,12831,12832,12833,12834,12835, |
| 93703 | 12836,12837,12838,12839,12840,12841,12842,12843,12844,12845,12846,12847, |
| 93704 | 12848,12849,12850,12851,12852,12853,12854,12855,12856,12857,12858,12859, |
| 93705 | 12860,12861,12862,12863,12864,12865,12866,12867,12868,12869,12870,12871, |
| 93706 | 12872,12873,12874,12875,12876,12877,12878,12879,12880,12881,12882,12883, |
| 93707 | 12884,12885,12886,12887,12888,12889,12890,12891,12892,12893,12894,12895, |
| 93708 | 12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907, |
| 93709 | 12908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919, |
| 93710 | 12920,12921,12922,12923,12924,12925,12926,12927,12928,12929,12930,12931, |
| 93711 | 12932,12933,12934,12935,12936,12937,12938,12939,12940,12941,12942,12943, |
| 93712 | 12944,12945,12946,12947,12948,12949,12950,12951,12952,12953,12954,12955, |
| 93713 | 12956,12957,12958,12959,12960,12961,12962,12963,12964,12965,12966,12967, |
| 93714 | 12968,12969,12970,12971,12972,12973,12974,12975,12976,12977,12978,12979, |
| 93715 | 12980,12981,12982,12983,12984,12985,12986,12987,12988,12989,12990,12991, |
| 93716 | 12992,12993,12994,12995,12996,12997,12998,12999,13000,13001,13002,13003, |
| 93717 | 13004,13005,13006,13007,13008,13009,13010,13011,13012,13013,13014,13015, |
| 93718 | 13016,13017,13018,13019,13020,13021,13022,13023,13024,13025,13026,13027, |
| 93719 | 13028,13029,13030,13031,13032,13033,13034,13035,13036,13037,13038,13039, |
| 93720 | 13040,13041,13042,13043,13044,13045,13046,13047,13048,13049,13050,13051, |
| 93721 | 13052,13053,13054,13055,13056,13057,13058,13059,13060,13061,13062,13063, |
| 93722 | 13064,13065,13066,13067,13068,13069,13070,13071,13072,13073,13074,13075, |
| 93723 | 13076,13077,13078,13079,13080,13081,13082,13083,13084,13085,13086,13087, |
| 93724 | 13088,13089,13090,13091,13092,13093,13094,13095,13096,13097,13098,13099, |
| 93725 | 13100,13101,13102,13103,13104,13105,13106,13107,13108,13109,13110,13111, |
| 93726 | 13112,13113,13114,13115,13116,13117,13118,13119,13120,13121,13122,13123, |
| 93727 | 13124,13125,13126,13127,13128,13129,13130,13131,13132,13133,13134,13135, |
| 93728 | 13136,13137,13138,13139,13140,13141,13142,13143,13144,13145,13146,13147, |
| 93729 | 13148,13149,13150,13151,13152,13153,13154,13155,13156,13157,13158,13159, |
| 93730 | 13160,13161,13162,13163,13164,13165,13166,13167,13168,13169,13170,13171, |
| 93731 | 13172,13173,13174,13175,13176,13177,13178,13179,13180,13181,13182,13183, |
| 93732 | 13184,13185,13186,13187,13188,13189,13190,13191,13192,13193,13194,13195, |
| 93733 | 13196,13197,13198,13199,13200,13201,13202,13203,13204,13205,13206,13207, |
| 93734 | 13208,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13219, |
| 93735 | 13220,13221,13222,13223,13224,13225,13226,13227,13228,13229,13230,13231, |
| 93736 | 13232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13242,13243, |
| 93737 | 13244,13245,13246,13247,13248,13249,13250,13251,13252,13253,13254,13255, |
| 93738 | 13256,13257,13258,13259,13260,13261,13262,13263,13264,13265,13266,13267, |
| 93739 | 13268,13269,13270,13271,13272,13273,13274,13275,13276,13277,13278,13279, |
| 93740 | 13280,13281,13282,13283,13284,13285,13286,13287,13288,13289,13290,13291, |
| 93741 | 13292,13293,13294,13295,13296,13297,13298,13299,13300,13301,13302,13303, |
| 93742 | 13304,13305,13306,13307,13308,13309,13310,13311,13312,13313,13314,13315, |
| 93743 | 13316,13317,13318,13319,13320,13321,13322,13323,13324,13325,13326,13327, |
| 93744 | 13328,13329,13330,13331,13332,13333,13334,13335,13336,13337,13338,13339, |
| 93745 | 13340,13341,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351, |
| 93746 | 13352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363, |
| 93747 | 13364,13365,13366,13367,13368,13369,13370,13371,13372,13373,13374,13375, |
| 93748 | 13376,13377,13378,13379,13380,13381,13382,13383,13384,13385,13386,13387, |
| 93749 | 13388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398,13399, |
| 93750 | 13400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411, |
| 93751 | 13412,13413,13414,13415,13416,13417,13418,13419,13420,13421,13422,13423, |
| 93752 | 13424,13425,13426,13427,13428,13429,13430,13431,13432,13433,13434,13435, |
| 93753 | 13436,13437,13438,13439,13440,13441,13442,13443,13444,13445,13446,13447, |
| 93754 | 13448,13449,13450,13451,13452,13453,13454,13455,13456,13457,13458,13459, |
| 93755 | 13460,13461,13462,13463,13464,13465,13466,13467,13468,13469,13470,13471, |
| 93756 | 13472,13473,13474,13475,13476,13477,13478,13479,13480,13481,13482,13483, |
| 93757 | 13484,13485,13486,13487,13488,13489,13490,13491,13492,13493,13494,13495, |
| 93758 | 13496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506,13507, |
| 93759 | 13508,13509,13510,13511,13512,13513,13514,13515,13516,13517,13518,13519, |
| 93760 | 13520,13521,13522,13523,13524,13525,13526,13527,13528,13529,13530,13531, |
| 93761 | 13532,13533,13534,13535,13536,13537,13538,13539,13540,13541,13542,13543, |
| 93762 | 13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554,13555, |
| 93763 | 13556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567, |
| 93764 | 13568,13569,13570,13571,13572,13573,13574,13575,13576,13577,13578,13579, |
| 93765 | 13580,13581,13582,13583,13584,13585,13586,13587,13588,13589,13590,13591, |
| 93766 | 13592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602,13603, |
| 93767 | 13604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615, |
| 93768 | 13616,13617,13618,13619,13620,13621,13622,13623,13624,13625,13626,13627, |
| 93769 | 13628,13629,13630,13631,13632,13633,13634,13635,13636,13637,13638,13639, |
| 93770 | 13640,13641,13642,13643,13644,13645,13646,13647,13648,13649,13650,13651, |
| 93771 | 13652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663, |
| 93772 | 13664,13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675, |
| 93773 | 13676,13677,13678,13679,13680,13681,13682,13683,13684,13685,13686,13687, |
| 93774 | 13688,13689,13690,13691,13692,13693,13694,13695,13696,13697,13698,13699, |
| 93775 | 13700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711, |
| 93776 | 13712,13713,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723, |
| 93777 | 13724,13725,13726,13727,13728,13729,13730,13731,13732,13733,13734,13735, |
| 93778 | 13736,13737,13738,13739,13740,13741,13742,13743,13744,13745,13746,13747, |
| 93779 | 13748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759, |
| 93780 | 13760,13761,13762,13763,13764,13765,13766,13767,13768,13769,13770,13771, |
| 93781 | 13772,13773,13774,13775,13776,13777,13778,13779,13780,13781,13782,13783, |
| 93782 | 13784,13785,13786,13787,13788,13789,13790,13791,13792,13793,13794,13795, |
| 93783 | 13796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807, |
| 93784 | 13808,13809,13810,13811,13812,13813,13814,13815,13816,13817,13818,13819, |
| 93785 | 13820,13821,13822,13823,13824,13825,13826,13827,13828,13829,13830,13831, |
| 93786 | 13832,13833,13834,13835,13836,13837,13838,13839,13840,13841,13842,13843, |
| 93787 | 13844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855, |
| 93788 | 13856,13857,13858,13859,13860,13861,13862,13863,13864,13865,13866,13867, |
| 93789 | 13868,13869,13870,13871,13872,13873,13874,13875,13876,13877,13878,13879, |
| 93790 | 13880,13881,13882,13883,13884,13885,13886,13887,13888,13889,13890,13891, |
| 93791 | 13892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903, |
| 93792 | 13904,13905,13906,13907,13908,13909,13910,13911,13912,13913,13914,13915, |
| 93793 | 13916,13917,13918,13919,13920,13921,13922,13923,13924,13925,13926,13927, |
| 93794 | 13928,13929,13930,13931,13932,13933,13934,13935,13936,13937,13938,13939, |
| 93795 | 13940,13941,13942,13943,13944,13945,13946,13947,13948,13949,13950,13951, |
| 93796 | 13952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963, |
| 93797 | 13964,13965,13966,13967,13968,13969,13970,13971,13972,13973,13974,13975, |
| 93798 | 13976,13977,13978,13979,13980,13981,13982,13983,13984,13985,13986,13987, |
| 93799 | 13988,13989,13990,13991,13992,13993,13994,13995,13996,13997,13998,13999, |
| 93800 | 14000,14001,14002,14003,14004,14005,14006,14007,14008,14009,14010,14011, |
| 93801 | 14012,14013,14014,14015,14016,14017,14018,14019,14020,14021,14022,14023, |
| 93802 | 14024,14025,14026,14027,14028,14029,14030,14031,14032,14033,14034,14035, |
| 93803 | 14036,14037,14038,14039,14040,14041,14042,14043,14044,14045,14046,14047, |
| 93804 | 14048,14049,14050,14051,14052,14053,14054,14055,14056,14057,14058,14059, |
| 93805 | 14060,14061,14062,14063,14064,14065,14066,14067,14068,14069,14070,14071, |
| 93806 | 14072,14073,14074,14075,14076,14077,14078,14079,14080,14081,14082,14083, |
| 93807 | 14084,14085,14086,14087,14088,14089,14090,14091,14092,14093,14094,14095, |
| 93808 | 14096,14097,14098,14099,14100,14101,14102,14103,14104,14105,14106,14107, |
| 93809 | 14108,14109,14110,14111,14112,14113,14114,14115,14116,14117,14118,14119, |
| 93810 | 14120,14121,14122,14123,14124,14125,14126,14127,14128,14129,14130,14131, |
| 93811 | 14132,14133,14134,14135,14136,14137,14138,14139,14140,14141,14142,14143, |
| 93812 | 14144,14145,14146,14147,14148,14149,14150,14151,14152,14153,14154,14155, |
| 93813 | 14156,14157,14158,14159,14160,14161,14162,14163,14164,14165,14166,14167, |
| 93814 | 14168,14169,14170,14171,14172,14173,14174,14175,14176,14177,14178,14179, |
| 93815 | 14180,14181,14182,14183,14184,14185,14186,14187,14188,14189,14190,14191, |
| 93816 | 14192,14193,14194,14195,14196,14197,14198,14199,14200,14201,14202,14203, |
| 93817 | 14204,14205,14206,14207,14208,14209,14210,14211,14212,14213,14214,14215, |
| 93818 | 14216,14217,14218,14219,14220,14221,14222,14223,14224,14225,14226,14227, |
| 93819 | 14228,14229,14230,14231,14232,14233,14234,14235,14236,14237,14238,14239, |
| 93820 | 14240,14241,14242,14243,14244,14245,14246,14247,14248,14249,14250,14251, |
| 93821 | 14252,14253,14254,14255,14256,14257,14258,14259,14260,14261,14262,14263, |
| 93822 | 14264,14265,14266,14267,14268,14269,14270,14271,14272,14273,14274,14275, |
| 93823 | 14276,14277,14278,14279,14280,14281,14282,14283,14284,14285,14286,14287, |
| 93824 | 14288,14289,14290,14291,14292,14293,14294,14295,14296,14297,14298,14299, |
| 93825 | 14300,14301,14302,14303,14304,14305,14306,14307,14308,14309,14310,14311, |
| 93826 | 14312,14313,14314,14315,14316,14317,14318,14319,14320,14321,14322,14323, |
| 93827 | 14324,14325,14326,14327,14328,14329,14330,14331,14332,14333,14334,14335, |
| 93828 | 14336,14337,14338,14339,14340,14341,14342,14343,14344,14345,14346,14347, |
| 93829 | 14348,14349,14350,14351,14352,14353,14354,14355,14356,14357,14358,14359, |
| 93830 | 14360,14361,14362,14363,14364,14365,14366,14367,14368,14369,14370,14371, |
| 93831 | 14372,14373,14374,14375,14376,14377,14378,14379,14380,14381,14382,14383, |
| 93832 | 14384,14385,14386,14387,14388,14389,14390,14391,14392,14393,14394,14395, |
| 93833 | 14396,14397,14398,14399,14400,14401,14402,14403,14404,14405,14406,14407, |
| 93834 | 14408,14409,14410,14411,14412,14413,14414,14415,14416,14417,14418,14419, |
| 93835 | 14420,14421,14422,14423,14424,14425,14426,14427,14428,14429,14430,14431, |
| 93836 | 14432,14433,14434,14435,14436,14437,14438,14439,14440,14441,14442,14443, |
| 93837 | 14444,14445,14446,14447,14448,14449,14450,14451,14452,14453,14454,14455, |
| 93838 | 14456,14457,14458,14459,14460,14461,14462,14463,14464,14465,14466,14467, |
| 93839 | 14468,14469,14470,14471,14472,14473,14474,14475,14476,14477,14478,14479, |
| 93840 | 14480,14481,14482,14483,14484,14485,14486,14487,14488,14489,14490,14491, |
| 93841 | 14492,14493,14494,14495,14496,14497,14498,14499,14500,14501,14502,14503, |
| 93842 | 14504,14505,14506,14507,14508,14509,14510,14511,14512,14513,14514,14515, |
| 93843 | 14516,14517,14518,14519,14520,14521,14522,14523,14524,14525,14526,14527, |
| 93844 | 14528,14529,14530,14531,14532,14533,14534,14535,14536,14537,14538,14539, |
| 93845 | 14540,14541,14542,14543,14544,14545,14546,14547,14548,14549,14550,14551, |
| 93846 | 14552,14553,14554,14555,14556,14557,14558,14559,14560,14561,14562,14563, |
| 93847 | 14564,14565,14566,14567,14568,14569,14570,14571,14572,14573,14574,14575, |
| 93848 | 14576,14577,14578,14579,14580,14581,14582,14583,14584,14585,14586,14587, |
| 93849 | 14588,14589,14590,14591,14592,14593,14594,14595,14596,14597,14598,14599, |
| 93850 | 14600,14601,14602,14603,14604,14605,14606,14607,14608,14609,14610,14611, |
| 93851 | 14612,14613,14614,14615,14616,14617,14618,14619,14620,14621,14622,14623, |
| 93852 | 14624,14625,14626,14627,14628,14629,14630,14631,14632,14633,14634,14635, |
| 93853 | 14636,14637,14638,14639,14640,14641,14642,14643,14644,14645,14646,14647, |
| 93854 | 14648,14649,14650,14651,14652,14653,14654,14655,14656,14657,14658,14659, |
| 93855 | 14660,14661,14662,14663,14664,14665,14666,14667,14668,14669,14670,14671, |
| 93856 | 14672,14673,14674,14675,14676,14677,14678,14679,14680,14681,14682,14683, |
| 93857 | 14684,14685,14686,14687,14688,14689,14690,14691,14692,14693,14694,14695, |
| 93858 | 14696,14697,14698,14699,14700,14701,14702,14703,14704,14705,14706,14707, |
| 93859 | 14708,14709,14710,14711,14712,14713,14714,14715,14716,14717,14718,14719, |
| 93860 | 14720,14721,14722,14723,14724,14725,14726,14727,14728,14729,14730,14731, |
| 93861 | 14732,14733,14734,14735,14736,14737,14738,14739,14740,14741,14742,14743, |
| 93862 | 14744,14745,14746,14747,14748,14749,14750,14751,14752,14753,14754,14755, |
| 93863 | 14756,14757,14758,14759,14760,14761,14762,14763,14764,14765,14766,14767, |
| 93864 | 14768,14769,14770,14771,14772,14773,14774,14775,14776,14777,14778,14779, |
| 93865 | 14780,14781,14782,14783,14784,14785,14786,14787,14788,14789,14790,14791, |
| 93866 | 14792,14793,14794,14795,14796,14797,14798,14799,14800,14801,14802,14803, |
| 93867 | 14804,14805,14806,14807,14808,14809,14810,14811,14812,14813,14814,14815, |
| 93868 | 14816,14817,14818,14819,14820,14821,14822,14823,14824,14825,14826,14827, |
| 93869 | 14828,14829,14830,14831,14832,14833,14834,14835,14836,14837,14838,14839, |
| 93870 | 14840,14841,14842,14843,14844,14845,14846,14847,14848,14849,14850,14851, |
| 93871 | 14852,14853,14854,14855,14856,14857,14858,14859,14860,14861,14862,14863, |
| 93872 | 14864,14865,14866,14867,14868,14869,14870,14871,14872,14873,14874,14875, |
| 93873 | 14876,14877,14878,14879,14880,14881,14882,14883,14884,14885,14886,14887, |
| 93874 | 14888,14889,14890,14891,14892,14893,14894,14895,14896,14897,14898,14899, |
| 93875 | 14900,14901,14902,14903,14904,14905,14906,14907,14908,14909,14910,14911, |
| 93876 | 14912,14913,14914,14915,14916,14917,14918,14919,14920,14921,14922,14923, |
| 93877 | 14924,14925,14926,14927,14928,14929,14930,14931,14932,14933,14934,14935, |
| 93878 | 14936,14937,14938,14939,14940,14941,14942,14943,14944,14945,14946,14947, |
| 93879 | 14948,14949,14950,14951,14952,14953,14954,14955,14956,14957,14958,14959, |
| 93880 | 14960,14961,14962,14963,14964,14965,14966,14967,14968,14969,14970,14971, |
| 93881 | 14972,14973,14974,14975,14976,14977,14978,14979,14980,14981,14982,14983, |
| 93882 | 14984,14985,14986,14987,14988,14989,14990,14991,14992,14993,14994,14995, |
| 93883 | 14996,14997,14998,14999,15000,15001,15002,15003,15004,15005,15006,15007, |
| 93884 | 15008,15009,15010,15011,15012,15013,15014,15015,15016,15017,15018,15019, |
| 93885 | 15020,15021,15022,15023,15024,15025,15026,15027,15028,15029,15030,15031, |
| 93886 | 15032,15033,15034,15035,15036,15037,15038,15039,15040,15041,15042,15043, |
| 93887 | 15044,15045,15046,15047,15048,15049,15050,15051,15052,15053,15054,15055, |
| 93888 | 15056,15057,15058,15059,15060,15061,15062,15063,15064,15065,15066,15067, |
| 93889 | 15068,15069,15070,15071,15072,15073,15074,15075,15076,15077,15078,15079, |
| 93890 | 15080,15081,15082,15083,15084,15085,15086,15087,15088,15089,15090,15091, |
| 93891 | 15092,15093,15094,15095,15096,15097,15098,15099,15100,15101,15102,15103, |
| 93892 | 15104,15105,15106,15107,15108,15109,15110,15111,15112,15113,15114,15115, |
| 93893 | 15116,15117,15118,15119,15120,15121,15122,15123,15124,15125,15126,15127, |
| 93894 | 15128,15129,15130,15131,15132,15133,15134,15135,15136,15137,15138,15139, |
| 93895 | 15140,15141,15142,15143,15144,15145,15146,15147,15148,15149,15150,15151, |
| 93896 | 15152,15153,15154,15155,15156,15157,15158,15159,15160,15161,15162,15163, |
| 93897 | 15164,15165,15166,15167,15168,15169,15170,15171,15172,15173,15174,15175, |
| 93898 | 15176,15177,15178,15179,15180,15181,15182,15183,15184,15185,15186,15187, |
| 93899 | 15188,15189,15190,15191,15192,15193,15194,15195,15196,15197,15198,15199, |
| 93900 | 15200,15201,15202,15203,15204,15205,15206,15207,15208,15209,15210,15211, |
| 93901 | 15212,15213,15214,15215,15216,15217,15218,15219,15220,15221,15222,15223, |
| 93902 | 15224,15225,15226,15227,15228,15229,15230,15231,15232,15233,15234,15235, |
| 93903 | 15236,15237,15238,15239,15240,15241,15242,15243,15244,15245,15246,15247, |
| 93904 | 15248,15249,15250,15251,15252,15253,15254,15255,15256,15257,15258,15259, |
| 93905 | 15260,15261,15262,15263,15264,15265,15266,15267,15268,15269,15270,15271, |
| 93906 | 15272,15273,15274,15275,15276,15277,15278,15279,15280,15281,15282,15283, |
| 93907 | 15284,15285,15286,15287,15288,15289,15290,15291,15292,15293,15294,15295, |
| 93908 | 15296,15297,15298,15299,15300,15301,15302,15303,15304,15305,15306,15307, |
| 93909 | 15308,15309,15310,15311,15312,15313,15314,15315,15316,15317,15318,15319, |
| 93910 | 15320,15321,15322,15323,15324,15325,15326,15327,15328,15329,15330,15331, |
| 93911 | 15332,15333,15334,15335,15336,15337,15338,15339,15340,15341,15342,15343, |
| 93912 | 15344,15345,15346,15347,15348,15349,15350,15351,15352,15353,15354,15355, |
| 93913 | 15356,15357,15358,15359,15360,15361,15362,15363,15364,15365,15366,15367, |
| 93914 | 15368,15369,15370,15371,15372,15373,15374,15375,15376,15377,15378,15379, |
| 93915 | 15380,15381,15382,15383,15384,15385,15386,15387,15388,15389,15390,15391, |
| 93916 | 15392,15393,15394,15395,15396,15397,15398,15399,15400,15401,15402,15403, |
| 93917 | 15404,15405,15406,15407,15408,15409,15410,15411,15412,15413,15414,15415, |
| 93918 | 15416,15417,15418,15419,15420,15421,15422,15423,15424,15425,15426,15427, |
| 93919 | 15428,15429,15430,15431,15432,15433,15434,15435,15436,15437,15438,15439, |
| 93920 | 15440,15441,15442,15443,15444,15445,15446,15447,15448,15449,15450,15451, |
| 93921 | 15452,15453,15454,15455,15456,15457,15458,15459,15460,15461,15462,15463, |
| 93922 | 15464,15465,15466,15467,15468,15469,15470,15471,15472,15473,15474,15475, |
| 93923 | 15476,15477,15478,15479,15480,15481,15482,15483,15484,15485,15486,15487, |
| 93924 | 15488,15489,15490,15491,15492,15493,15494,15495,15496,15497,15498,15499, |
| 93925 | 15500,15501,15502,15503,15504,15505,15506,15507,15508,15509,15510,15511, |
| 93926 | 15512,15513,15514,15515,15516,15517,15518,15519,15520,15521,15522,15523, |
| 93927 | 15524,15525,15526,15527,15528,15529,15530,15531,15532,15533,15534,15535, |
| 93928 | 15536,15537,15538,15539,15540,15541,15542,15543,15544,15545,15546,15547, |
| 93929 | 15548,15549,15550,15551,15552,15553,15554,15555,15556,15557,15558,15559, |
| 93930 | 15560,15561,15562,15563,15564,15565,15566,15567,15568,15569,15570,15571, |
| 93931 | 15572,15573,15574,15575,15576,15577,15578,15579,15580,15581,15582,15583, |
| 93932 | 15584,15585,15586,15587,15588,15589,15590,15591,15592,15593,15594,15595, |
| 93933 | 15596,15597,15598,15599,15600,15601,15602,15603,15604,15605,15606,15607, |
| 93934 | 15608,15609,15610,15611,15612,15613,15614,15615,15616,15617,15618,15619, |
| 93935 | 15620,15621,15622,15623,15624,15625,15626,15627,15628,15629,15630,15631, |
| 93936 | 15632,15633,15634,15635,15636,15637,15638,15639,15640,15641,15642,15643, |
| 93937 | 15644,15645,15646,15647,15648,15649,15650,15651,15652,15653,15654,15655, |
| 93938 | 15656,15657,15658,15659,15660,15661,15662,15663,15664,15665,15666,15667, |
| 93939 | 15668,15669,15670,15671,15672,15673,15674,15675,15676,15677,15678,15679, |
| 93940 | 15680,15681,15682,15683,15684,15685,15686,15687,15688,15689,15690,15691, |
| 93941 | 15692,15693,15694,15695,15696,15697,15698,15699,15700,15701,15702,15703, |
| 93942 | 15704,15705,15706,15707,15708,15709,15710,15711,15712,15713,15714,15715, |
| 93943 | 15716,15717,15718,15719,15720,15721,15722,15723,15724,15725,15726,15727, |
| 93944 | 15728,15729,15730,15731,15732,15733,15734,15735,15736,15737,15738,15739, |
| 93945 | 15740,15741,15742,15743,15744,15745,15746,15747,15748,15749,15750,15751, |
| 93946 | 15752,15753,15754,15755,15756,15757,15758,15759,15760,15761,15762,15763, |
| 93947 | 15764,15765,15766,15767,15768,15769,15770,15771,15772,15773,15774,15775, |
| 93948 | 15776,15777,15778,15779,15780,15781,15782,15783,15784,15785,15786,15787, |
| 93949 | 15788,15789,15790,15791,15792,15793,15794,15795,15796,15797,15798,15799, |
| 93950 | 15800,15801,15802,15803,15804,15805,15806,15807,15808,15809,15810,15811, |
| 93951 | 15812,15813,15814,15815,15816,15817,15818,15819,15820,15821,15822,15823, |
| 93952 | 15824,15825,15826,15827,15828,15829,15830,15831,15832,15833,15834,15835, |
| 93953 | 15836,15837,15838,15839,15840,15841,15842,15843,15844,15845,15846,15847, |
| 93954 | 15848,15849,15850,15851,15852,15853,15854,15855,15856,15857,15858,15859, |
| 93955 | 15860,15861,15862,15863,15864,15865,15866,15867,15868,15869,15870,15871, |
| 93956 | 15872,15873,15874,15875,15876,15877,15878,15879,15880,15881,15882,15883, |
| 93957 | 15884,15885,15886,15887,15888,15889,15890,15891,15892,15893,15894,15895, |
| 93958 | 15896,15897,15898,15899,15900,15901,15902,15903,15904,15905,15906,15907, |
| 93959 | 15908,15909,15910,15911,15912,15913,15914,15915,15916,15917,15918,15919, |
| 93960 | 15920,15921,15922,15923,15924,15925,15926,15927,15928,15929,15930,15931, |
| 93961 | 15932,15933,15934,15935,15936,15937,15938,15939,15940,15941,15942,15943, |
| 93962 | 15944,15945,15946,15947,15948,15949,15950,15951,15952,15953,15954,15955, |
| 93963 | 15956,15957,15958,15959,15960,15961,15962,15963,15964,15965,15966,15967, |
| 93964 | 15968,15969,15970,15971,15972,15973,15974,15975,15976,15977,15978,15979, |
| 93965 | 15980,15981,15982,15983,15984,15985,15986,15987,15988,15989,15990,15991, |
| 93966 | 15992,15993,15994,15995,15996,15997,15998,15999,16000,16001,16002,16003, |
| 93967 | 16004,16005,16006,16007,16008,16009,16010,16011,16012,16013,16014,16015, |
| 93968 | 16016,16017,16018,16019,16020,16021,16022,16023,16024,16025,16026,16027, |
| 93969 | 16028,16029,16030,16031,16032,16033,16034,16035,16036,16037,16038,16039, |
| 93970 | 16040,16041,16042,16043,16044,16045,16046,16047,16048,16049,16050,16051, |
| 93971 | 16052,16053,16054,16055,16056,16057,16058,16059,16060,16061,16062,16063, |
| 93972 | 16064,16065,16066,16067,16068,16069,16070,16071,16072,16073,16074,16075, |
| 93973 | 16076,16077,16078,16079,16080,16081,16082,16083,16084,16085,16086,16087, |
| 93974 | 16088,16089,16090,16091,16092,16093,16094,16095,16096,16097,16098,16099, |
| 93975 | 16100,16101,16102,16103,16104,16105,16106,16107,16108,16109,16110,16111, |
| 93976 | 16112,16113,16114,16115,16116,16117,16118,16119,16120,16121,16122,16123, |
| 93977 | 16124,16125,16126,16127,16128,16129,16130,16131,16132,16133,16134,16135, |
| 93978 | 16136,16137,16138,16139,16140,16141,16142,16143,16144,16145,16146,16147, |
| 93979 | 16148,16149,16150,16151,16152,16153,16154,16155,16156,16157,16158,16159, |
| 93980 | 16160,16161,16162,16163,16164,16165,16166,16167,16168,16169,16170,16171, |
| 93981 | 16172,16173,16174,16175,16176,16177,16178,16179,16180,16181,16182,16183, |
| 93982 | 16184,16185,16186,16187,16188,16189,16190,16191,16192,16193,16194,16195, |
| 93983 | 16196,16197,16198,16199,16200,16201,16202,16203,16204,16205,16206,16207, |
| 93984 | 16208,16209,16210,16211,16212,16213,16214,16215,16216,16217,16218,16219, |
| 93985 | 16220,16221,16222,16223,16224,16225,16226,16227,16228,16229,16230,16231, |
| 93986 | 16232,16233,16234,16235,16236,16237,16238,16239,16240,16241,16242,16243, |
| 93987 | 16244,16245,16246,16247,16248,16249,16250,16251,16252,16253,16254,16255, |
| 93988 | 16256,16257,16258,16259,16260,16261,16262,16263,16264,16265,16266,16267, |
| 93989 | 16268,16269,16270,16271,16272,16273,16274,16275,16276,16277,16278,16279, |
| 93990 | 16280,16281,16282,16283,16284,16285,16286,16287,16288,16289,16290,16291, |
| 93991 | 16292,16293,16294,16295,16296,16297,16298,16299,16300,16301,16302,16303, |
| 93992 | 16304,16305,16306,16307,16308,16309,16310,16311,16312,16313,16314,16315, |
| 93993 | 16316,16317,16318,16319,16320,16321,16322,16323,16324,16325,16326,16327, |
| 93994 | 16328,16329,16330,16331,16332,16333,16334,16335,16336,16337,16338,16339, |
| 93995 | 16340,16341,16342,16343,16344,16345,16346,16347,16348,16349,16350,16351, |
| 93996 | 16352,16353,16354,16355,16356,16357,16358,16359,16360,16361,16362,16363, |
| 93997 | 16364,16365,16366,16367,16368,16369,16370,16371,16372,16373,16374,16375, |
| 93998 | 16376,16377,16378,16379,16380,16381,16382,16383,16384,16385,16386,16387, |
| 93999 | 16388,16389,16390,16391,16392,16393,16394,16395,16396,16397,16398,16399, |
| 94000 | 16400,16401,16402,16403,16404,16405,16406,16407,16408,16409,16410,16411, |
| 94001 | 16412,16413,16414,16415,16416,16417,16418,16419,16420,16421,16422,16423, |
| 94002 | 16424,16425,16426,16427,16428,16429,16430,16431,16432,16433,16434,16435, |
| 94003 | 16436,16437,16438,16439,16440,16441,16442,16443,16444,16445,16446,16447, |
| 94004 | 16448,16449,16450,16451,16452,16453,16454,16455,16456,16457,16458,16459, |
| 94005 | 16460,16461,16462,16463,16464,16465,16466,16467,16468,16469,16470,16471, |
| 94006 | 16472,16473,16474,16475,16476,16477,16478,16479,16480,16481,16482,16483, |
| 94007 | 16484,16485,16486,16487,16488,16489,16490,16491,16492,16493,16494,16495, |
| 94008 | 16496,16497,16498,16499,16500,16501,16502,16503,16504,16505,16506,16507, |
| 94009 | 16508,16509,16510,16511,16512,16513,16514,16515,16516,16517,16518,16519, |
| 94010 | 16520,16521,16522,16523,16524,16525,16526,16527,16528,16529,16530,16531, |
| 94011 | 16532,16533,16534,16535,16536,16537,16538,16539,16540,16541,16542,16543, |
| 94012 | 16544,16545,16546,16547,16548,16549,16550,16551,16552,16553,16554,16555, |
| 94013 | 16556,16557,16558,16559,16560,16561,16562,16563,16564,16565,16566,16567, |
| 94014 | 16568,16569,16570,16571,16572,16573,16574,16575,16576,16577,16578,16579, |
| 94015 | 16580,16581,16582,16583,16584,16585,16586,16587,16588,16589,16590,16591, |
| 94016 | 16592,16593,16594,16595,16596,16597,16598,16599,16600,16601,16602,16603, |
| 94017 | 16604,16605,16606,16607,16608,16609,16610,16611,16612,16613,16614,16615, |
| 94018 | 16616,16617,16618,16619,16620,16621,16622,16623,16624,16625,16626,16627, |
| 94019 | 16628,16629,16630,16631,16632,16633,16634,16635,16636,16637,16638,16639, |
| 94020 | 16640,16641,16642,16643,16644,16645,16646,16647,16648,16649,16650,16651, |
| 94021 | 16652,16653,16654,16655,16656,16657,16658,16659,16660,16661,16662,16663, |
| 94022 | 16664,16665,16666,16667,16668,16669,16670,16671,16672,16673,16674,16675, |
| 94023 | 16676,16677,16678,16679,16680,16681,16682,16683,16684,16685,16686,16687, |
| 94024 | 16688,16689,16690,16691,16692,16693,16694,16695,16696,16697,16698,16699, |
| 94025 | 16700,16701,16702,16703,16704,16705,16706,16707,16708,16709,16710,16711, |
| 94026 | 16712,16713,16714,16715,16716,16717,16718,16719,16720,16721,16722,16723, |
| 94027 | 16724,16725,16726,16727,16728,16729,16730,16731,16732,16733,16734,16735, |
| 94028 | 16736,16737,16738,16739,16740,16741,16742,16743,16744,16745,16746,16747, |
| 94029 | 16748,16749,16750,16751,16752,16753,16754,16755,16756,16757,16758,16759, |
| 94030 | 16760,16761,16762,16763,16764,16765,16766,16767,16768,16769,16770,16771, |
| 94031 | 16772,16773,16774,16775,16776,16777,16778,16779,16780,16781,16782,16783, |
| 94032 | 16784,16785,16786,16787,16788,16789,16790,16791,16792,16793,16794,16795, |
| 94033 | 16796,16797,16798,16799,16800,16801,16802,16803,16804,16805,16806,16807, |
| 94034 | 16808,16809,16810,16811,16812,16813,16814,16815,16816,16817,16818,16819, |
| 94035 | 16820,16821,16822,16823,16824,16825,16826,16827,16828,16829,16830,16831, |
| 94036 | 16832,16833,16834,16835,16836,16837,16838,16839,16840,16841,16842,16843, |
| 94037 | 16844,16845,16846,16847,16848,16849,16850,16851,16852,16853,16854,16855, |
| 94038 | 16856,16857,16858,16859,16860,16861,16862,16863,16864,16865,16866,16867, |
| 94039 | 16868,16869,16870,16871,16872,16873,16874,16875,16876,16877,16878,16879, |
| 94040 | 16880,16881,16882,16883,16884,16885,16886,16887,16888,16889,16890,16891, |
| 94041 | 16892,16893,16894,16895,16896,16897,16898,16899,16900,16901,16902,16903, |
| 94042 | 16904,16905,16906,16907,16908,16909,16910,16911,16912,16913,16914,16915, |
| 94043 | 16916,16917,16918,16919,16920,16921,16922,16923,16924,16925,16926,16927, |
| 94044 | 16928,16929,16930,16931,16932,16933,16934,16935,16936,16937,16938,16939, |
| 94045 | 16940,16941,16942,16943,16944,16945,16946,16947,16948,16949,16950,16951, |
| 94046 | 16952,16953,16954,16955,16956,16957,16958,16959,16960,16961,16962,16963, |
| 94047 | 16964,16965,16966,16967,16968,16969,16970,16971,16972,16973,16974,16975, |
| 94048 | 16976,16977,16978,16979,16980,16981,16982,16983,16984,16985,16986,16987, |
| 94049 | 16988,16989,16990,16991,16992,16993,16994,16995,16996,16997,16998,16999, |
| 94050 | 17000,17001,17002,17003,17004,17005,17006,17007,17008,17009,17010,17011, |
| 94051 | 17012,17013,17014,17015,17016,17017,17018,17019,17020,17021,17022,17023, |
| 94052 | 17024,17025,17026,17027,17028,17029,17030,17031,17032,17033,17034,17035, |
| 94053 | 17036,17037,17038,17039,17040,17041,17042,17043,17044,17045,17046,17047, |
| 94054 | 17048,17049,17050,17051,17052,17053,17054,17055,17056,17057,17058,17059, |
| 94055 | 17060,17061,17062,17063,17064,17065,17066,17067,17068,17069,17070,17071, |
| 94056 | 17072,17073,17074,17075,17076,17077,17078,17079,17080,17081,17082,17083, |
| 94057 | 17084,17085,17086,17087,17088,17089,17090,17091,17092,17093,17094,17095, |
| 94058 | 17096,17097,17098,17099,17100,17101,17102,17103,17104,17105,17106,17107, |
| 94059 | 17108,17109,17110,17111,17112,17113,17114,17115,17116,17117,17118,17119, |
| 94060 | 17120,17121,17122,17123,17124,17125,17126,17127,17128,17129,17130,17131, |
| 94061 | 17132,17133,17134,17135,17136,17137,17138,17139,17140,17141,17142,17143, |
| 94062 | 17144,17145,17146,17147,17148,17149,17150,17151,17152,17153,17154,17155, |
| 94063 | 17156,17157,17158,17159,17160,17161,17162,17163,17164,17165,17166,17167, |
| 94064 | 17168,17169,17170,17171,17172,17173,17174,17175,17176,17177,17178,17179, |
| 94065 | 17180,17181,17182,17183,17184,17185,17186,17187,17188,17189,17190,17191, |
| 94066 | 17192,17193,17194,17195,17196,17197,17198,17199,17200,17201,17202,17203, |
| 94067 | 17204,17205,17206,17207,17208,17209,17210,17211,17212,17213,17214,17215, |
| 94068 | 17216,17217,17218,17219,17220,17221,17222,17223,17224,17225,17226,17227, |
| 94069 | 17228,17229,17230,17231,17232,17233,17234,17235,17236,17237,17238,17239, |
| 94070 | 17240,17241,17242,17243,17244,17245,17246,17247,17248,17249,17250,17251, |
| 94071 | 17252,17253,17254,17255,17256,17257,17258,17259,17260,17261,17262,17263, |
| 94072 | 17264,17265,17266,17267,17268,17269,17270,17271,17272,17273,17274,17275, |
| 94073 | 17276,17277,17278,17279,17280,17281,17282,17283,17284,17285,17286,17287, |
| 94074 | 17288,17289,17290,17291,17292,17293,17294,17295,17296,17297,17298,17299, |
| 94075 | 17300,17301,17302,17303,17304,17305,17306,17307,17308,17309,17310,17311, |
| 94076 | 17312,17313,17314,17315,17316,17317,17318,17319,17320,17321,17322,17323, |
| 94077 | 17324,17325,17326,17327,17328,17329,17330,17331,17332,17333,17334,17335, |
| 94078 | 17336,17337,17338,17339,17340,17341,17342,17343,17344,17345,17346,17347, |
| 94079 | 17348,17349,17350,17351,17352,17353,17354,17355,17356,17357,17358,17359, |
| 94080 | 17360,17361,17362,17363,17364,17365,17366,17367,17368,17369,17370,17371, |
| 94081 | 17372,17373,17374,17375,17376,17377,17378,17379,17380,17381,17382,17383, |
| 94082 | 17384,17385,17386,17387,17388,17389,17390,17391,17392,17393,17394,17395, |
| 94083 | 17396,17397,17398,17399,17400,17401,17402,17403,17404,17405,17406,17407, |
| 94084 | 17408,17409,17410,17411,17412,17413,17414,17415,17416,17417,17418,17419, |
| 94085 | 17420,17421,17422,17423,17424,17425,17426,17427,17428,17429,17430,17431, |
| 94086 | 17432,17433,17434,17435,17436,17437,17438,17439,17440,17441,17442,17443, |
| 94087 | 17444,17445,17446,17447,17448,17449,17450,17451,17452,17453,17454,17455, |
| 94088 | 17456,17457,17458,17459,17460,17461,17462,17463,17464,17465,17466,17467, |
| 94089 | 17468,17469,17470,17471,17472,17473,17474,17475,17476,17477,17478,17479, |
| 94090 | 17480,17481,17482,17483,17484,17485,17486,17487,17488,17489,17490,17491, |
| 94091 | 17492,17493,17494,17495,17496,17497,17498,17499,17500,17501,17502,17503, |
| 94092 | 17504,17505,17506,17507,17508,17509,17510,17511,17512,17513,17514,17515, |
| 94093 | 17516,17517,17518,17519,17520,17521,17522,17523,17524,17525,17526,17527, |
| 94094 | 17528,17529,17530,17531,17532,17533,17534,17535,17536,17537,17538,17539, |
| 94095 | 17540,17541,17542,17543,17544,17545,17546,17547,17548,17549,17550,17551, |
| 94096 | 17552,17553,17554,17555,17556,17557,17558,17559,17560,17561,17562,17563, |
| 94097 | 17564,17565,17566,17567,17568,17569,17570,17571,17572,17573,17574,17575, |
| 94098 | 17576,17577,17578,17579,17580,17581,17582,17583,17584,17585,17586,17587, |
| 94099 | 17588,17589,17590,17591,17592,17593,17594,17595,17596,17597,17598,17599, |
| 94100 | 17600,17601,17602,17603,17604,17605,17606,17607,17608,17609,17610,17611, |
| 94101 | 17612,17613,17614,17615,17616,17617,17618,17619,17620,17621,17622,17623, |
| 94102 | 17624,17625,17626,17627,17628,17629,17630,17631,17632,17633,17634,17635, |
| 94103 | 17636,17637,17638,17639,17640,17641,17642,17643,17644,17645,17646,17647, |
| 94104 | 17648,17649,17650,17651,17652,17653,17654,17655,17656,17657,17658,17659, |
| 94105 | 17660,17661,17662,17663,17664,17665,17666,17667,17668,17669,17670,17671, |
| 94106 | 17672,17673,17674,17675,17676,17677,17678,17679,17680,17681,17682,17683, |
| 94107 | 17684,17685,17686,17687,17688,17689,17690,17691,17692,17693,17694,17695, |
| 94108 | 17696,17697,17698,17699,17700,17701,17702,17703,17704,17705,17706,17707, |
| 94109 | 17708,17709,17710,17711,17712,17713,17714,17715,17716,17717,17718,17719, |
| 94110 | 17720,17721,17722,17723,17724,17725,17726,17727,17728,17729,17730,17731, |
| 94111 | 17732,17733,17734,17735,17736,17737,17738,17739,17740,17741,17742,17743, |
| 94112 | 17744,17745,17746,17747,17748,17749,17750,17751,17752,17753,17754,17755, |
| 94113 | 17756,17757,17758,17759,17760,17761,17762,17763,17764,17765,17766,17767, |
| 94114 | 17768,17769,17770,17771,17772,17773,17774,17775,17776,17777,17778,17779, |
| 94115 | 17780,17781,17782,17783,17784,17785,17786,17787,17788,17789,17790,17791, |
| 94116 | 17792,17793,17794,17795,17796,17797,17798,17799,17800,17801,17802,17803, |
| 94117 | 17804,17805,17806,17807,17808,17809,17810,17811,17812,17813,17814,17815, |
| 94118 | 17816,17817,17818,17819,17820,17821,17822,17823,17824,17825,17826,17827, |
| 94119 | 17828,17829,17830,17831,17832,17833,17834,17835,17836,17837,17838,17839, |
| 94120 | 17840,17841,17842,17843,17844,17845,17846,17847,17848,17849,17850,17851, |
| 94121 | 17852,17853,17854,17855,17856,17857,17858,17859,17860,17861,17862,17863, |
| 94122 | 17864,17865,17866,17867,17868,17869,17870,17871,17872,17873,17874,17875, |
| 94123 | 17876,17877,17878,17879,17880,17881,17882,17883,17884,17885,17886,17887, |
| 94124 | 17888,17889,17890,17891,17892,17893,17894,17895,17896,17897,17898,17899, |
| 94125 | 17900,17901,17902,17903,17904,17905,17906,17907,17908,17909,17910,17911, |
| 94126 | 17912,17913,17914,17915,17916,17917,17918,17919,17920,17921,17922,17923, |
| 94127 | 17924,17925,17926,17927,17928,17929,17930,17931,17932,17933,17934,17935, |
| 94128 | 17936,17937,17938,17939,17940,17941,17942,17943,17944,17945,17946,17947, |
| 94129 | 17948,17949,17950,17951,17952,17953,17954,17955,17956,17957,17958,17959, |
| 94130 | 17960,17961,17962,17963,17964,17965,17966,17967,17968,17969,17970,17971, |
| 94131 | 17972,17973,17974,17975,17976,17977,17978,17979,17980,17981,17982,17983, |
| 94132 | 17984,17985,17986,17987,17988,17989,17990,17991,17992,17993,17994,17995, |
| 94133 | 17996,17997,17998,17999,18000,18001,18002,18003,18004,18005,18006,18007, |
| 94134 | 18008,18009,18010,18011,18012,18013,18014,18015,18016,18017,18018,18019, |
| 94135 | 18020,18021,18022,18023,18024,18025,18026,18027,18028,18029,18030,18031, |
| 94136 | 18032,18033,18034,18035,18036,18037,18038,18039,18040,18041,18042,18043, |
| 94137 | 18044,18045,18046,18047,18048,18049,18050,18051,18052,18053,18054,18055, |
| 94138 | 18056,18057,18058,18059,18060,18061,18062,18063,18064,18065,18066,18067, |
| 94139 | 18068,18069,18070,18071,18072,18073,18074,18075,18076,18077,18078,18079, |
| 94140 | 18080,18081,18082,18083,18084,18085,18086,18087,18088,18089,18090,18091, |
| 94141 | 18092,18093,18094,18095,18096,18097,18098,18099,18100,18101,18102,18103, |
| 94142 | 18104,18105,18106,18107,18108,18109,18110,18111,18112,18113,18114,18115, |
| 94143 | 18116,18117,18118,18119,18120,18121,18122,18123,18124,18125,18126,18127, |
| 94144 | 18128,18129,18130,18131,18132,18133,18134,18135,18136,18137,18138,18139, |
| 94145 | 18140,18141,18142,18143,18144,18145,18146,18147,18148,18149,18150,18151, |
| 94146 | 18152,18153,18154,18155,18156,18157,18158,18159,18160,18161,18162,18163, |
| 94147 | 18164,18165,18166,18167,18168,18169,18170,18171,18172,18173,18174,18175, |
| 94148 | 18176,18177,18178,18179,18180,18181,18182,18183,18184,18185,18186,18187, |
| 94149 | 18188,18189,18190,18191,18192,18193,18194,18195,18196,18197,18198,18199, |
| 94150 | 18200,18201,18202,18203,18204,18205,18206,18207,18208,18209,18210,18211, |
| 94151 | 18212,18213,18214,18215,18216,18217,18218,18219,18220,18221,18222,18223, |
| 94152 | 18224,18225,18226,18227,18228,18229,18230,18231,18232,18233,18234,18235, |
| 94153 | 18236,18237,18238,18239,18240,18241,18242,18243,18244,18245,18246,18247, |
| 94154 | 18248,18249,18250,18251,18252,18253,18254,18255,18256,18257,18258,18259, |
| 94155 | 18260,18261,18262,18263,18264,18265,18266,18267,18268,18269,18270,18271, |
| 94156 | 18272,18273,18274,18275,18276,18277,18278,18279,18280,18281,18282,18283, |
| 94157 | 18284,18285,18286,18287,18288,18289,18290,18291,18292,18293,18294,18295, |
| 94158 | 18296,18297,18298,18299,18300,18301,18302,18303,18304,18305,18306,18307, |
| 94159 | 18308,18309,18310,18311,18312,18313,18314,18315,18316,18317,18318,18319, |
| 94160 | 18320,18321,18322,18323,18324,18325,18326,18327,18328,18329,18330,18331, |
| 94161 | 18332,18333,18334,18335,18336,18337,18338,18339,18340,18341,18342,18343, |
| 94162 | 18344,18345,18346,18347,18348,18349,18350,18351,18352,18353,18354,18355, |
| 94163 | 18356,18357,18358,18359,18360,18361,18362,18363,18364,18365,18366,18367, |
| 94164 | 18368,18369,18370,18371,18372,18373,18374,18375,18376,18377,18378,18379, |
| 94165 | 18380,18381,18382,18383,18384,18385,18386,18387,18388,18389,18390,18391, |
| 94166 | 18392,18393,18394,18395,18396,18397,18398,18399,18400,18401,18402,18403, |
| 94167 | 18404,18405,18406,18407,18408,18409,18410,18411,18412,18413,18414,18415, |
| 94168 | 18416,18417,18418,18419,18420,18421,18422,18423,18424,18425,18426,18427, |
| 94169 | 18428,18429,18430,18431,18432,18433,18434,18435,18436,18437,18438,18439, |
| 94170 | 18440,18441,18442,18443,18444,18445,18446,18447,18448,18449,18450,18451, |
| 94171 | 18452,18453,18454,18455,18456,18457,18458,18459,18460,18461,18462,18463, |
| 94172 | 18464,18465,18466,18467,18468,18469,18470,18471,18472,18473,18474,18475, |
| 94173 | 18476,18477,18478,18479,18480,18481,18482,18483,18484,18485,18486,18487, |
| 94174 | 18488,18489,18490,18491,18492,18493,18494,18495,18496,18497,18498,18499, |
| 94175 | 18500,18501,18502,18503,18504,18505,18506,18507,18508,18509,18510,18511, |
| 94176 | 18512,18513,18514,18515,18516,18517,18518,18519,18520,18521,18522,18523, |
| 94177 | 18524,18525,18526,18527,18528,18529,18530,18531,18532,18533,18534,18535, |
| 94178 | 18536,18537,18538,18539,18540,18541,18542,18543,18544,18545,18546,18547, |
| 94179 | 18548,18549,18550,18551,18552,18553,18554,18555,18556,18557,18558,18559, |
| 94180 | 18560,18561,18562,18563,18564,18565,18566,18567,18568,18569,18570,18571, |
| 94181 | 18572,18573,18574,18575,18576,18577,18578,18579,18580,18581,18582,18583, |
| 94182 | 18584,18585,18586,18587,18588,18589,18590,18591,18592,18593,18594,18595, |
| 94183 | 18596,18597,18598,18599,18600,18601,18602,18603,18604,18605,18606,18607, |
| 94184 | 18608,18609,18610,18611,18612,18613,18614,18615,18616,18617,18618,18619, |
| 94185 | 18620,18621,18622,18623,18624,18625,18626,18627,18628,18629,18630,18631, |
| 94186 | 18632,18633,18634,18635,18636,18637,18638,18639,18640,18641,18642,18643, |
| 94187 | 18644,18645,18646,18647,18648,18649,18650,18651,18652,18653,18654,18655, |
| 94188 | 18656,18657,18658,18659,18660,18661,18662,18663,18664,18665,18666,18667, |
| 94189 | 18668,18669,18670,18671,18672,18673,18674,18675,18676,18677,18678,18679, |
| 94190 | 18680,18681,18682,18683,18684,18685,18686,18687,18688,18689,18690,18691, |
| 94191 | 18692,18693,18694,18695,18696,18697,18698,18699,18700,18701,18702,18703, |
| 94192 | 18704,18705,18706,18707,18708,18709,18710,18711,18712,18713,18714,18715, |
| 94193 | 18716,18717,18718,18719,18720,18721,18722,18723,18724,18725,18726,18727, |
| 94194 | 18728,18729,18730,18731,18732,18733,18734,18735,18736,18737,18738,18739, |
| 94195 | 18740,18741,18742,18743,18744,18745,18746,18747,18748,18749,18750,18751, |
| 94196 | 18752,18753,18754,18755,18756,18757,18758,18759,18760,18761,18762,18763, |
| 94197 | 18764,18765,18766,18767,18768,18769,18770,18771,18772,18773,18774,18775, |
| 94198 | 18776,18777,18778,18779,18780,18781,18782,18783,18784,18785,18786,18787, |
| 94199 | 18788,18789,18790,18791,18792,18793,18794,18795,18796,18797,18798,18799, |
| 94200 | 18800,18801,18802,18803,18804,18805,18806,18807,18808,18809,18810,18811, |
| 94201 | 18812,18813,18814,18815,18816,18817,18818,18819,18820,18821,18822,18823, |
| 94202 | 18824,18825,18826,18827,18828,18829,18830,18831,18832,18833,18834,18835, |
| 94203 | 18836,18837,18838,18839,18840,18841,18842,18843,18844,18845,18846,18847, |
| 94204 | 18848,18849,18850,18851,18852,18853,18854,18855,18856,18857,18858,18859, |
| 94205 | 18860,18861,18862,18863,18864,18865,18866,18867,18868,18869,18870,18871, |
| 94206 | 18872,18873,18874,18875,18876,18877,18878,18879,18880,18881,18882,18883, |
| 94207 | 18884,18885,18886,18887,18888,18889,18890,18891,18892,18893,18894,18895, |
| 94208 | 18896,18897,18898,18899,18900,18901,18902,18903,18904,18905,18906,18907, |
| 94209 | 18908,18909,18910,18911,18912,18913,18914,18915,18916,18917,18918,18919, |
| 94210 | 18920,18921,18922,18923,18924,18925,18926,18927,18928,18929,18930,18931, |
| 94211 | 18932,18933,18934,18935,18936,18937,18938,18939,18940,18941,18942,18943, |
| 94212 | 18944,18945,18946,18947,18948,18949,18950,18951,18952,18953,18954,18955, |
| 94213 | 18956,18957,18958,18959,18960,18961,18962,18963,18964,18965,18966,18967, |
| 94214 | 18968,18969,18970,18971,18972,18973,18974,18975,18976,18977,18978,18979, |
| 94215 | 18980,18981,18982,18983,18984,18985,18986,18987,18988,18989,18990,18991, |
| 94216 | 18992,18993,18994,18995,18996,18997,18998,18999,19000,19001,19002,19003, |
| 94217 | 19004,19005,19006,19007,19008,19009,19010,19011,19012,19013,19014,19015, |
| 94218 | 19016,19017,19018,19019,19020,19021,19022,19023,19024,19025,19026,19027, |
| 94219 | 19028,19029,19030,19031,19032,19033,19034,19035,19036,19037,19038,19039, |
| 94220 | 19040,19041,19042,19043,19044,19045,19046,19047,19048,19049,19050,19051, |
| 94221 | 19052,19053,19054,19055,19056,19057,19058,19059,19060,19061,19062,19063, |
| 94222 | 19064,19065,19066,19067,19068,19069,19070,19071,19072,19073,19074,19075, |
| 94223 | 19076,19077,19078,19079,19080,19081,19082,19083,19084,19085,19086,19087, |
| 94224 | 19088,19089,19090,19091,19092,19093,19094,19095,19096,19097,19098,19099, |
| 94225 | 19100,19101,19102,19103,19104,19105,19106,19107,19108,19109,19110,19111, |
| 94226 | 19112,19113,19114,19115,19116,19117,19118,19119,19120,19121,19122,19123, |
| 94227 | 19124,19125,19126,19127,19128,19129,19130,19131,19132,19133,19134,19135, |
| 94228 | 19136,19137,19138,19139,19140,19141,19142,19143,19144,19145,19146,19147, |
| 94229 | 19148,19149,19150,19151,19152,19153,19154,19155,19156,19157,19158,19159, |
| 94230 | 19160,19161,19162,19163,19164,19165,19166,19167,19168,19169,19170,19171, |
| 94231 | 19172,19173,19174,19175,19176,19177,19178,19179,19180,19181,19182,19183, |
| 94232 | 19184,19185,19186,19187,19188,19189,19190,19191,19192,19193,19194,19195, |
| 94233 | 19196,19197,19198,19199,19200,19201,19202,19203,19204,19205,19206,19207, |
| 94234 | 19208,19209,19210,19211,19212,19213,19214,19215,19216,19217,19218,19219, |
| 94235 | 19220,19221,19222,19223,19224,19225,19226,19227,19228,19229,19230,19231, |
| 94236 | 19232,19233,19234,19235,19236,19237,19238,19239,19240,19241,19242,19243, |
| 94237 | 19244,19245,19246,19247,19248,19249,19250,19251,19252,19253,19254,19255, |
| 94238 | 19256,19257,19258,19259,19260,19261,19262,19263,19264,19265,19266,19267, |
| 94239 | 19268,19269,19270,19271,19272,19273,19274,19275,19276,19277,19278,19279, |
| 94240 | 19280,19281,19282,19283,19284,19285,19286,19287,19288,19289,19290,19291, |
| 94241 | 19292,19293,19294,19295,19296,19297,19298,19299,19300,19301,19302,19303, |
| 94242 | 19304,19305,19306,19307,19308,19309,19310,19311,19312,19313,19314,19315, |
| 94243 | 19316,19317,19318,19319,19320,19321,19322,19323,19324,19325,19326,19327, |
| 94244 | 19328,19329,19330,19331,19332,19333,19334,19335,19336,19337,19338,19339, |
| 94245 | 19340,19341,19342,19343,19344,19345,19346,19347,19348,19349,19350,19351, |
| 94246 | 19352,19353,19354,19355,19356,19357,19358,19359,19360,19361,19362,19363, |
| 94247 | 19364,19365,19366,19367,19368,19369,19370,19371,19372,19373,19374,19375, |
| 94248 | 19376,19377,19378,19379,19380,19381,19382,19383,19384,19385,19386,19387, |
| 94249 | 19388,19389,19390,19391,19392,19393,19394,19395,19396,19397,19398,19399, |
| 94250 | 19400,19401,19402,19403,19404,19405,19406,19407,19408,19409,19410,19411, |
| 94251 | 19412,19413,19414,19415,19416,19417,19418,19419,19420,19421,19422,19423, |
| 94252 | 19424,19425,19426,19427,19428,19429,19430,19431,19432,19433,19434,19435, |
| 94253 | 19436,19437,19438,19439,19440,19441,19442,19443,19444,19445,19446,19447, |
| 94254 | 19448,19449,19450,19451,19452,19453,19454,19455,19456,19457,19458,19459, |
| 94255 | 19460,19461,19462,19463,19464,19465,19466,19467,19468,19469,19470,19471, |
| 94256 | 19472,19473,19474,19475,19476,19477,19478,19479,19480,19481,19482,19483, |
| 94257 | 19484,19485,19486,19487,19488,19489,19490,19491,19492,19493,19494,19495, |
| 94258 | 19496,19497,19498,19499,19500,19501,19502,19503,19504,19505,19506,19507, |
| 94259 | 19508,19509,19510,19511,19512,19513,19514,19515,19516,19517,19518,19519, |
| 94260 | 19520,19521,19522,19523,19524,19525,19526,19527,19528,19529,19530,19531, |
| 94261 | 19532,19533,19534,19535,19536,19537,19538,19539,19540,19541,19542,19543, |
| 94262 | 19544,19545,19546,19547,19548,19549,19550,19551,19552,19553,19554,19555, |
| 94263 | 19556,19557,19558,19559,19560,19561,19562,19563,19564,19565,19566,19567, |
| 94264 | 19568,19569,19570,19571,19572,19573,19574,19575,19576,19577,19578,19579, |
| 94265 | 19580,19581,19582,19583,19584,19585,19586,19587,19588,19589,19590,19591, |
| 94266 | 19592,19593,19594,19595,19596,19597,19598,19599,19600,19601,19602,19603, |
| 94267 | 19604,19605,19606,19607,19608,19609,19610,19611,19612,19613,19614,19615, |
| 94268 | 19616,19617,19618,19619,19620,19621,19622,19623,19624,19625,19626,19627, |
| 94269 | 19628,19629,19630,19631,19632,19633,19634,19635,19636,19637,19638,19639, |
| 94270 | 19640,19641,19642,19643,19644,19645,19646,19647,19648,19649,19650,19651, |
| 94271 | 19652,19653,19654,19655,19656,19657,19658,19659,19660,19661,19662,19663, |
| 94272 | 19664,19665,19666,19667,19668,19669,19670,19671,19672,19673,19674,19675, |
| 94273 | 19676,19677,19678,19679,19680,19681,19682,19683,19684,19685,19686,19687, |
| 94274 | 19688,19689,19690,19691,19692,19693,19694,19695,19696,19697,19698,19699, |
| 94275 | 19700,19701,19702,19703,19704,19705,19706,19707,19708,19709,19710,19711, |
| 94276 | 19712,19713,19714,19715,19716,19717,19718,19719,19720,19721,19722,19723, |
| 94277 | 19724,19725,19726,19727,19728,19729,19730,19731,19732,19733,19734,19735, |
| 94278 | 19736,19737,19738,19739,19740,19741,19742,19743,19744,19745,19746,19747, |
| 94279 | 19748,19749,19750,19751,19752,19753,19754,19755,19756,19757,19758,19759, |
| 94280 | 19760,19761,19762,19763,19764,19765,19766,19767,19768,19769,19770,19771, |
| 94281 | 19772,19773,19774,19775,19776,19777,19778,19779,19780,19781,19782,19783, |
| 94282 | 19784,19785,19786,19787,19788,19789,19790,19791,19792,19793,19794,19795, |
| 94283 | 19796,19797,19798,19799,19800,19801,19802,19803,19804,19805,19806,19807, |
| 94284 | 19808,19809,19810,19811,19812,19813,19814,19815,19816,19817,19818,19819, |
| 94285 | 19820,19821,19822,19823,19824,19825,19826,19827,19828,19829,19830,19831, |
| 94286 | 19832,19833,19834,19835,19836,19837,19838,19839,19840,19841,19842,19843, |
| 94287 | 19844,19845,19846,19847,19848,19849,19850,19851,19852,19853,19854,19855, |
| 94288 | 19856,19857,19858,19859,19860,19861,19862,19863,19864,19865,19866,19867, |
| 94289 | 19868,19869,19870,19871,19872,19873,19874,19875,19876,19877,19878,19879, |
| 94290 | 19880,19881,19882,19883,19884,19885,19886,19887,19888,19889,19890,19891, |
| 94291 | 19892,19893,19894,19895,19896,19897,19898,19899,19900,19901,19902,19903, |
| 94292 | 19904,19905,19906,19907,19908,19909,19910,19911,19912,19913,19914,19915, |
| 94293 | 19916,19917,19918,19919,19920,19921,19922,19923,19924,19925,19926,19927, |
| 94294 | 19928,19929,19930,19931,19932,19933,19934,19935,19936,19937,19938,19939, |
| 94295 | 19940,19941,19942,19943,19944,19945,19946,19947,19948,19949,19950,19951, |
| 94296 | 19952,19953,19954,19955,19956,19957,19958,19959,19960,19961,19962,19963, |
| 94297 | 19964,19965,19966,19967,19968,19969,19970,19971,19972,19973,19974,19975, |
| 94298 | 19976,19977,19978,19979,19980,19981,19982,19983,19984,19985,19986,19987, |
| 94299 | 19988,19989,19990,19991,19992,19993,19994,19995,19996,19997,19998,19999, |
| 94300 | 20000,20001,20002,20003,20004,20005,20006,20007,20008,20009,20010,20011, |
| 94301 | 20012,20013,20014,20015,20016,20017,20018,20019,20020,20021,20022,20023, |
| 94302 | 20024,20025,20026,20027,20028,20029,20030,20031,20032,20033,20034,20035, |
| 94303 | 20036,20037,20038,20039,20040,20041,20042,20043,20044,20045,20046,20047, |
| 94304 | 20048,20049,20050,20051,20052,20053,20054,20055,20056,20057,20058,20059, |
| 94305 | 20060,20061,20062,20063,20064,20065,20066,20067,20068,20069,20070,20071, |
| 94306 | 20072,20073,20074,20075,20076,20077,20078,20079,20080,20081,20082,20083, |
| 94307 | 20084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20094,20095, |
| 94308 | 20096,20097,20098,20099,20100,20101,20102,20103,20104,20105,20106,20107, |
| 94309 | 20108,20109,20110,20111,20112,20113,20114,20115,20116,20117,20118,20119, |
| 94310 | 20120,20121,20122,20123,20124,20125,20126,20127,20128,20129,20130,20131, |
| 94311 | 20132,20133,20134,20135,20136,20137,20138,20139,20140,20141,20142,20143, |
| 94312 | 20144,20145,20146,20147,20148,20149,20150,20151,20152,20153,20154,20155, |
| 94313 | 20156,20157,20158,20159,20160,20161,20162,20163,20164,20165,20166,20167, |
| 94314 | 20168,20169,20170,20171,20172,20173,20174,20175,20176,20177,20178,20179, |
| 94315 | 20180,20181,20182,20183,20184,20185,20186,20187,20188,20189,20190,20191, |
| 94316 | 20192,20193,20194,20195,20196,20197,20198,20199,20200,20201,20202,20203, |
| 94317 | 20204,20205,20206,20207,20208,20209,20210,20211,20212,20213,20214,20215, |
| 94318 | 20216,20217,20218,20219,20220,20221,20222,20223,20224,20225,20226,20227, |
| 94319 | 20228,20229,20230,20231,20232,20233,20234,20235,20236,20237,20238,20239, |
| 94320 | 20240,20241,20242,20243,20244,20245,20246,20247,20248,20249,20250,20251, |
| 94321 | 20252,20253,20254,20255,20256,20257,20258,20259,20260,20261,20262,20263, |
| 94322 | 20264,20265,20266,20267,20268,20269,20270,20271,20272,20273,20274,20275, |
| 94323 | 20276,20277,20278,20279,20280,20281,20282,20283,20284,20285,20286,20287, |
| 94324 | 20288,20289,20290,20291,20292,20293,20294,20295,20296,20297,20298,20299, |
| 94325 | 20300,20301,20302,20303,20304,20305,20306,20307,20308,20309,20310,20311, |
| 94326 | 20312,20313,20314,20315,20316,20317,20318,20319,20320,20321,20322,20323, |
| 94327 | 20324,20325,20326,20327,20328,20329,20330,20331,20332,20333,20334,20335, |
| 94328 | 20336,20337,20338,20339,20340,20341,20342,20343,20344,20345,20346,20347, |
| 94329 | 20348,20349,20350,20351,20352,20353,20354,20355,20356,20357,20358,20359, |
| 94330 | 20360,20361,20362,20363,20364,20365,20366,20367,20368,20369,20370,20371, |
| 94331 | 20372,20373,20374,20375,20376,20377,20378,20379,20380,20381,20382,20383, |
| 94332 | 20384,20385,20386,20387,20388,20389,20390,20391,20392,20393,20394,20395, |
| 94333 | 20396,20397,20398,20399,20400,20401,20402,20403,20404,20405,20406,20407, |
| 94334 | 20408,20409,20410,20411,20412,20413,20414,20415,20416,20417,20418,20419, |
| 94335 | 20420,20421,20422,20423,20424,20425,20426,20427,20428,20429,20430,20431, |
| 94336 | 20432,20433,20434,20435,20436,20437,20438,20439,20440,20441,20442,20443, |
| 94337 | 20444,20445,20446,20447,20448,20449,20450,20451,20452,20453,20454,20455, |
| 94338 | 20456,20457,20458,20459,20460,20461,20462,20463,20464,20465,20466,20467, |
| 94339 | 20468,20469,20470,20471,20472,20473,20474,20475,20476,20477,20478,20479, |
| 94340 | 20480,20481,20482,20483,20484,20485,20486,20487,20488,20489,20490,20491, |
| 94341 | 20492,20493,20494,20495,20496,20497,20498,20499,20500,20501,20502,20503, |
| 94342 | 20504,20505,20506,20507,20508,20509,20510,20511,20512,20513,20514,20515, |
| 94343 | 20516,20517,20518,20519,20520,20521,20522,20523,20524,20525,20526,20527, |
| 94344 | 20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20538,20539, |
| 94345 | 20540,20541,20542,20543,20544,20545,20546,20547,20548,20549,20550,20551, |
| 94346 | 20552,20553,20554,20555,20556,20557,20558,20559,20560,20561,20562,20563, |
| 94347 | 20564,20565,20566,20567,20568,20569,20570,20571,20572,20573,20574,20575, |
| 94348 | 20576,20577,20578,20579,20580,20581,20582,20583,20584,20585,20586,20587, |
| 94349 | 20588,20589,20590,20591,20592,20593,20594,20595,20596,20597,20598,20599, |
| 94350 | 20600,20601,20602,20603,20604,20605,20606,20607,20608,20609,20610,20611, |
| 94351 | 20612,20613,20614,20615,20616,20617,20618,20619,20620,20621,20622,20623, |
| 94352 | 20624,20625,20626,20627,20628,20629,20630,20631,20632,20633,20634,20635, |
| 94353 | 20636,20637,20638,20639,20640,20641,20642,20643,20644,20645,20646,20647, |
| 94354 | 20648,20649,20650,20651,20652,20653,20654,20655,20656,20657,20658,20659, |
| 94355 | 20660,20661,20662,20663,20664,20665,20666,20667,20668,20669,20670,20671, |
| 94356 | 20672,20673,20674,20675,20676,20677,20678,20679,20680,20681,20682,20683, |
| 94357 | 20684,20685,20686,20687,20688,20689,20690,20691,20692,20693,20694,20695, |
| 94358 | 20696,20697,20698,20699,20700,20701,20702,20703,20704,20705,20706,20707, |
| 94359 | 20708,20709,20710,20711,20712,20713,20714,20715,20716,20717,20718,20719, |
| 94360 | 20720,20721,20722,20723,20724,20725,20726,20727,20728,20729,20730,20731, |
| 94361 | 20732,20733,20734,20735,20736,20737,20738,20739,20740,20741,20742,20743, |
| 94362 | 20744,20745,20746,20747,20748,20749,20750,20751,20752,20753,20754,20755, |
| 94363 | 20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767, |
| 94364 | 20768,20769,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779, |
| 94365 | 20780,20781,20782,20783,20784,20785,20786,20787,20788,20789,20790,20791, |
| 94366 | 20792,20793,20794,20795,20796,20797,20798,20799,20800,20801,20802,20803, |
| 94367 | 20804,20805,20806,20807,20808,20809,20810,20811,20812,20813,20814,20815, |
| 94368 | 20816,20817,20818,20819,20820,20821,20822,20823,20824,20825,20826,20827, |
| 94369 | 20828,20829,20830,20831,20832,20833,20834,20835,20836,20837,20838,20839, |
| 94370 | 20840,20841,20842,20843,20844,20845,20846,20847,20848,20849,20850,20851, |
| 94371 | 20852,20853,20854,20855,20856,20857,20858,20859,20860,20861,20862,20863, |
| 94372 | 20864,20865,20866,20867,20868,20869,20870,20871,20872,20873,20874,20875, |
| 94373 | 20876,20877,20878,20879,20880,20881,20882,20883,20884,20885,20886,20887, |
| 94374 | 20888,20889,20890,20891,20892,20893,20894,20895,20896,20897,20898,20899, |
| 94375 | 20900,20901,20902,20903,20904,20905,20906,20907,20908,20909,20910,20911, |
| 94376 | 20912,20913,20914,20915,20916,20917,20918,20919,20920,20921,20922,20923, |
| 94377 | 20924,20925,20926,20927,20928,20929,20930,20931,20932,20933,20934,20935, |
| 94378 | 20936,20937,20938,20939,20940,20941,20942,20943,20944,20945,20946,20947, |
| 94379 | 20948,20949,20950,20951,20952,20953,20954,20955,20956,20957,20958,20959, |
| 94380 | 20960,20961,20962,20963,20964,20965,20966,20967,20968,20969,20970,20971, |
| 94381 | 20972,20973,20974,20975,20976,20977,20978,20979,20980,20981,20982,20983, |
| 94382 | 20984,20985,20986,20987,20988,20989,20990,20991,20992,20993,20994,20995, |
| 94383 | 20996,20997,20998,20999,21000,21001,21002,21003,21004,21005,21006,21007, |
| 94384 | 21008,21009,21010,21011,21012,21013,21014,21015,21016,21017,21018,21019, |
| 94385 | 21020,21021,21022,21023,21024,21025,21026,21027,21028,21029,21030,21031, |
| 94386 | 21032,21033,21034,21035,21036,21037,21038,21039,21040,21041,21042,21043, |
| 94387 | 21044,21045,21046,21047,21048,21049,21050,21051,21052,21053,21054,21055, |
| 94388 | 21056,21057,21058,21059,21060,21061,21062,21063,21064,21065,21066,21067, |
| 94389 | 21068,21069,21070,21071,21072,21073,21074,21075,21076,21077,21078,21079, |
| 94390 | 21080,21081,21082,21083,21084,21085,21086,21087,21088,21089,21090,21091, |
| 94391 | 21092,21093,21094,21095,21096,21097,21098,21099,21100,21101,21102,21103, |
| 94392 | 21104,21105,21106,21107,21108,21109,21110,21111,21112,21113,21114,21115, |
| 94393 | 21116,21117,21118,21119,21120,21121,21122,21123,21124,21125,21126,21127, |
| 94394 | 21128,21129,21130,21131,21132,21133,21134,21135,21136,21137,21138,21139, |
| 94395 | 21140,21141,21142,21143,21144,21145,21146,21147,21148,21149,21150,21151, |
| 94396 | 21152,21153,21154,21155,21156,21157,21158,21159,21160,21161,21162,21163, |
| 94397 | 21164,21165,21166,21167,21168,21169,21170,21171,21172,21173,21174,21175, |
| 94398 | 21176,21177,21178,21179,21180,21181,21182,21183,21184,21185,21186,21187, |
| 94399 | 21188,21189,21190,21191,21192,21193,21194,21195,21196,21197,21198,21199, |
| 94400 | 21200,21201,21202,21203,21204,21205,21206,21207,21208,21209,21210,21211, |
| 94401 | 21212,21213,21214,21215,21216,21217,21218,21219,21220,21221,21222,21223, |
| 94402 | 21224,21225,21226,21227,21228,21229,21230,21231,21232,21233,21234,21235, |
| 94403 | 21236,21237,21238,21239,21240,21241,21242,21243,21244,21245,21246,21247, |
| 94404 | 21248,21249,21250,21251,21252,21253,21254,21255,21256,21257,21258,21259, |
| 94405 | 21260,21261,21262,21263,21264,21265,21266,21267,21268,21269,21270,21271, |
| 94406 | 21272,21273,21274,21275,21276,21277,21278,21279,21280,21281,21282,21283, |
| 94407 | 21284,21285,21286,21287,21288,21289,21290,21291,21292,21293,21294,21295, |
| 94408 | 21296,21297,21298,21299,21300,21301,21302,21303,21304,21305,21306,21307, |
| 94409 | 21308,21309,21310,21311,21312,21313,21314,21315,21316,21317,21318,21319, |
| 94410 | 21320,21321,21322,21323,21324,21325,21326,21327,21328,21329,21330,21331, |
| 94411 | 21332,21333,21334,21335,21336,21337,21338,21339,21340,21341,21342,21343, |
| 94412 | 21344,21345,21346,21347,21348,21349,21350,21351,21352,21353,21354,21355, |
| 94413 | 21356,21357,21358,21359,21360,21361,21362,21363,21364,21365,21366,21367, |
| 94414 | 21368,21369,21370,21371,21372,21373,21374,21375,21376,21377,21378,21379, |
| 94415 | 21380,21381,21382,21383,21384,21385,21386,21387,21388,21389,21390,21391, |
| 94416 | 21392,21393,21394,21395,21396,21397,21398,21399,21400,21401,21402,21403, |
| 94417 | 21404,21405,21406,21407,21408,21409,21410,21411,21412,21413,21414,21415, |
| 94418 | 21416,21417,21418,21419,21420,21421,21422,21423,21424,21425,21426,21427, |
| 94419 | 21428,21429,21430,21431,21432,21433,21434,21435,21436,21437,21438,21439, |
| 94420 | 21440,21441,21442,21443,21444,21445,21446,21447,21448,21449,21450,21451, |
| 94421 | 21452,21453,21454,21455,21456,21457,21458,21459,21460,21461,21462,21463, |
| 94422 | 21464,21465,21466,21467,21468,21469,21470,21471,21472,21473,21474,21475, |
| 94423 | 21476,21477,21478,21479,21480,21481,21482,21483,21484,21485,21486,21487, |
| 94424 | 21488,21489,21490,21491,21492,21493,21494,21495,21496,21497,21498,21499, |
| 94425 | 21500,21501,21502,21503,21504,21505,21506,21507,21508,21509,21510,21511, |
| 94426 | 21512,21513,21514,21515,21516,21517,21518,21519,21520,21521,21522,21523, |
| 94427 | 21524,21525,21526,21527,21528,21529,21530,21531,21532,21533,21534,21535, |
| 94428 | 21536,21537,21538,21539,21540,21541,21542,21543,21544,21545,21546,21547, |
| 94429 | 21548,21549,21550,21551,21552,21553,21554,21555,21556,21557,21558,21559, |
| 94430 | 21560,21561,21562,21563,21564,21565,21566,21567,21568,21569,21570,21571, |
| 94431 | 21572,21573,21574,21575,21576,21577,21578,21579,21580,21581,21582,21583, |
| 94432 | 21584,21585,21586,21587,21588,21589,21590,21591,21592,21593,21594,21595, |
| 94433 | 21596,21597,21598,21599,21600,21601,21602,21603,21604,21605,21606,21607, |
| 94434 | 21608,21609,21610,21611,21612,21613,21614,21615,21616,21617,21618,21619, |
| 94435 | 21620,21621,21622,21623,21624,21625,21626,21627,21628,21629,21630,21631, |
| 94436 | 21632,21633,21634,21635,21636,21637,21638,21639,21640,21641,21642,21643, |
| 94437 | 21644,21645,21646,21647,21648,21649,21650,21651,21652,21653,21654,21655, |
| 94438 | 21656,21657,21658,21659,21660,21661,21662,21663,21664,21665,21666,21667, |
| 94439 | 21668,21669,21670,21671,21672,21673,21674,21675,21676,21677,21678,21679, |
| 94440 | 21680,21681,21682,21683,21684,21685,21686,21687,21688,21689,21690,21691, |
| 94441 | 21692,21693,21694,21695,21696,21697,21698,21699,21700,21701,21702,21703, |
| 94442 | 21704,21705,21706,21707,21708,21709,21710,21711,21712,21713,21714,21715, |
| 94443 | 21716,21717,21718,21719,21720,21721,21722,21723,21724,21725,21726,21727, |
| 94444 | 21728,21729,21730,21731,21732,21733,21734,21735,21736,21737,21738,21739, |
| 94445 | 21740,21741,21742,21743,21744,21745,21746,21747,21748,21749,21750,21751, |
| 94446 | 21752,21753,21754,21755,21756,21757,21758,21759,21760,21761,21762,21763, |
| 94447 | 21764,21765,21766,21767,21768,21769,21770,21771,21772,21773,21774,21775, |
| 94448 | 21776,21777,21778,21779,21780,21781,21782,21783,21784,21785,21786,21787, |
| 94449 | 21788,21789,21790,21791,21792,21793,21794,21795,21796,21797,21798,21799, |
| 94450 | 21800,21801,21802,21803,21804,21805,21806,21807,21808,21809,21810,21811, |
| 94451 | 21812,21813,21814,21815,21816,21817,21818,21819,21820,21821,21822,21823, |
| 94452 | 21824,21825,21826,21827,21828,21829,21830,21831,21832,21833,21834,21835, |
| 94453 | 21836,21837,21838,21839,21840,21841,21842,21843,21844,21845,21846,21847, |
| 94454 | 21848,21849,21850,21851,21852,21853,21854,21855,21856,21857,21858,21859, |
| 94455 | 21860,21861,21862,21863,21864,21865,21866,21867,21868,21869,21870,21871, |
| 94456 | 21872,21873,21874,21875,21876,21877,21878,21879,21880,21881,21882,21883, |
| 94457 | 21884,21885,21886,21887,21888,21889,21890,21891,21892,21893,21894,21895, |
| 94458 | 21896,21897,21898,21899,21900,21901,21902,21903,21904,21905,21906,21907, |
| 94459 | 21908,21909,21910,21911,21912,21913,21914,21915,21916,21917,21918,21919, |
| 94460 | 21920,21921,21922,21923,21924,21925,21926,21927,21928,21929,21930,21931, |
| 94461 | 21932,21933,21934,21935,21936,21937,21938,21939,21940,21941,21942,21943, |
| 94462 | 21944,21945,21946,21947,21948,21949,21950,21951,21952,21953,21954,21955, |
| 94463 | 21956,21957,21958,21959,21960,21961,21962,21963,21964,21965,21966,21967, |
| 94464 | 21968,21969,21970,21971,21972,21973,21974,21975,21976,21977,21978,21979, |
| 94465 | 21980,21981,21982,21983,21984,21985,21986,21987,21988,21989,21990,21991, |
| 94466 | 21992,21993,21994,21995,21996,21997,21998,21999,22000,22001,22002,22003, |
| 94467 | 22004,22005,22006,22007,22008,22009,22010,22011,22012,22013,22014,22015, |
| 94468 | 22016,22017,22018,22019,22020,22021,22022,22023,22024,22025,22026,22027, |
| 94469 | 22028,22029,22030,22031,22032,22033,22034,22035,22036,22037,22038,22039, |
| 94470 | 22040,22041,22042,22043,22044,22045,22046,22047,22048,22049,22050,22051, |
| 94471 | 22052,22053,22054,22055,22056,22057,22058,22059,22060,22061,22062,22063, |
| 94472 | 22064,22065,22066,22067,22068,22069,22070,22071,22072,22073,22074,22075, |
| 94473 | 22076,22077,22078,22079,22080,22081,22082,22083,22084,22085,22086,22087, |
| 94474 | 22088,22089,22090,22091,22092,22093,22094,22095,22096,22097,22098,22099, |
| 94475 | 22100,22101,22102,22103,22104,22105,22106,22107,22108,22109,22110,22111, |
| 94476 | 22112,22113,22114,22115,22116,22117,22118,22119,22120,22121,22122,22123, |
| 94477 | 22124,22125,22126,22127,22128,22129,22130,22131,22132,22133,22134,22135, |
| 94478 | 22136,22137,22138,22139,22140,22141,22142,22143,22144,22145,22146,22147, |
| 94479 | 22148,22149,22150,22151,22152,22153,22154,22155,22156,22157,22158,22159, |
| 94480 | 22160,22161,22162,22163,22164,22165,22166,22167,22168,22169,22170,22171, |
| 94481 | 22172,22173,22174,22175,22176,22177,22178,22179,22180,22181,22182,22183, |
| 94482 | 22184,22185,22186,22187,22188,22189,22190,22191,22192,22193,22194,22195, |
| 94483 | 22196,22197,22198,22199,22200,22201,22202,22203,22204,22205,22206,22207, |
| 94484 | 22208,22209,22210,22211,22212,22213,22214,22215,22216,22217,22218,22219, |
| 94485 | 22220,22221,22222,22223,22224,22225,22226,22227,22228,22229,22230,22231, |
| 94486 | 22232,22233,22234,22235,22236,22237,22238,22239,22240,22241,22242,22243, |
| 94487 | 22244,22245,22246,22247,22248,22249,22250,22251,22252,22253,22254,22255, |
| 94488 | 22256,22257,22258,22259,22260,22261,22262,22263,22264,22265,22266,22267, |
| 94489 | 22268,22269,22270,22271,22272,22273,22274,22275,22276,22277,22278,22279, |
| 94490 | 22280,22281,22282,22283,22284,22285,22286,22287,22288,22289,22290,22291, |
| 94491 | 22292,22293,22294,22295,22296,22297,22298,22299,22300,22301,22302,22303, |
| 94492 | 22304,22305,22306,22307,22308,22309,22310,22311,22312,22313,22314,22315, |
| 94493 | 22316,22317,22318,22319,22320,22321,22322,22323,22324,22325,22326,22327, |
| 94494 | 22328,22329,22330,22331,22332,22333,22334,22335,22336,22337,22338,22339, |
| 94495 | 22340,22341,22342,22343,22344,22345,22346,22347,22348,22349,22350,22351, |
| 94496 | 22352,22353,22354,22355,22356,22357,22358,22359,22360,22361,22362,22363, |
| 94497 | 22364,22365,22366,22367,22368,22369,22370,22371,22372,22373,22374,22375, |
| 94498 | 22376,22377,22378,22379,22380,22381,22382,22383,22384,22385,22386,22387, |
| 94499 | 22388,22389,22390,22391,22392,22393,22394,22395,22396,22397,22398,22399, |
| 94500 | 22400,22401,22402,22403,22404,22405,22406,22407,22408,22409,22410,22411, |
| 94501 | 22412,22413,22414,22415,22416,22417,22418,22419,22420,22421,22422,22423, |
| 94502 | 22424,22425,22426,22427,22428,22429,22430,22431,22432,22433,22434,22435, |
| 94503 | 22436,22437,22438,22439,22440,22441,22442,22443,22444,22445,22446,22447, |
| 94504 | 22448,22449,22450,22451,22452,22453,22454,22455,22456,22457,22458,22459, |
| 94505 | 22460,22461,22462,22463,22464,22465,22466,22467,22468,22469,22470,22471, |
| 94506 | 22472,22473,22474,22475,22476,22477,22478,22479,22480,22481,22482,22483, |
| 94507 | 22484,22485,22486,22487,22488,22489,22490,22491,22492,22493,22494,22495, |
| 94508 | 22496,22497,22498,22499,22500,22501,22502,22503,22504,22505,22506,22507, |
| 94509 | 22508,22509,22510,22511,22512,22513,22514,22515,22516,22517,22518,22519, |
| 94510 | 22520,22521,22522,22523,22524,22525,22526,22527,22528,22529,22530,22531, |
| 94511 | 22532,22533,22534,22535,22536,22537,22538,22539,22540,22541,22542,22543, |
| 94512 | 22544,22545,22546,22547,22548,22549,22550,22551,22552,22553,22554,22555, |
| 94513 | 22556,22557,22558,22559,22560,22561,22562,22563,22564,22565,22566,22567, |
| 94514 | 22568,22569,22570,22571,22572,22573,22574,22575,22576,22577,22578,22579, |
| 94515 | 22580,22581,22582,22583,22584,22585,22586,22587,22588,22589,22590,22591, |
| 94516 | 22592,22593,22594,22595,22596,22597,22598,22599,22600,22601,22602,22603, |
| 94517 | 22604,22605,22606,22607,22608,22609,22610,22611,22612,22613,22614,22615, |
| 94518 | 22616,22617,22618,22619,22620,22621,22622,22623,22624,22625,22626,22627, |
| 94519 | 22628,22629,22630,22631,22632,22633,22634,22635,22636,22637,22638,22639, |
| 94520 | 22640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651, |
| 94521 | 22652,22653,22654,22655,22656,22657,22658,22659,22660,22661,22662,22663, |
| 94522 | 22664,22665,22666,22667,22668,22669,22670,22671,22672,22673,22674,22675, |
| 94523 | 22676,22677,22678,22679,22680,22681,22682,22683,22684,22685,22686,22687, |
| 94524 | 22688,22689,22690,22691,22692,22693,22694,22695,22696,22697,22698,22699, |
| 94525 | 22700,22701,22702,22703,22704,22705,22706,22707,22708,22709,22710,22711, |
| 94526 | 22712,22713,22714,22715,22716,22717,22718,22719,22720,22721,22722,22723, |
| 94527 | 22724,22725,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735, |
| 94528 | 22736,22737,22738,22739,22740,22741,22742,22743,22744,22745,22746,22747, |
| 94529 | 22748,22749,22750,22751,22752,22753,22754,22755,22756,22757,22758,22759, |
| 94530 | 22760,22761,22762,22763,22764,22765,22766,22767,22768,22769,22770,22771, |
| 94531 | 22772,22773,22774,22775,22776,22777,22778,22779,22780,22781,22782,22783, |
| 94532 | 22784,22785,22786,22787,22788,22789,22790,22791,22792,22793,22794,22795, |
| 94533 | 22796,22797,22798,22799,22800,22801,22802,22803,22804,22805,22806,22807, |
| 94534 | 22808,22809,22810,22811,22812,22813,22814,22815,22816,22817,22818,22819, |
| 94535 | 22820,22821,22822,22823,22824,22825,22826,22827,22828,22829,22830,22831, |
| 94536 | 22832,22833,22834,22835,22836,22837,22838,22839,22840,22841,22842,22843, |
| 94537 | 22844,22845,22846,22847,22848,22849,22850,22851,22852,22853,22854,22855, |
| 94538 | 22856,22857,22858,22859,22860,22861,22862,22863,22864,22865,22866,22867, |
| 94539 | 22868,22869,22870,22871,22872,22873,22874,22875,22876,22877,22878,22879, |
| 94540 | 22880,22881,22882,22883,22884,22885,22886,22887,22888,22889,22890,22891, |
| 94541 | 22892,22893,22894,22895,22896,22897,22898,22899,22900,22901,22902,22903, |
| 94542 | 22904,22905,22906,22907,22908,22909,22910,22911,22912,22913,22914,22915, |
| 94543 | 22916,22917,22918,22919,22920,22921,22922,22923,22924,22925,22926,22927, |
| 94544 | 22928,22929,22930,22931,22932,22933,22934,22935,22936,22937,22938,22939, |
| 94545 | 22940,22941,22942,22943,22944,22945,22946,22947,22948,22949,22950,22951, |
| 94546 | 22952,22953,22954,22955,22956,22957,22958,22959,22960,22961,22962,22963, |
| 94547 | 22964,22965,22966,22967,22968,22969,22970,22971,22972,22973,22974,22975, |
| 94548 | 22976,22977,22978,22979,22980,22981,22982,22983,22984,22985,22986,22987, |
| 94549 | 22988,22989,22990,22991,22992,22993,22994,22995,22996,22997,22998,22999, |
| 94550 | 23000,23001,23002,23003,23004,23005,23006,23007,23008,23009,23010,23011, |
| 94551 | 23012,23013,23014,23015,23016,23017,23018,23019,23020,23021,23022,23023, |
| 94552 | 23024,23025,23026,23027,23028,23029,23030,23031,23032,23033,23034,23035, |
| 94553 | 23036,23037,23038,23039,23040,23041,23042,23043,23044,23045,23046,23047, |
| 94554 | 23048,23049,23050,23051,23052,23053,23054,23055,23056,23057,23058,23059, |
| 94555 | 23060,23061,23062,23063,23064,23065,23066,23067,23068,23069,23070,23071, |
| 94556 | 23072,23073,23074,23075,23076,23077,23078,23079,23080,23081,23082,23083, |
| 94557 | 23084,23085,23086,23087,23088,23089,23090,23091,23092,23093,23094,23095, |
| 94558 | 23096,23097,23098,23099,23100,23101,23102,23103,23104,23105,23106,23107, |
| 94559 | 23108,23109,23110,23111,23112,23113,23114,23115,23116,23117,23118,23119, |
| 94560 | 23120,23121,23122,23123,23124,23125,23126,23127,23128,23129,23130,23131, |
| 94561 | 23132,23133,23134,23135,23136,23137,23138,23139,23140,23141,23142,23143, |
| 94562 | 23144,23145,23146,23147,23148,23149,23150,23151,23152,23153,23154,23155, |
| 94563 | 23156,23157,23158,23159,23160,23161,23162,23163,23164,23165,23166,23167, |
| 94564 | 23168,23169,23170,23171,23172,23173,23174,23175,23176,23177,23178,23179, |
| 94565 | 23180,23181,23182,23183,23184,23185,23186,23187,23188,23189,23190,23191, |
| 94566 | 23192,23193,23194,23195,23196,23197,23198,23199,23200,23201,23202,23203, |
| 94567 | 23204,23205,23206,23207,23208,23209,23210,23211,23212,23213,23214,23215, |
| 94568 | 23216,23217,23218,23219,23220,23221,23222,23223,23224,23225,23226,23227, |
| 94569 | 23228,23229,23230,23231,23232,23233,23234,23235,23236,23237,23238,23239, |
| 94570 | 23240,23241,23242,23243,23244,23245,23246,23247,23248,23249,23250,23251, |
| 94571 | 23252,23253,23254,23255,23256,23257,23258,23259,23260,23261,23262,23263, |
| 94572 | 23264,23265,23266,23267,23268,23269,23270,23271,23272,23273,23274,23275, |
| 94573 | 23276,23277,23278,23279,23280,23281,23282,23283,23284,23285,23286,23287, |
| 94574 | 23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299, |
| 94575 | 23300,23301,23302,23303,23304,23305,23306,23307,23308,23309,23310,23311, |
| 94576 | 23312,23313,23314,23315,23316,23317,23318,23319,23320,23321,23322,23323, |
| 94577 | 23324,23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,23335, |
| 94578 | 23336,23337,23338,23339,23340,23341,23342,23343,23344,23345,23346,23347, |
| 94579 | 23348,23349,23350,23351,23352,23353,23354,23355,23356,23357,23358,23359, |
| 94580 | 23360,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371, |
| 94581 | 23372,23373,23374,23375,23376,23377,23378,23379,23380,23381,23382,23383, |
| 94582 | 23384,23385,23386,23387,23388,23389,23390,23391,23392,23393,23394,23395, |
| 94583 | 23396,23397,23398,23399,23400,23401,23402,23403,23404,23405,23406,23407, |
| 94584 | 23408,23409,23410,23411,23412,23413,23414,23415,23416,23417,23418,23419, |
| 94585 | 23420,23421,23422,23423,23424,23425,23426,23427,23428,23429,23430,23431, |
| 94586 | 23432,23433,23434,23435,23436,23437,23438,23439,23440,23441,23442,23443, |
| 94587 | 23444,23445,23446,23447,23448,23449,23450,23451,23452,23453,23454,23455, |
| 94588 | 23456,23457,23458,23459,23460,23461,23462,23463,23464,23465,23466,23467, |
| 94589 | 23468,23469,23470,23471,23472,23473,23474,23475,23476,23477,23478,23479, |
| 94590 | 23480,23481,23482,23483,23484,23485,23486,23487,23488,23489,23490,23491, |
| 94591 | 23492,23493,23494,23495,23496,23497,23498,23499,23500,23501,23502,23503, |
| 94592 | 23504,23505,23506,23507,23508,23509,23510,23511,23512,23513,23514,23515, |
| 94593 | 23516,23517,23518,23519,23520,23521,23522,23523,23524,23525,23526,23527, |
| 94594 | 23528,23529,23530,23531,23532,23533,23534,23535,23536,23537,23538,23539, |
| 94595 | 23540,23541,23542,23543,23544,23545,23546,23547,23548,23549,23550,23551, |
| 94596 | 23552,23553,23554,23555,23556,23557,23558,23559,23560,23561,23562,23563, |
| 94597 | 23564,23565,23566,23567,23568,23569,23570,23571,23572,23573,23574,23575, |
| 94598 | 23576,23577,23578,23579,23580,23581,23582,23583,23584,23585,23586,23587, |
| 94599 | 23588,23589,23590,23591,23592,23593,23594,23595,23596,23597,23598,23599, |
| 94600 | 23600,23601,23602,23603,23604,23605,23606,23607,23608,23609,23610,23611, |
| 94601 | 23612,23613,23614,23615,23616,23617,23618,23619,23620,23621,23622,23623, |
| 94602 | 23624,23625,23626,23627,23628,23629,23630,23631,23632,23633,23634,23635, |
| 94603 | 23636,23637,23638,23639,23640,23641,23642,23643,23644,23645,23646,23647, |
| 94604 | 23648,23649,23650,23651,23652,23653,23654,23655,23656,23657,23658,23659, |
| 94605 | 23660,23661,23662,23663,23664,23665,23666,23667,23668,23669,23670,23671, |
| 94606 | 23672,23673,23674,23675,23676,23677,23678,23679,23680,23681,23682,23683, |
| 94607 | 23684,23685,23686,23687,23688,23689,23690,23691,23692,23693,23694,23695, |
| 94608 | 23696,23697,23698,23699,23700,23701,23702,23703,23704,23705,23706,23707, |
| 94609 | 23708,23709,23710,23711,23712,23713,23714,23715,23716,23717,23718,23719, |
| 94610 | 23720,23721,23722,23723,23724,23725,23726,23727,23728,23729,23730,23731, |
| 94611 | 23732,23733,23734,23735,23736,23737,23738,23739,23740,23741,23742,23743, |
| 94612 | 23744,23745,23746,23747,23748,23749,23750,23751,23752,23753,23754,23755, |
| 94613 | 23756,23757,23758,23759,23760,23761,23762,23763,23764,23765,23766,23767, |
| 94614 | 23768,23769,23770,23771,23772,23773,23774,23775,23776,23777,23778,23779, |
| 94615 | 23780,23781,23782,23783,23784,23785,23786,23787,23788,23789,23790,23791, |
| 94616 | 23792,23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23803, |
| 94617 | 23804,23805,23806,23807,23808,23809,23810,23811,23812,23813,23814,23815, |
| 94618 | 23816,23817,23818,23819,23820,23821,23822,23823,23824,23825,23826,23827, |
| 94619 | 23828,23829,23830,23831,23832,23833,23834,23835,23836,23837,23838,23839, |
| 94620 | 23840,23841,23842,23843,23844,23845,23846,23847,23848,23849,23850,23851, |
| 94621 | 23852,23853,23854,23855,23856,23857,23858,23859,23860,23861,23862,23863, |
| 94622 | 23864,23865,23866,23867,23868,23869,23870,23871,23872,23873,23874,23875, |
| 94623 | 23876,23877,23878,23879,23880,23881,23882,23883,23884,23885,23886,23887, |
| 94624 | 23888,23889,23890,23891,23892,23893,23894,23895,23896,23897,23898,23899, |
| 94625 | 23900,23901,23902,23903,23904,23905,23906,23907,23908,23909,23910,23911, |
| 94626 | 23912,23913,23914,23915,23916,23917,23918,23919,23920,23921,23922,23923, |
| 94627 | 23924,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935, |
| 94628 | 23936,23937,23938,23939,23940,23941,23942,23943,23944,23945,23946,23947, |
| 94629 | 23948,23949,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959, |
| 94630 | 23960,23961,23962,23963,23964,23965,23966,23967,23968,23969,23970,23971, |
| 94631 | 23972,23973,23974,23975,23976,23977,23978,23979,23980,23981,23982,23983, |
| 94632 | 23984,23985,23986,23987,23988,23989,23990,23991,23992,23993,23994,23995, |
| 94633 | 23996,23997,23998,23999,24000,24001,24002,24003,24004,24005,24006,24007, |
| 94634 | 24008,24009,24010,24011,24012,24013,24014,24015,24016,24017,24018,24019, |
| 94635 | 24020,24021,24022,24023,24024,24025,24026,24027,24028,24029,24030,24031, |
| 94636 | 24032,24033,24034,24035,24036,24037,24038,24039,24040,24041,24042,24043, |
| 94637 | 24044,24045,24046,24047,24048,24049,24050,24051,24052,24053,24054,24055, |
| 94638 | 24056,24057,24058,24059,24060,24061,24062,24063,24064,24065,24066,24067, |
| 94639 | 24068,24069,24070,24071,24072,24073,24074,24075,24076,24077,24078,24079, |
| 94640 | 24080,24081,24082,24083,24084,24085,24086,24087,24088,24089,24090,24091, |
| 94641 | 24092,24093,24094,24095,24096,24097,24098,24099,24100,24101,24102,24103, |
| 94642 | 24104,24105,24106,24107,24108,24109,24110,24111,24112,24113,24114,24115, |
| 94643 | 24116,24117,24118,24119,24120,24121,24122,24123,24124,24125,24126,24127, |
| 94644 | 24128,24129,24130,24131,24132,24133,24134,24135,24136,24137,24138,24139, |
| 94645 | 24140,24141,24142,24143,24144,24145,24146,24147,24148,24149,24150,24151, |
| 94646 | 24152,24153,24154,24155,24156,24157,24158,24159,24160,24161,24162,24163, |
| 94647 | 24164,24165,24166,24167,24168,24169,24170,24171,24172,24173,24174,24175, |
| 94648 | 24176,24177,24178,24179,24180,24181,24182,24183,24184,24185,24186,24187, |
| 94649 | 24188,24189,24190,24191,24192,24193,24194,24195,24196,24197,24198,24199, |
| 94650 | 24200,24201,24202,24203,24204,24205,24206,24207,24208,24209,24210,24211, |
| 94651 | 24212,24213,24214,24215,24216,24217,24218,24219,24220,24221,24222,24223, |
| 94652 | 24224,24225,24226,24227,24228,24229,24230,24231,24232,24233,24234,24235, |
| 94653 | 24236,24237,24238,24239,24240,24241,24242,24243,24244,24245,24246,24247, |
| 94654 | 24248,24249,24250,24251,24252,24253,24254,24255,24256,24257,24258,24259, |
| 94655 | 24260,24261,24262,24263,24264,24265,24266,24267,24268,24269,24270,24271, |
| 94656 | 24272,24273,24274,24275,24276,24277,24278,24279,24280,24281,24282,24283, |
| 94657 | 24284,24285,24286,24287,24288,24289,24290,24291,24292,24293,24294,24295, |
| 94658 | 24296,24297,24298,24299,24300,24301,24302,24303,24304,24305,24306,24307, |
| 94659 | 24308,24309,24310,24311,24312,24313,24314,24315,24316,24317,24318,24319, |
| 94660 | 24320,24321,24322,24323,24324,24325,24326,24327,24328,24329,24330,24331, |
| 94661 | 24332,24333,24334,24335,24336,24337,24338,24339,24340,24341,24342,24343, |
| 94662 | 24344,24345,24346,24347,24348,24349,24350,24351,24352,24353,24354,24355, |
| 94663 | 24356,24357,24358,24359,24360,24361,24362,24363,24364,24365,24366,24367, |
| 94664 | 24368,24369,24370,24371,24372,24373,24374,24375,24376,24377,24378,24379, |
| 94665 | 24380,24381,24382,24383,24384,24385,24386,24387,24388,24389,24390,24391, |
| 94666 | 24392,24393,24394,24395,24396,24397,24398,24399,24400,24401,24402,24403, |
| 94667 | 24404,24405,24406,24407,24408,24409,24410,24411,24412,24413,24414,24415, |
| 94668 | 24416,24417,24418,24419,24420,24421,24422,24423,24424,24425,24426,24427, |
| 94669 | 24428,24429,24430,24431,24432,24433,24434,24435,24436,24437,24438,24439, |
| 94670 | 24440,24441,24442,24443,24444,24445,24446,24447,24448,24449,24450,24451, |
| 94671 | 24452,24453,24454,24455,24456,24457,24458,24459,24460,24461,24462,24463, |
| 94672 | 24464,24465,24466,24467,24468,24469,24470,24471,24472,24473,24474,24475, |
| 94673 | 24476,24477,24478,24479,24480,24481,24482,24483,24484,24485,24486,24487, |
| 94674 | 24488,24489,24490,24491,24492,24493,24494,24495,24496,24497,24498,24499, |
| 94675 | 24500,24501,24502,24503,24504,24505,24506,24507,24508,24509,24510,24511, |
| 94676 | 24512,24513,24514,24515,24516,24517,24518,24519,24520,24521,24522,24523, |
| 94677 | 24524,24525,24526,24527,24528,24529,24530,24531,24532,24533,24534,24535, |
| 94678 | 24536,24537,24538,24539,24540,24541,24542,24543,24544,24545,24546,24547, |
| 94679 | 24548,24549,24550,24551,24552,24553,24554,24555,24556,24557,24558,24559, |
| 94680 | 24560,24561,24562,24563,24564,24565,24566,24567,24568,24569,24570,24571, |
| 94681 | 24572,24573,24574,24575,24576,24577,24578,24579,24580,24581,24582,24583, |
| 94682 | 24584,24585,24586,24587,24588,24589,24590,24591,24592,24593,24594,24595, |
| 94683 | 24596,24597,24598,24599,24600,24601,24602,24603,24604,24605,24606,24607, |
| 94684 | 24608,24609,24610,24611,24612,24613,24614,24615,24616,24617,24618,24619, |
| 94685 | 24620,24621,24622,24623,24624,24625,24626,24627,24628,24629,24630,24631, |
| 94686 | 24632,24633,24634,24635,24636,24637,24638,24639,24640,24641,24642,24643, |
| 94687 | 24644,24645,24646,24647,24648,24649,24650,24651,24652,24653,24654,24655, |
| 94688 | 24656,24657,24658,24659,24660,24661,24662,24663,24664,24665,24666,24667, |
| 94689 | 24668,24669,24670,24671,24672,24673,24674,24675,24676,24677,24678,24679, |
| 94690 | 24680,24681,24682,24683,24684,24685,24686,24687,24688,24689,24690,24691, |
| 94691 | 24692,24693,24694,24695,24696,24697,24698,24699,24700,24701,24702,24703, |
| 94692 | 24704,24705,24706,24707,24708,24709,24710,24711,24712,24713,24714,24715, |
| 94693 | 24716,24717,24718,24719,24720,24721,24722,24723,24724,24725,24726,24727, |
| 94694 | 24728,24729,24730,24731,24732,24733,24734,24735,24736,24737,24738,24739, |
| 94695 | 24740,24741,24742,24743,24744,24745,24746,24747,24748,24749,24750,24751, |
| 94696 | 24752,24753,24754,24755,24756,24757,24758,24759,24760,24761,24762,24763, |
| 94697 | 24764,24765,24766,24767,24768,24769,24770,24771,24772,24773,24774,24775, |
| 94698 | 24776,24777,24778,24779,24780,24781,24782,24783,24784,24785,24786,24787, |
| 94699 | 24788,24789,24790,24791,24792,24793,24794,24795,24796,24797,24798,24799, |
| 94700 | 24800,24801,24802,24803,24804,24805,24806,24807,24808,24809,24810,24811, |
| 94701 | 24812,24813,24814,24815,24816,24817,24818,24819,24820,24821,24822,24823, |
| 94702 | 24824,24825,24826,24827,24828,24829,24830,24831,24832,24833,24834,24835, |
| 94703 | 24836,24837,24838,24839,24840,24841,24842,24843,24844,24845,24846,24847, |
| 94704 | 24848,24849,24850,24851,24852,24853,24854,24855,24856,24857,24858,24859, |
| 94705 | 24860,24861,24862,24863,24864,24865,24866,24867,24868,24869,24870,24871, |
| 94706 | 24872,24873,24874,24875,24876,24877,24878,24879,24880,24881,24882,24883, |
| 94707 | 24884,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24895, |
| 94708 | 24896,24897,24898,24899,24900,24901,24902,24903,24904,24905,24906,24907, |
| 94709 | 24908,24909,24910,24911,24912,24913,24914,24915,24916,24917,24918,24919, |
| 94710 | 24920,24921,24922,24923,24924,24925,24926,24927,24928,24929,24930,24931, |
| 94711 | 24932,24933,24934,24935,24936,24937,24938,24939,24940,24941,24942,24943, |
| 94712 | 24944,24945,24946,24947,24948,24949,24950,24951,24952,24953,24954,24955, |
| 94713 | 24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966,24967, |
| 94714 | 24968,24969,24970,24971,24972,24973,24974,24975,24976,24977,24978,24979, |
| 94715 | 24980,24981,24982,24983,24984,24985,24986,24987,24988,24989,24990,24991, |
| 94716 | 24992,24993,24994,24995,24996,24997,24998,24999,25000,25001,25002,25003, |
| 94717 | 25004,25005,25006,25007,25008,25009,25010,25011,25012,25013,25014,25015, |
| 94718 | 25016,25017,25018,25019,25020,25021,25022,25023,25024,25025,25026,25027, |
| 94719 | 25028,25029,25030,25031,25032,25033,25034,25035,25036,25037,25038,25039, |
| 94720 | 25040,25041,25042,25043,25044,25045,25046,25047,25048,25049,25050,25051, |
| 94721 | 25052,25053,25054,25055,25056,25057,25058,25059,25060,25061,25062,25063, |
| 94722 | 25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074,25075, |
| 94723 | 25076,25077,25078,25079,25080,25081,25082,25083,25084,25085,25086,25087, |
| 94724 | 25088,25089,25090,25091,25092,25093,25094,25095,25096,25097,25098,25099, |
| 94725 | 25100,25101,25102,25103,25104,25105,25106,25107,25108,25109,25110,25111, |
| 94726 | 25112,25113,25114,25115,25116,25117,25118,25119,25120,25121,25122,25123, |
| 94727 | 25124,25125,25126,25127,25128,25129,25130,25131,25132,25133,25134,25135, |
| 94728 | 25136,25137,25138,25139,25140,25141,25142,25143,25144,25145,25146,25147, |
| 94729 | 25148,25149,25150,25151,25152,25153,25154,25155,25156,25157,25158,25159, |
| 94730 | 25160,25161,25162,25163,25164,25165,25166,25167,25168,25169,25170,25171, |
| 94731 | 25172,25173,25174,25175,25176,25177,25178,25179,25180,25181,25182,25183, |
| 94732 | 25184,25185,25186,25187,25188,25189,25190,25191,25192,25193,25194,25195, |
| 94733 | 25196,25197,25198,25199,25200,25201,25202,25203,25204,25205,25206,25207, |
| 94734 | 25208,25209,25210,25211,25212,25213,25214,25215,25216,25217,25218,25219, |
| 94735 | 25220,25221,25222,25223,25224,25225,25226,25227,25228,25229,25230,25231, |
| 94736 | 25232,25233,25234,25235,25236,25237,25238,25239,25240,25241,25242,25243, |
| 94737 | 25244,25245,25246,25247,25248,25249,25250,25251,25252,25253,25254,25255, |
| 94738 | 25256,25257,25258,25259,25260,25261,25262,25263,25264,25265,25266,25267, |
| 94739 | 25268,25269,25270,25271,25272,25273,25274,25275,25276,25277,25278,25279, |
| 94740 | 25280,25281,25282,25283,25284,25285,25286,25287,25288,25289,25290,25291, |
| 94741 | 25292,25293,25294,25295,25296,25297,25298,25299,25300,25301,25302,25303, |
| 94742 | 25304,25305,25306,25307,25308,25309,25310,25311,25312,25313,25314,25315, |
| 94743 | 25316,25317,25318,25319,25320,25321,25322,25323,25324,25325,25326,25327, |
| 94744 | 25328,25329,25330,25331,25332,25333,25334,25335,25336,25337,25338,25339, |
| 94745 | 25340,25341,25342,25343,25344,25345,25346,25347,25348,25349,25350,25351, |
| 94746 | 25352,25353,25354,25355,25356,25357,25358,25359,25360,25361,25362,25363, |
| 94747 | 25364,25365,25366,25367,25368,25369,25370,25371,25372,25373,25374,25375, |
| 94748 | 25376,25377,25378,25379,25380,25381,25382,25383,25384,25385,25386,25387, |
| 94749 | 25388,25389,25390,25391,25392,25393,25394,25395,25396,25397,25398,25399, |
| 94750 | 25400,25401,25402,25403,25404,25405,25406,25407,25408,25409,25410,25411, |
| 94751 | 25412,25413,25414,25415,25416,25417,25418,25419,25420,25421,25422,25423, |
| 94752 | 25424,25425,25426,25427,25428,25429,25430,25431,25432,25433,25434,25435, |
| 94753 | 25436,25437,25438,25439,25440,25441,25442,25443,25444,25445,25446,25447, |
| 94754 | 25448,25449,25450,25451,25452,25453,25454,25455,25456,25457,25458,25459, |
| 94755 | 25460,25461,25462,25463,25464,25465,25466,25467,25468,25469,25470,25471, |
| 94756 | 25472,25473,25474,25475,25476,25477,25478,25479,25480,25481,25482,25483, |
| 94757 | 25484,25485,25486,25487,25488,25489,25490,25491,25492,25493,25494,25495, |
| 94758 | 25496,25497,25498,25499,25500,25501,25502,25503,25504,25505,25506,25507, |
| 94759 | 25508,25509,25510,25511,25512,25513,25514,25515,25516,25517,25518,25519, |
| 94760 | 25520,25521,25522,25523,25524,25525,25526,25527,25528,25529,25530,25531, |
| 94761 | 25532,25533,25534,25535,25536,25537,25538,25539,25540,25541,25542,25543, |
| 94762 | 25544,25545,25546,25547,25548,25549,25550,25551,25552,25553,25554,25555, |
| 94763 | 25556,25557,25558,25559,25560,25561,25562,25563,25564,25565,25566,25567, |
| 94764 | 25568,25569,25570,25571,25572,25573,25574,25575,25576,25577,25578,25579, |
| 94765 | 25580,25581,25582,25583,25584,25585,25586,25587,25588,25589,25590,25591, |
| 94766 | 25592,25593,25594,25595,25596,25597,25598,25599,25600,25601,25602,25603, |
| 94767 | 25604,25605,25606,25607,25608,25609,25610,25611,25612,25613,25614,25615, |
| 94768 | 25616,25617,25618,25619,25620,25621,25622,25623,25624,25625,25626,25627, |
| 94769 | 25628,25629,25630,25631,25632,25633,25634,25635,25636,25637,25638,25639, |
| 94770 | 25640,25641,25642,25643,25644,25645,25646,25647,25648,25649,25650,25651, |
| 94771 | 25652,25653,25654,25655,25656,25657,25658,25659,25660,25661,25662,25663, |
| 94772 | 25664,25665,25666,25667,25668,25669,25670,25671,25672,25673,25674,25675, |
| 94773 | 25676,25677,25678,25679,25680,25681,25682,25683,25684,25685,25686,25687, |
| 94774 | 25688,25689,25690,25691,25692,25693,25694,25695,25696,25697,25698,25699, |
| 94775 | 25700,25701,25702,25703,25704,25705,25706,25707,25708,25709,25710,25711, |
| 94776 | 25712,25713,25714,25715,25716,25717,25718,25719,25720,25721,25722,25723, |
| 94777 | 25724,25725,25726,25727,25728,25729,25730,25731,25732,25733,25734,25735, |
| 94778 | 25736,25737,25738,25739,25740,25741,25742,25743,25744,25745,25746,25747, |
| 94779 | 25748,25749,25750,25751,25752,25753,25754,25755,25756,25757,25758,25759, |
| 94780 | 25760,25761,25762,25763,25764,25765,25766,25767,25768,25769,25770,25771, |
| 94781 | 25772,25773,25774,25775,25776,25777,25778,25779,25780,25781,25782,25783, |
| 94782 | 25784,25785,25786,25787,25788,25789,25790,25791,25792,25793,25794,25795, |
| 94783 | 25796,25797,25798,25799,25800,25801,25802,25803,25804,25805,25806,25807, |
| 94784 | 25808,25809,25810,25811,25812,25813,25814,25815,25816,25817,25818,25819, |
| 94785 | 25820,25821,25822,25823,25824,25825,25826,25827,25828,25829,25830,25831, |
| 94786 | 25832,25833,25834,25835,25836,25837,25838,25839,25840,25841,25842,25843, |
| 94787 | 25844,25845,25846,25847,25848,25849,25850,25851,25852,25853,25854,25855, |
| 94788 | 25856,25857,25858,25859,25860,25861,25862,25863,25864,25865,25866,25867, |
| 94789 | 25868,25869,25870,25871,25872,25873,25874,25875,25876,25877,25878,25879, |
| 94790 | 25880,25881,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891, |
| 94791 | 25892,25893,25894,25895,25896,25897,25898,25899,25900,25901,25902,25903, |
| 94792 | 25904,25905,25906,25907,25908,25909,25910,25911,25912,25913,25914,25915, |
| 94793 | 25916,25917,25918,25919,25920,25921,25922,25923,25924,25925,25926,25927, |
| 94794 | 25928,25929,25930,25931,25932,25933,25934,25935,25936,25937,25938,25939, |
| 94795 | 25940,25941,25942,25943,25944,25945,25946,25947,25948,25949,25950,25951, |
| 94796 | 25952,25953,25954,25955,25956,25957,25958,25959,25960,25961,25962,25963, |
| 94797 | 25964,25965,25966,25967,25968,25969,25970,25971,25972,25973,25974,25975, |
| 94798 | 25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986,25987, |
| 94799 | 25988,25989,25990,25991,25992,25993,25994,25995,25996,25997,25998,25999, |
| 94800 | 26000,26001,26002,26003,26004,26005,26006,26007,26008,26009,26010,26011, |
| 94801 | 26012,26013,26014,26015,26016,26017,26018,26019,26020,26021,26022,26023, |
| 94802 | 26024,26025,26026,26027,26028,26029,26030,26031,26032,26033,26034,26035, |
| 94803 | 26036,26037,26038,26039,26040,26041,26042,26043,26044,26045,26046,26047, |
| 94804 | 26048,26049,26050,26051,26052,26053,26054,26055,26056,26057,26058,26059, |
| 94805 | 26060,26061,26062,26063,26064,26065,26066,26067,26068,26069,26070,26071, |
| 94806 | 26072,26073,26074,26075,26076,26077,26078,26079,26080,26081,26082,26083, |
| 94807 | 26084,26085,26086,26087,26088,26089,26090,26091,26092,26093,26094,26095, |
| 94808 | 26096,26097,26098,26099,26100,26101,26102,26103,26104,26105,26106,26107, |
| 94809 | 26108,26109,26110,26111,26112,26113,26114,26115,26116,26117,26118,26119, |
| 94810 | 26120,26121,26122,26123,26124,26125,26126,26127,26128,26129,26130,26131, |
| 94811 | 26132,26133,26134,26135,26136,26137,26138,26139,26140,26141,26142,26143, |
| 94812 | 26144,26145,26146,26147,26148,26149,26150,26151,26152,26153,26154,26155, |
| 94813 | 26156,26157,26158,26159,26160,26161,26162,26163,26164,26165,26166,26167, |
| 94814 | 26168,26169,26170,26171,26172,26173,26174,26175,26176,26177,26178,26179, |
| 94815 | 26180,26181,26182,26183,26184,26185,26186,26187,26188,26189,26190,26191, |
| 94816 | 26192,26193,26194,26195,26196,26197,26198,26199,26200,26201,26202,26203, |
| 94817 | 26204,26205,26206,26207,26208,26209,26210,26211,26212,26213,26214,26215, |
| 94818 | 26216,26217,26218,26219,26220,26221,26222,26223,26224,26225,26226,26227, |
| 94819 | 26228,26229,26230,26231,26232,26233,26234,26235,26236,26237,26238,26239, |
| 94820 | 26240,26241,26242,26243,26244,26245,26246,26247,26248,26249,26250,26251, |
| 94821 | 26252,26253,26254,26255,26256,26257,26258,26259,26260,26261,26262,26263, |
| 94822 | 26264,26265,26266,26267,26268,26269,26270,26271,26272,26273,26274,26275, |
| 94823 | 26276,26277,26278,26279,26280,26281,26282,26283,26284,26285,26286,26287, |
| 94824 | 26288,26289,26290,26291,26292,26293,26294,26295,26296,26297,26298,26299, |
| 94825 | 26300,26301,26302,26303,26304,26305,26306,26307,26308,26309,26310,26311, |
| 94826 | 26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322,26323, |
| 94827 | 26324,26325,26326,26327,26328,26329,26330,26331,26332,26333,26334,26335, |
| 94828 | 26336,26337,26338,26339,26340,26341,26342,26343,26344,26345,26346,26347, |
| 94829 | 26348,26349,26350,26351,26352,26353,26354,26355,26356,26357,26358,26359, |
| 94830 | 26360,26361,26362,26363,26364,26365,26366,26367,26368,26369,26370,26371, |
| 94831 | 26372,26373,26374,26375,26376,26377,26378,26379,26380,26381,26382,26383, |
| 94832 | 26384,26385,26386,26387,26388,26389,26390,26391,26392,26393,26394,26395, |
| 94833 | 26396,26397,26398,26399,26400,26401,26402,26403,26404,26405,26406,26407, |
| 94834 | 26408,26409,26410,26411,26412,26413,26414,26415,26416,26417,26418,26419, |
| 94835 | 26420,26421,26422,26423,26424,26425,26426,26427,26428,26429,26430,26431, |
| 94836 | 26432,26433,26434,26435,26436,26437,26438,26439,26440,26441,26442,26443, |
| 94837 | 26444,26445,26446,26447,26448,26449,26450,26451,26452,26453,26454,26455, |
| 94838 | 26456,26457,26458,26459,26460,26461,26462,26463,26464,26465,26466,26467, |
| 94839 | 26468,26469,26470,26471,26472,26473,26474,26475,26476,26477,26478,26479, |
| 94840 | 26480,26481,26482,26483,26484,26485,26486,26487,26488,26489,26490,26491, |
| 94841 | 26492,26493,26494,26495,26496,26497,26498,26499,26500,26501,26502,26503, |
| 94842 | 26504,26505,26506,26507,26508,26509,26510,26511,26512,26513,26514,26515, |
| 94843 | 26516,26517,26518,26519,26520,26521,26522,26523,26524,26525,26526,26527, |
| 94844 | 26528,26529,26530,26531,26532,26533,26534,26535,26536,26537,26538,26539, |
| 94845 | 26540,26541,26542,26543,26544,26545,26546,26547,26548,26549,26550,26551, |
| 94846 | 26552,26553,26554,26555,26556,26557,26558,26559,26560,26561,26562,26563, |
| 94847 | 26564,26565,26566,26567,26568,26569,26570,26571,26572,26573,26574,26575, |
| 94848 | 26576,26577,26578,26579,26580,26581,26582,26583,26584,26585,26586,26587, |
| 94849 | 26588,26589,26590,26591,26592,26593,26594,26595,26596,26597,26598,26599, |
| 94850 | 26600,26601,26602,26603,26604,26605,26606,26607,26608,26609,26610,26611, |
| 94851 | 26612,26613,26614,26615,26616,26617,26618,26619,26620,26621,26622,26623, |
| 94852 | 26624,26625,26626,26627,26628,26629,26630,26631,26632,26633,26634,26635, |
| 94853 | 26636,26637,26638,26639,26640,26641,26642,26643,26644,26645,26646,26647, |
| 94854 | 26648,26649,26650,26651,26652,26653,26654,26655,26656,26657,26658,26659, |
| 94855 | 26660,26661,26662,26663,26664,26665,26666,26667,26668,26669,26670,26671, |
| 94856 | 26672,26673,26674,26675,26676,26677,26678,26679,26680,26681,26682,26683, |
| 94857 | 26684,26685,26686,26687,26688,26689,26690,26691,26692,26693,26694,26695, |
| 94858 | 26696,26697,26698,26699,26700,26701,26702,26703,26704,26705,26706,26707, |
| 94859 | 26708,26709,26710,26711,26712,26713,26714,26715,26716,26717,26718,26719, |
| 94860 | 26720,26721,26722,26723,26724,26725,26726,26727,26728,26729,26730,26731, |
| 94861 | 26732,26733,26734,26735,26736,26737,26738,26739,26740,26741,26742,26743, |
| 94862 | 26744,26745,26746,26747,26748,26749,26750,26751,26752,26753,26754,26755, |
| 94863 | 26756,26757,26758,26759,26760,26761,26762,26763,26764,26765,26766,26767, |
| 94864 | 26768,26769,26770,26771,26772,26773,26774,26775,26776,26777,26778,26779, |
| 94865 | 26780,26781,26782,26783,26784,26785,26786,26787,26788,26789,26790,26791, |
| 94866 | 26792,26793,26794,26795,26796,26797,26798,26799,26800,26801,26802,26803, |
| 94867 | 26804,26805,26806,26807,26808,26809,26810,26811,26812,26813,26814,26815, |
| 94868 | 26816,26817,26818,26819,26820,26821,26822,26823,26824,26825,26826,26827, |
| 94869 | 26828,26829,26830,26831,26832,26833,26834,26835,26836,26837,26838,26839, |
| 94870 | 26840,26841,26842,26843,26844,26845,26846,26847,26848,26849,26850,26851, |
| 94871 | 26852,26853,26854,26855,26856,26857,26858,26859,26860,26861,26862,26863, |
| 94872 | 26864,26865,26866,26867,26868,26869,26870,26871,26872,26873,26874,26875, |
| 94873 | 26876,26877,26878,26879,26880,26881,26882,26883,26884,26885,26886,26887, |
| 94874 | 26888,26889,26890,26891,26892,26893,26894,26895,26896,26897,26898,26899, |
| 94875 | 26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,26910,26911, |
| 94876 | 26912,26913,26914,26915,26916,26917,26918,26919,26920,26921,26922,26923, |
| 94877 | 26924,26925,26926,26927,26928,26929,26930,26931,26932,26933,26934,26935, |
| 94878 | 26936,26937,26938,26939,26940,26941,26942,26943,26944,26945,26946,26947, |
| 94879 | 26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958,26959, |
| 94880 | 26960,26961,26962,26963,26964,26965,26966,26967,26968,26969,26970,26971, |
| 94881 | 26972,26973,26974,26975,26976,26977,26978,26979,26980,26981,26982,26983, |
| 94882 | 26984,26985,26986,26987,26988,26989,26990,26991,26992,26993,26994,26995, |
| 94883 | 26996,26997,26998,26999,27000,27001,27002,27003,27004,27005,27006,27007, |
| 94884 | 27008,27009,27010,27011,27012,27013,27014,27015,27016,27017,27018,27019, |
| 94885 | 27020,27021,27022,27023,27024,27025,27026,27027,27028,27029,27030,27031, |
| 94886 | 27032,27033,27034,27035,27036,27037,27038,27039,27040,27041,27042,27043, |
| 94887 | 27044,27045,27046,27047,27048,27049,27050,27051,27052,27053,27054,27055, |
| 94888 | 27056,27057,27058,27059,27060,27061,27062,27063,27064,27065,27066,27067, |
| 94889 | 27068,27069,27070,27071,27072,27073,27074,27075,27076,27077,27078,27079, |
| 94890 | 27080,27081,27082,27083,27084,27085,27086,27087,27088,27089,27090,27091, |
| 94891 | 27092,27093,27094,27095,27096,27097,27098,27099,27100,27101,27102,27103, |
| 94892 | 27104,27105,27106,27107,27108,27109,27110,27111,27112,27113,27114,27115, |
| 94893 | 27116,27117,27118,27119,27120,27121,27122,27123,27124,27125,27126,27127, |
| 94894 | 27128,27129,27130,27131,27132,27133,27134,27135,27136,27137,27138,27139, |
| 94895 | 27140,27141,27142,27143,27144,27145,27146,27147,27148,27149,27150,27151, |
| 94896 | 27152,27153,27154,27155,27156,27157,27158,27159,27160,27161,27162,27163, |
| 94897 | 27164,27165,27166,27167,27168,27169,27170,27171,27172,27173,27174,27175, |
| 94898 | 27176,27177,27178,27179,27180,27181,27182,27183,27184,27185,27186,27187, |
| 94899 | 27188,27189,27190,27191,27192,27193,27194,27195,27196,27197,27198,27199, |
| 94900 | 27200,27201,27202,27203,27204,27205,27206,27207,27208,27209,27210,27211, |
| 94901 | 27212,27213,27214,27215,27216,27217,27218,27219,27220,27221,27222,27223, |
| 94902 | 27224,27225,27226,27227,27228,27229,27230,27231,27232,27233,27234,27235, |
| 94903 | 27236,27237,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247, |
| 94904 | 27248,27249,27250,27251,27252,27253,27254,27255,27256,27257,27258,27259, |
| 94905 | 27260,27261,27262,27263,27264,27265,27266,27267,27268,27269,27270,27271, |
| 94906 | 27272,27273,27274,27275,27276,27277,27278,27279,27280,27281,27282,27283, |
| 94907 | 27284,27285,27286,27287,27288,27289,27290,27291,27292,27293,27294,27295, |
| 94908 | 27296,27297,27298,27299,27300,27301,27302,27303,27304,27305,27306,27307, |
| 94909 | 27308,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319, |
| 94910 | 27320,27321,27322,27323,27324,27325,27326,27327,27328,27329,27330,27331, |
| 94911 | 27332,27333,27334,27335,27336,27337,27338,27339,27340,27341,27342,27343, |
| 94912 | 27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355, |
| 94913 | 27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367, |
| 94914 | 27368,27369,27370,27371,27372,27373,27374,27375,27376,27377,27378,27379, |
| 94915 | 27380,27381,27382,27383,27384,27385,27386,27387,27388,27389,27390,27391, |
| 94916 | 27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402,27403, |
| 94917 | 27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415, |
| 94918 | 27416,27417,27418,27419,27420,27421,27422,27423,27424,27425,27426,27427, |
| 94919 | 27428,27429,27430,27431,27432,27433,27434,27435,27436,27437,27438,27439, |
| 94920 | 27440,27441,27442,27443,27444,27445,27446,27447,27448,27449,27450,27451, |
| 94921 | 27452,27453,27454,27455,27456,27457,27458,27459,27460,27461,27462,27463, |
| 94922 | 27464,27465,27466,27467,27468,27469,27470,27471,27472,27473,27474,27475, |
| 94923 | 27476,27477,27478,27479,27480,27481,27482,27483,27484,27485,27486,27487, |
| 94924 | 27488,27489,27490,27491,27492,27493,27494,27495,27496,27497,27498,27499, |
| 94925 | 27500,27501,27502,27503,27504,27505,27506,27507,27508,27509,27510,27511, |
| 94926 | 27512,27513,27514,27515,27516,27517,27518,27519,27520,27521,27522,27523, |
| 94927 | 27524,27525,27526,27527,27528,27529,27530,27531,27532,27533,27534,27535, |
| 94928 | 27536,27537,27538,27539,27540,27541,27542,27543,27544,27545,27546,27547, |
| 94929 | 27548,27549,27550,27551,27552,27553,27554,27555,27556,27557,27558,27559, |
| 94930 | 27560,27561,27562,27563,27564,27565,27566,27567,27568,27569,27570,27571, |
| 94931 | 27572,27573,27574,27575,27576,27577,27578,27579,27580,27581,27582,27583, |
| 94932 | 27584,27585,27586,27587,27588,27589,27590,27591,27592,27593,27594,27595, |
| 94933 | 27596,27597,27598,27599,27600,27601,27602,27603,27604,27605,27606,27607, |
| 94934 | 27608,27609,27610,27611,27612,27613,27614,27615,27616,27617,27618,27619, |
| 94935 | 27620,27621,27622,27623,27624,27625,27626,27627,27628,27629,27630,27631, |
| 94936 | 27632,27633,27634,27635,27636,27637,27638,27639,27640,27641,27642,27643, |
| 94937 | 27644,27645,27646,27647,27648,27649,27650,27651,27652,27653,27654,27655, |
| 94938 | 27656,27657,27658,27659,27660,27661,27662,27663,27664,27665,27666,27667, |
| 94939 | 27668,27669,27670,27671,27672,27673,27674,27675,27676,27677,27678,27679, |
| 94940 | 27680,27681,27682,27683,27684,27685,27686,27687,27688,27689,27690,27691, |
| 94941 | 27692,27693,27694,27695,27696,27697,27698,27699,27700,27701,27702,27703, |
| 94942 | 27704,27705,27706,27707,27708,27709,27710,27711,27712,27713,27714,27715, |
| 94943 | 27716,27717,27718,27719,27720,27721,27722,27723,27724,27725,27726,27727, |
| 94944 | 27728,27729,27730,27731,27732,27733,27734,27735,27736,27737,27738,27739, |
| 94945 | 27740,27741,27742,27743,27744,27745,27746,27747,27748,27749,27750,27751, |
| 94946 | 27752,27753,27754,27755,27756,27757,27758,27759,27760,27761,27762,27763, |
| 94947 | 27764,27765,27766,27767,27768,27769,27770,27771,27772,27773,27774,27775, |
| 94948 | 27776,27777,27778,27779,27780,27781,27782,27783,27784,27785,27786,27787, |
| 94949 | 27788,27789,27790,27791,27792,27793,27794,27795,27796,27797,27798,27799, |
| 94950 | 27800,27801,27802,27803,27804,27805,27806,27807,27808,27809,27810,27811, |
| 94951 | 27812,27813,27814,27815,27816,27817,27818,27819,27820,27821,27822,27823, |
| 94952 | 27824,27825,27826,27827,27828,27829,27830,27831,27832,27833,27834,27835, |
| 94953 | 27836,27837,27838,27839,27840,27841,27842,27843,27844,27845,27846,27847, |
| 94954 | 27848,27849,27850,27851,27852,27853,27854,27855,27856,27857,27858,27859, |
| 94955 | 27860,27861,27862,27863,27864,27865,27866,27867,27868,27869,27870,27871, |
| 94956 | 27872,27873,27874,27875,27876,27877,27878,27879,27880,27881,27882,27883, |
| 94957 | 27884,27885,27886,27887,27888,27889,27890,27891,27892,27893,27894,27895, |
| 94958 | 27896,27897,27898,27899,27900,27901,27902,27903,27904,27905,27906,27907, |
| 94959 | 27908,27909,27910,27911,27912,27913,27914,27915,27916,27917,27918,27919, |
| 94960 | 27920,27921,27922,27923,27924,27925,27926,27927,27928,27929,27930,27931, |
| 94961 | 27932,27933,27934,27935,27936,27937,27938,27939,27940,27941,27942,27943, |
| 94962 | 27944,27945,27946,27947,27948,27949,27950,27951,27952,27953,27954,27955, |
| 94963 | 27956,27957,27958,27959,27960,27961,27962,27963,27964,27965,27966,27967, |
| 94964 | 27968,27969,27970,27971,27972,27973,27974,27975,27976,27977,27978,27979, |
| 94965 | 27980,27981,27982,27983,27984,27985,27986,27987,27988,27989,27990,27991, |
| 94966 | 27992,27993,27994,27995,27996,27997,27998,27999,28000,28001,28002,28003, |
| 94967 | 28004,28005,28006,28007,28008,28009,28010,28011,28012,28013,28014,28015, |
| 94968 | 28016,28017,28018,28019,28020,28021,28022,28023,28024,28025,28026,28027, |
| 94969 | 28028,28029,28030,28031,28032,28033,28034,28035,28036,28037,28038,28039, |
| 94970 | 28040,28041,28042,28043,28044,28045,28046,28047,28048,28049,28050,28051, |
| 94971 | 28052,28053,28054,28055,28056,28057,28058,28059,28060,28061,28062,28063, |
| 94972 | 28064,28065,28066,28067,28068,28069,28070,28071,28072,28073,28074,28075, |
| 94973 | 28076,28077,28078,28079,28080,28081,28082,28083,28084,28085,28086,28087, |
| 94974 | 28088,28089,28090,28091,28092,28093,28094,28095,28096,28097,28098,28099, |
| 94975 | 28100,28101,28102,28103,28104,28105,28106,28107,28108,28109,28110,28111, |
| 94976 | 28112,28113,28114,28115,28116,28117,28118,28119,28120,28121,28122,28123, |
| 94977 | 28124,28125,28126,28127,28128,28129,28130,28131,28132,28133,28134,28135, |
| 94978 | 28136,28137,28138,28139,28140,28141,28142,28143,28144,28145,28146,28147, |
| 94979 | 28148,28149,28150,28151,28152,28153,28154,28155,28156,28157,28158,28159, |
| 94980 | 28160,28161,28162,28163,28164,28165,28166,28167,28168,28169,28170,28171, |
| 94981 | 28172,28173,28174,28175,28176,28177,28178,28179,28180,28181,28182,28183, |
| 94982 | 28184,28185,28186,28187,28188,28189,28190,28191,28192,28193,28194,28195, |
| 94983 | 28196,28197,28198,28199,28200,28201,28202,28203,28204,28205,28206,28207, |
| 94984 | 28208,28209,28210,28211,28212,28213,28214,28215,28216,28217,28218,28219, |
| 94985 | 28220,28221,28222,28223,28224,28225,28226,28227,28228,28229,28230,28231, |
| 94986 | 28232,28233,28234,28235,28236,28237,28238,28239,28240,28241,28242,28243, |
| 94987 | 28244,28245,28246,28247,28248,28249,28250,28251,28252,28253,28254,28255, |
| 94988 | 28256,28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28267, |
| 94989 | 28268,28269,28270,28271,28272,28273,28274,28275,28276,28277,28278,28279, |
| 94990 | 28280,28281,28282,28283,28284,28285,28286,28287,28288,28289,28290,28291, |
| 94991 | 28292,28293,28294,28295,28296,28297,28298,28299,28300,28301,28302,28303, |
| 94992 | 28304,28305,28306,28307,28308,28309,28310,28311,28312,28313,28314,28315, |
| 94993 | 28316,28317,28318,28319,28320,28321,28322,28323,28324,28325,28326,28327, |
| 94994 | 28328,28329,28330,28331,28332,28333,28334,28335,28336,28337,28338,28339, |
| 94995 | 28340,28341,28342,28343,28344,28345,28346,28347,28348,28349,28350,28351, |
| 94996 | 28352,28353,28354,28355,28356,28357,28358,28359,28360,28361,28362,28363, |
| 94997 | 28364,28365,28366,28367,28368,28369,28370,28371,28372,28373,28374,28375, |
| 94998 | 28376,28377,28378,28379,28380,28381,28382,28383,28384,28385,28386,28387, |
| 94999 | 28388,28389,28390,28391,28392,28393,28394,28395,28396,28397,28398,28399, |
| 95000 | 28400,28401,28402,28403,28404,28405,28406,28407,28408,28409,28410,28411, |
| 95001 | 28412,28413,28414,28415,28416,28417,28418,28419,28420,28421,28422,28423, |
| 95002 | 28424,28425,28426,28427,28428,28429,28430,28431,28432,28433,28434,28435, |
| 95003 | 28436,28437,28438,28439,28440,28441,28442,28443,28444,28445,28446,28447, |
| 95004 | 28448,28449,28450,28451,28452,28453,28454,28455,28456,28457,28458,28459, |
| 95005 | 28460,28461,28462,28463,28464,28465,28466,28467,28468,28469,28470,28471, |
| 95006 | 28472,28473,28474,28475,28476,28477,28478,28479,28480,28481,28482,28483, |
| 95007 | 28484,28485,28486,28487,28488,28489,28490,28491,28492,28493,28494,28495, |
| 95008 | 28496,28497,28498,28499,28500,28501,28502,28503,28504,28505,28506,28507, |
| 95009 | 28508,28509,28510,28511,28512,28513,28514,28515,28516,28517,28518,28519, |
| 95010 | 28520,28521,28522,28523,28524,28525,28526,28527,28528,28529,28530,28531, |
| 95011 | 28532,28533,28534,28535,28536,28537,28538,28539,28540,28541,28542,28543, |
| 95012 | 28544,28545,28546,28547,28548,28549,28550,28551,28552,28553,28554,28555, |
| 95013 | 28556,28557,28558,28559,28560,28561,28562,28563,28564,28565,28566,28567, |
| 95014 | 28568,28569,28570,28571,28572,28573,28574,28575,28576,28577,28578,28579, |
| 95015 | 28580,28581,28582,28583,28584,28585,28586,28587,28588,28589,28590,28591, |
| 95016 | 28592,28593,28594,28595,28596,28597,28598,28599,28600,28601,28602,28603, |
| 95017 | 28604,28605,28606,28607,28608,28609,28610,28611,28612,28613,28614,28615, |
| 95018 | 28616,28617,28618,28619,28620,28621,28622,28623,28624,28625,28626,28627, |
| 95019 | 28628,28629,28630,28631,28632,28633,28634,28635,28636,28637,28638,28639, |
| 95020 | 28640,28641,28642,28643,28644,28645,28646,28647,28648,28649,28650,28651, |
| 95021 | 28652,28653,28654,28655,28656,28657,28658,28659,28660,28661,28662,28663, |
| 95022 | 28664,28665,28666,28667,28668,28669,28670,28671,28672,28673,28674,28675, |
| 95023 | 28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687, |
| 95024 | 28688,28689,28690,28691,28692,28693,28694,28695,28696,28697,28698,28699, |
| 95025 | 28700,28701,28702,28703,28704,28705,28706,28707,28708,28709,28710,28711, |
| 95026 | 28712,28713,28714,28715,28716,28717,28718,28719,28720,28721,28722,28723, |
| 95027 | 28724,28725,28726,28727,28728,28729,28730,28731,28732,28733,28734,28735, |
| 95028 | 28736,28737,28738,28739,28740,28741,28742,28743,28744,28745,28746,28747, |
| 95029 | 28748,28749,28750,28751,28752,28753,28754,28755,28756,28757,28758,28759, |
| 95030 | 28760,28761,28762,28763,28764,28765,28766,28767,28768,28769,28770,28771, |
| 95031 | 28772,28773,28774,28775,28776,28777,28778,28779,28780,28781,28782,28783, |
| 95032 | 28784,28785,28786,28787,28788,28789,28790,28791,28792,28793,28794,28795, |
| 95033 | 28796,28797,28798,28799,28800,28801,28802,28803,28804,28805,28806,28807, |
| 95034 | 28808,28809,28810,28811,28812,28813,28814,28815,28816,28817,28818,28819, |
| 95035 | 28820,28821,28822,28823,28824,28825,28826,28827,28828,28829,28830,28831, |
| 95036 | 28832,28833,28834,28835,28836,28837,28838,28839,28840,28841,28842,28843, |
| 95037 | 28844,28845,28846,28847,28848,28849,28850,28851,28852,28853,28854,28855, |
| 95038 | 28856,28857,28858,28859,28860,28861,28862,28863,28864,28865,28866,28867, |
| 95039 | 28868,28869,28870,28871,28872,28873,28874,28875,28876,28877,28878,28879, |
| 95040 | 28880,28881,28882,28883,28884,28885,28886,28887,28888,28889,28890,28891, |
| 95041 | 28892,28893,28894,28895,28896,28897,28898,28899,28900,28901,28902,28903, |
| 95042 | 28904,28905,28906,28907,28908,28909,28910,28911,28912,28913,28914,28915, |
| 95043 | 28916,28917,28918,28919,28920,28921,28922,28923,28924,28925,28926,28927, |
| 95044 | 28928,28929,28930,28931,28932,28933,28934,28935,28936,28937,28938,28939, |
| 95045 | 28940,28941,28942,28943,28944,28945,28946,28947,28948,28949,28950,28951, |
| 95046 | 28952,28953,28954,28955,28956,28957,28958,28959,28960,28961,28962,28963, |
| 95047 | 28964,28965,28966,28967,28968,28969,28970,28971,28972,28973,28974,28975, |
| 95048 | 28976,28977,28978,28979,28980,28981,28982,28983,28984,28985,28986,28987, |
| 95049 | 28988,28989,28990,28991,28992,28993,28994,28995,28996,28997,28998,28999, |
| 95050 | 29000,29001,29002,29003,29004,29005,29006,29007,29008,29009,29010,29011, |
| 95051 | 29012,29013,29014,29015,29016,29017,29018,29019,29020,29021,29022,29023, |
| 95052 | 29024,29025,29026,29027,29028,29029,29030,29031,29032,29033,29034,29035, |
| 95053 | 29036,29037,29038,29039,29040,29041,29042,29043,29044,29045,29046,29047, |
| 95054 | 29048,29049,29050,29051,29052,29053,29054,29055,29056,29057,29058,29059, |
| 95055 | 29060,29061,29062,29063,29064,29065,29066,29067,29068,29069,29070,29071, |
| 95056 | 29072,29073,29074,29075,29076,29077,29078,29079,29080,29081,29082,29083, |
| 95057 | 29084,29085,29086,29087,29088,29089,29090,29091,29092,29093,29094,29095, |
| 95058 | 29096,29097,29098,29099,29100,29101,29102,29103,29104,29105,29106,29107, |
| 95059 | 29108,29109,29110,29111,29112,29113,29114,29115,29116,29117,29118,29119, |
| 95060 | 29120,29121,29122,29123,29124,29125,29126,29127,29128,29129,29130,29131, |
| 95061 | 29132,29133,29134,29135,29136,29137,29138,29139,29140,29141,29142,29143, |
| 95062 | 29144,29145,29146,29147,29148,29149,29150,29151,29152,29153,29154,29155, |
| 95063 | 29156,29157,29158,29159,29160,29161,29162,29163,29164,29165,29166,29167, |
| 95064 | 29168,29169,29170,29171,29172,29173,29174,29175,29176,29177,29178,29179, |
| 95065 | 29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29190,29191, |
| 95066 | 29192,29193,29194,29195,29196,29197,29198,29199,29200,29201,29202,29203, |
| 95067 | 29204,29205,29206,29207,29208,29209,29210,29211,29212,29213,29214,29215, |
| 95068 | 29216,29217,29218,29219,29220,29221,29222,29223,29224,29225,29226,29227, |
| 95069 | 29228,29229,29230,29231,29232,29233,29234,29235,29236,29237,29238,29239, |
| 95070 | 29240,29241,29242,29243,29244,29245,29246,29247,29248,29249,29250,29251, |
| 95071 | 29252,29253,29254,29255,29256,29257,29258,29259,29260,29261,29262,29263, |
| 95072 | 29264,29265,29266,29267,29268,29269,29270,29271,29272,29273,29274,29275, |
| 95073 | 29276,29277,29278,29279,29280,29281,29282,29283,29284,29285,29286,29287, |
| 95074 | 29288,29289,29290,29291,29292,29293,29294,29295,29296,29297,29298,29299, |
| 95075 | 29300,29301,29302,29303,29304,29305,29306,29307,29308,29309,29310,29311, |
| 95076 | 29312,29313,29314,29315,29316,29317,29318,29319,29320,29321,29322,29323, |
| 95077 | 29324,29325,29326,29327,29328,29329,29330,29331,29332,29333,29334,29335, |
| 95078 | 29336,29337,29338,29339,29340,29341,29342,29343,29344,29345,29346,29347, |
| 95079 | 29348,29349,29350,29351,29352,29353,29354,29355,29356,29357,29358,29359, |
| 95080 | 29360,29361,29362,29363,29364,29365,29366,29367,29368,29369,29370,29371, |
| 95081 | 29372,29373,29374,29375,29376,29377,29378,29379,29380,29381,29382,29383, |
| 95082 | 29384,29385,29386,29387,29388,29389,29390,29391,29392,29393,29394,29395, |
| 95083 | 29396,29397,29398,29399,29400,29401,29402,29403,29404,29405,29406,29407, |
| 95084 | 29408,29409,29410,29411,29412,29413,29414,29415,29416,29417,29418,29419, |
| 95085 | 29420,29421,29422,29423,29424,29425,29426,29427,29428,29429,29430,29431, |
| 95086 | 29432,29433,29434,29435,29436,29437,29438,29439,29440,29441,29442,29443, |
| 95087 | 29444,29445,29446,29447,29448,29449,29450,29451,29452,29453,29454,29455, |
| 95088 | 29456,29457,29458,29459,29460,29461,29462,29463,29464,29465,29466,29467, |
| 95089 | 29468,29469,29470,29471,29472,29473,29474,29475,29476,29477,29478,29479, |
| 95090 | 29480,29481,29482,29483,29484,29485,29486,29487,29488,29489,29490,29491, |
| 95091 | 29492,29493,29494,29495,29496,29497,29498,29499,29500,29501,29502,29503, |
| 95092 | 29504,29505,29506,29507,29508,29509,29510,29511,29512,29513,29514,29515, |
| 95093 | 29516,29517,29518,29519,29520,29521,29522,29523,29524,29525,29526,29527, |
| 95094 | 29528,29529,29530,29531,29532,29533,29534,29535,29536,29537,29538,29539, |
| 95095 | 29540,29541,29542,29543,29544,29545,29546,29547,29548,29549,29550,29551, |
| 95096 | 29552,29553,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563, |
| 95097 | 29564,29565,29566,29567,29568,29569,29570,29571,29572,29573,29574,29575, |
| 95098 | 29576,29577,29578,29579,29580,29581,29582,29583,29584,29585,29586,29587, |
| 95099 | 29588,29589,29590,29591,29592,29593,29594,29595,29596,29597,29598,29599, |
| 95100 | 29600,29601,29602,29603,29604,29605,29606,29607,29608,29609,29610,29611, |
| 95101 | 29612,29613,29614,29615,29616,29617,29618,29619,29620,29621,29622,29623, |
| 95102 | 29624,29625,29626,29627,29628,29629,29630,29631,29632,29633,29634,29635, |
| 95103 | 29636,29637,29638,29639,29640,29641,29642,29643,29644,29645,29646,29647, |
| 95104 | 29648,29649,29650,29651,29652,29653,29654,29655,29656,29657,29658,29659, |
| 95105 | 29660,29661,29662,29663,29664,29665,29666,29667,29668,29669,29670,29671, |
| 95106 | 29672,29673,29674,29675,29676,29677,29678,29679,29680,29681,29682,29683, |
| 95107 | 29684,29685,29686,29687,29688,29689,29690,29691,29692,29693,29694,29695, |
| 95108 | 29696,29697,29698,29699,29700,29701,29702,29703,29704,29705,29706,29707, |
| 95109 | 29708,29709,29710,29711,29712,29713,29714,29715,29716,29717,29718,29719, |
| 95110 | 29720,29721,29722,29723,29724,29725,29726,29727,29728,29729,29730,29731, |
| 95111 | 29732,29733,29734,29735,29736,29737,29738,29739,29740,29741,29742,29743, |
| 95112 | 29744,29745,29746,29747,29748,29749,29750,29751,29752,29753,29754,29755, |
| 95113 | 29756,29757,29758,29759,29760,29761,29762,29763,29764,29765,29766,29767, |
| 95114 | 29768,29769,29770,29771,29772,29773,29774,29775,29776,29777,29778,29779, |
| 95115 | 29780,29781,29782,29783,29784,29785,29786,29787,29788,29789,29790,29791, |
| 95116 | 29792,29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803, |
| 95117 | 29804,29805,29806,29807,29808,29809,29810,29811,29812,29813,29814,29815, |
| 95118 | 29816,29817,29818,29819,29820,29821,29822,29823,29824,29825,29826,29827, |
| 95119 | 29828,29829,29830,29831,29832,29833,29834,29835,29836,29837,29838,29839, |
| 95120 | 29840,29841,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851, |
| 95121 | 29852,29853,29854,29855,29856,29857,29858,29859,29860,29861,29862,29863, |
| 95122 | 29864,29865,29866,29867,29868,29869,29870,29871,29872,29873,29874,29875, |
| 95123 | 29876,29877,29878,29879,29880,29881,29882,29883,29884,29885,29886,29887, |
| 95124 | 29888,29889,29890,29891,29892,29893,29894,29895,29896,29897,29898,29899, |
| 95125 | 29900,29901,29902,29903,29904,29905,29906,29907,29908,29909,29910,29911, |
| 95126 | 29912,29913,29914,29915,29916,29917,29918,29919,29920,29921,29922,29923, |
| 95127 | 29924,29925,29926,29927,29928,29929,29930,29931,29932,29933,29934,29935, |
| 95128 | 29936,29937,29938,29939,29940,29941,29942,29943,29944,29945,29946,29947, |
| 95129 | 29948,29949,29950,29951,29952,29953,29954,29955,29956,29957,29958,29959, |
| 95130 | 29960,29961,29962,29963,29964,29965,29966,29967,29968,29969,29970,29971, |
| 95131 | 29972,29973,29974,29975,29976,29977,29978,29979,29980,29981,29982,29983, |
| 95132 | 29984,29985,29986,29987,29988,29989,29990,29991,29992,29993,29994,29995, |
| 95133 | 29996,29997,29998,29999,30000,30001,30002,30003,30004,30005,30006,30007, |
| 95134 | 30008,30009,30010,30011,30012,30013,30014,30015,30016,30017,30018,30019, |
| 95135 | 30020,30021,30022,30023,30024,30025,30026,30027,30028,30029,30030,30031, |
| 95136 | 30032,30033,30034,30035,30036,30037,30038,30039,30040,30041,30042,30043, |
| 95137 | 30044,30045,30046,30047,30048,30049,30050,30051,30052,30053,30054,30055, |
| 95138 | 30056,30057,30058,30059,30060,30061,30062,30063,30064,30065,30066,30067, |
| 95139 | 30068,30069,30070,30071,30072,30073,30074,30075,30076,30077,30078,30079, |
| 95140 | 30080,30081,30082,30083,30084,30085,30086,30087,30088,30089,30090,30091, |
| 95141 | 30092,30093,30094,30095,30096,30097,30098,30099,30100,30101,30102,30103, |
| 95142 | 30104,30105,30106,30107,30108,30109,30110,30111,30112,30113,30114,30115, |
| 95143 | 30116,30117,30118,30119,30120,30121,30122,30123,30124,30125,30126,30127, |
| 95144 | 30128,30129,30130,30131,30132,30133,30134,30135,30136,30137,30138,30139, |
| 95145 | 30140,30141,30142,30143,30144,30145,30146,30147,30148,30149,30150,30151, |
| 95146 | 30152,30153,30154,30155,30156,30157,30158,30159,30160,30161,30162,30163, |
| 95147 | 30164,30165,30166,30167,30168,30169,30170,30171,30172,30173,30174,30175, |
| 95148 | 30176,30177,30178,30179,30180,30181,30182,30183,30184,30185,30186,30187, |
| 95149 | 30188,30189,30190,30191,30192,30193,30194,30195,30196,30197,30198,30199, |
| 95150 | 30200,30201,30202,30203,30204,30205,30206,30207,30208,30209,30210,30211, |
| 95151 | 30212,30213,30214,30215,30216,30217,30218,30219,30220,30221,30222,30223, |
| 95152 | 30224,30225,30226,30227,30228,30229,30230,30231,30232,30233,30234,30235, |
| 95153 | 30236,30237,30238,30239,30240,30241,30242,30243,30244,30245,30246,30247, |
| 95154 | 30248,30249,30250,30251,30252,30253,30254,30255,30256,30257,30258,30259, |
| 95155 | 30260,30261,30262,30263,30264,30265,30266,30267,30268,30269,30270,30271, |
| 95156 | 30272,30273,30274,30275,30276,30277,30278,30279,30280,30281,30282,30283, |
| 95157 | 30284,30285,30286,30287,30288,30289,30290,30291,30292,30293,30294,30295, |
| 95158 | 30296,30297,30298,30299,30300,30301,30302,30303,30304,30305,30306,30307, |
| 95159 | 30308,30309,30310,30311,30312,30313,30314,30315,30316,30317,30318,30319, |
| 95160 | 30320,30321,30322,30323,30324,30325,30326,30327,30328,30329,30330,30331, |
| 95161 | 30332,30333,30334,30335,30336,30337,30338,30339,30340,30341,30342,30343, |
| 95162 | 30344,30345,30346,30347,30348,30349,30350,30351,30352,30353,30354,30355, |
| 95163 | 30356,30357,30358,30359,30360,30361,30362,30363,30364,30365,30366,30367, |
| 95164 | 30368,30369,30370,30371,30372,30373,30374,30375,30376,30377,30378,30379, |
| 95165 | 30380,30381,30382,30383,30384,30385,30386,30387,30388,30389,30390,30391, |
| 95166 | 30392,30393,30394,30395,30396,30397,30398,30399,30400,30401,30402,30403, |
| 95167 | 30404,30405,30406,30407,30408,30409,30410,30411,30412,30413,30414,30415, |
| 95168 | 30416,30417,30418,30419,30420,30421,30422,30423,30424,30425,30426,30427, |
| 95169 | 30428,30429,30430,30431,30432,30433,30434,30435,30436,30437,30438,30439, |
| 95170 | 30440,30441,30442,30443,30444,30445,30446,30447,30448,30449,30450,30451, |
| 95171 | 30452,30453,30454,30455,30456,30457,30458,30459,30460,30461,30462,30463, |
| 95172 | 30464,30465,30466,30467,30468,30469,30470,30471,30472,30473,30474,30475, |
| 95173 | 30476,30477,30478,30479,30480,30481,30482,30483,30484,30485,30486,30487, |
| 95174 | 30488,30489,30490,30491,30492,30493,30494,30495,30496,30497,30498,30499, |
| 95175 | 30500,30501,30502,30503,30504,30505,30506,30507,30508,30509,30510,30511, |
| 95176 | 30512,30513,30514,30515,30516,30517,30518,30519,30520,30521,30522,30523, |
| 95177 | 30524,30525,30526,30527,30528,30529,30530,30531,30532,30533,30534,30535, |
| 95178 | 30536,30537,30538,30539,30540,30541,30542,30543,30544,30545,30546,30547, |
| 95179 | 30548,30549,30550,30551,30552,30553,30554,30555,30556,30557,30558,30559, |
| 95180 | 30560,30561,30562,30563,30564,30565,30566,30567,30568,30569,30570,30571, |
| 95181 | 30572,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583, |
| 95182 | 30584,30585,30586,30587,30588,30589,30590,30591,30592,30593,30594,30595, |
| 95183 | 30596,30597,30598,30599,30600,30601,30602,30603,30604,30605,30606,30607, |
| 95184 | 30608,30609,30610,30611,30612,30613,30614,30615,30616,30617,30618,30619, |
| 95185 | 30620,30621,30622,30623,30624,30625,30626,30627,30628,30629,30630,30631, |
| 95186 | 30632,30633,30634,30635,30636,30637,30638,30639,30640,30641,30642,30643, |
| 95187 | 30644,30645,30646,30647,30648,30649,30650,30651,30652,30653,30654,30655, |
| 95188 | 30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667, |
| 95189 | 30668,30669,30670,30671,30672,30673,30674,30675,30676,30677,30678,30679, |
| 95190 | 30680,30681,30682,30683,30684,30685,30686,30687,30688,30689,30690,30691, |
| 95191 | 30692,30693,30694,30695,30696,30697,30698,30699,30700,30701,30702,30703, |
| 95192 | 30704,30705,30706,30707,30708,30709,30710,30711,30712,30713,30714,30715, |
| 95193 | 30716,30717,30718,30719,30720,30721,30722,30723,30724,30725,30726,30727, |
| 95194 | 30728,30729,30730,30731,30732,30733,30734,30735,30736,30737,30738,30739, |
| 95195 | 30740,30741,30742,30743,30744,30745,30746,30747,30748,30749,30750,30751, |
| 95196 | 30752,30753,30754,30755,30756,30757,30758,30759,30760,30761,30762,30763, |
| 95197 | 30764,30765,30766,30767,30768,30769,30770,30771,30772,30773,30774,30775, |
| 95198 | 30776,30777,30778,30779,30780,30781,30782,30783,30784,30785,30786,30787, |
| 95199 | 30788,30789,30790,30791,30792,30793,30794,30795,30796,30797,30798,30799, |
| 95200 | 30800,30801,30802,30803,30804,30805,30806,30807,30808,30809,30810,30811, |
| 95201 | 30812,30813,30814,30815,30816,30817,30818,30819,30820,30821,30822,30823, |
| 95202 | 30824,30825,30826,30827,30828,30829,30830,30831,30832,30833,30834,30835, |
| 95203 | 30836,30837,30838,30839,30840,30841,30842,30843,30844,30845,30846,30847, |
| 95204 | 30848,30849,30850,30851,30852,30853,30854,30855,30856,30857,30858,30859, |
| 95205 | 30860,30861,30862,30863,30864,30865,30866,30867,30868,30869,30870,30871, |
| 95206 | 30872,30873,30874,30875,30876,30877,30878,30879,30880,30881,30882,30883, |
| 95207 | 30884,30885,30886,30887,30888,30889,30890,30891,30892,30893,30894,30895, |
| 95208 | 30896,30897,30898,30899,30900,30901,30902,30903,30904,30905,30906,30907, |
| 95209 | 30908,30909,30910,30911,30912,30913,30914,30915,30916,30917,30918,30919, |
| 95210 | 30920,30921,30922,30923,30924,30925,30926,30927,30928,30929,30930,30931, |
| 95211 | 30932,30933,30934,30935,30936,30937,30938,30939,30940,30941,30942,30943, |
| 95212 | 30944,30945,30946,30947,30948,30949,30950,30951,30952,30953,30954,30955, |
| 95213 | 30956,30957,30958,30959,30960,30961,30962,30963,30964,30965,30966,30967, |
| 95214 | 30968,30969,30970,30971,30972,30973,30974,30975,30976,30977,30978,30979, |
| 95215 | 30980,30981,30982,30983,30984,30985,30986,30987,30988,30989,30990,30991, |
| 95216 | 30992,30993,30994,30995,30996,30997,30998,30999,31000,31001,31002,31003, |
| 95217 | 31004,31005,31006,31007,31008,31009,31010,31011,31012,31013,31014,31015, |
| 95218 | 31016,31017,31018,31019,31020,31021,31022,31023,31024,31025,31026,31027, |
| 95219 | 31028,31029,31030,31031,31032,31033,31034,31035,31036,31037,31038,31039, |
| 95220 | 31040,31041,31042,31043,31044,31045,31046,31047,31048,31049,31050,31051, |
| 95221 | 31052,31053,31054,31055,31056,31057,31058,31059,31060,31061,31062,31063, |
| 95222 | 31064,31065,31066,31067,31068,31069,31070,31071,31072,31073,31074,31075, |
| 95223 | 31076,31077,31078,31079,31080,31081,31082,31083,31084,31085,31086,31087, |
| 95224 | 31088,31089,31090,31091,31092,31093,31094,31095,31096,31097,31098,31099, |
| 95225 | 31100,31101,31102,31103,31104,31105,31106,31107,31108,31109,31110,31111, |
| 95226 | 31112,31113,31114,31115,31116,31117,31118,31119,31120,31121,31122,31123, |
| 95227 | 31124,31125,31126,31127,31128,31129,31130,31131,31132,31133,31134,31135, |
| 95228 | 31136,31137,31138,31139,31140,31141,31142,31143,31144,31145,31146,31147, |
| 95229 | 31148,31149,31150,31151,31152,31153,31154,31155,31156,31157,31158,31159, |
| 95230 | 31160,31161,31162,31163,31164,31165,31166,31167,31168,31169,31170,31171, |
| 95231 | 31172,31173,31174,31175,31176,31177,31178,31179,31180,31181,31182,31183, |
| 95232 | 31184,31185,31186,31187,31188,31189,31190,31191,31192,31193,31194,31195, |
| 95233 | 31196,31197,31198,31199,31200,31201,31202,31203,31204,31205,31206,31207, |
| 95234 | 31208,31209,31210,31211,31212,31213,31214,31215,31216,31217,31218,31219, |
| 95235 | 31220,31221,31222,31223,31224,31225,31226,31227,31228,31229,31230,31231, |
| 95236 | 31232,31233,31234,31235,31236,31237,31238,31239,31240,31241,31242,31243, |
| 95237 | 31244,31245,31246,31247,31248,31249,31250,31251,31252,31253,31254,31255, |
| 95238 | 31256,31257,31258,31259,31260,31261,31262,31263,31264,31265,31266,31267, |
| 95239 | 31268,31269,31270,31271,31272,31273,31274,31275,31276,31277,31278,31279, |
| 95240 | 31280,31281,31282,31283,31284,31285,31286,31287,31288,31289,31290,31291, |
| 95241 | 31292,31293,31294,31295,31296,31297,31298,31299,31300,31301,31302,31303, |
| 95242 | 31304,31305,31306,31307,31308,31309,31310,31311,31312,31313,31314,31315, |
| 95243 | 31316,31317,31318,31319,31320,31321,31322,31323,31324,31325,31326,31327, |
| 95244 | 31328,31329,31330,31331,31332,31333,31334,31335,31336,31337,31338,31339, |
| 95245 | 31340,31341,31342,31343,31344,31345,31346,31347,31348,31349,31350,31351, |
| 95246 | 31352,31353,31354,31355,31356,31357,31358,31359,31360,31361,31362,31363, |
| 95247 | 31364,31365,31366,31367,31368,31369,31370,31371,31372,31373,31374,31375, |
| 95248 | 31376,31377,31378,31379,31380,31381,31382,31383,31384,31385,31386,31387, |
| 95249 | 31388,31389,31390,31391,31392,31393,31394,31395,31396,31397,31398,31399, |
| 95250 | 31400,31401,31402,31403,31404,31405,31406,31407,31408,31409,31410,31411, |
| 95251 | 31412,31413,31414,31415,31416,31417,31418,31419,31420,31421,31422,31423, |
| 95252 | 31424,31425,31426,31427,31428,31429,31430,31431,31432,31433,31434,31435, |
| 95253 | 31436,31437,31438,31439,31440,31441,31442,31443,31444,31445,31446,31447, |
| 95254 | 31448,31449,31450,31451,31452,31453,31454,31455,31456,31457,31458,31459, |
| 95255 | 31460,31461,31462,31463,31464,31465,31466,31467,31468,31469,31470,31471, |
| 95256 | 31472,31473,31474,31475,31476,31477,31478,31479,31480,31481,31482,31483, |
| 95257 | 31484,31485,31486,31487,31488,31489,31490,31491,31492,31493,31494,31495, |
| 95258 | 31496,31497,31498,31499,31500,31501,31502,31503,31504,31505,31506,31507, |
| 95259 | 31508,31509,31510,31511,31512,31513,31514,31515,31516,31517,31518,31519, |
| 95260 | 31520,31521,31522,31523,31524,31525,31526,31527,31528,31529,31530,31531, |
| 95261 | 31532,31533,31534,31535,31536,31537,31538,31539,31540,31541,31542,31543, |
| 95262 | 31544,31545,31546,31547,31548,31549,31550,31551,31552,31553,31554,31555, |
| 95263 | 31556,31557,31558,31559,31560,31561,31562,31563,31564,31565,31566,31567, |
| 95264 | 31568,31569,31570,31571,31572,31573,31574,31575,31576,31577,31578,31579, |
| 95265 | 31580,31581,31582,31583,31584,31585,31586,31587,31588,31589,31590,31591, |
| 95266 | 31592,31593,31594,31595,31596,31597,31598,31599,31600,31601,31602,31603, |
| 95267 | 31604,31605,31606,31607,31608,31609,31610,31611,31612,31613,31614,31615, |
| 95268 | 31616,31617,31618,31619,31620,31621,31622,31623,31624,31625,31626,31627, |
| 95269 | 31628,31629,31630,31631,31632,31633,31634,31635,31636,31637,31638,31639, |
| 95270 | 31640,31641,31642,31643,31644,31645,31646,31647,31648,31649,31650,31651, |
| 95271 | 31652,31653,31654,31655,31656,31657,31658,31659,31660,31661,31662,31663, |
| 95272 | 31664,31665,31666,31667,31668,31669,31670,31671,31672,31673,31674,31675, |
| 95273 | 31676,31677,31678,31679,31680,31681,31682,31683,31684,31685,31686,31687, |
| 95274 | 31688,31689,31690,31691,31692,31693,31694,31695,31696,31697,31698,31699, |
| 95275 | 31700,31701,31702,31703,31704,31705,31706,31707,31708,31709,31710,31711, |
| 95276 | 31712,31713,31714,31715,31716,31717,31718,31719,31720,31721,31722,31723, |
| 95277 | 31724,31725,31726,31727,31728,31729,31730,31731,31732,31733,31734,31735, |
| 95278 | 31736,31737,31738,31739,31740,31741,31742,31743,31744,31745,31746,31747, |
| 95279 | 31748,31749,31750,31751,31752,31753,31754,31755,31756,31757,31758,31759, |
| 95280 | 31760,31761,31762,31763,31764,31765,31766,31767,31768,31769,31770,31771, |
| 95281 | 31772,31773,31774,31775,31776,31777,31778,31779,31780,31781,31782,31783, |
| 95282 | 31784,31785,31786,31787,31788,31789,31790,31791,31792,31793,31794,31795, |
| 95283 | 31796,31797,31798,31799,31800,31801,31802,31803,31804,31805,31806,31807, |
| 95284 | 31808,31809,31810,31811,31812,31813,31814,31815,31816,31817,31818,31819, |
| 95285 | 31820,31821,31822,31823,31824,31825,31826,31827,31828,31829,31830,31831, |
| 95286 | 31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843, |
| 95287 | 31844,31845,31846,31847,31848,31849,31850,31851,31852,31853,31854,31855, |
| 95288 | 31856,31857,31858,31859,31860,31861,31862,31863,31864,31865,31866,31867, |
| 95289 | 31868,31869,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879, |
| 95290 | 31880,31881,31882,31883,31884,31885,31886,31887,31888,31889,31890,31891, |
| 95291 | 31892,31893,31894,31895,31896,31897,31898,31899,31900,31901,31902,31903, |
| 95292 | 31904,31905,31906,31907,31908,31909,31910,31911,31912,31913,31914,31915, |
| 95293 | 31916,31917,31918,31919,31920,31921,31922,31923,31924,31925,31926,31927, |
| 95294 | 31928,31929,31930,31931,31932,31933,31934,31935,31936,31937,31938,31939, |
| 95295 | 31940,31941,31942,31943,31944,31945,31946,31947,31948,31949,31950,31951, |
| 95296 | 31952,31953,31954,31955,31956,31957,31958,31959,31960,31961,31962,31963, |
| 95297 | 31964,31965,31966,31967,31968,31969,31970,31971,31972,31973,31974,31975, |
| 95298 | 31976,31977,31978,31979,31980,31981,31982,31983,31984,31985,31986,31987, |
| 95299 | 31988,31989,31990,31991,31992,31993,31994,31995,31996,31997,31998,31999, |
| 95300 | 32000,32001,32002,32003,32004,32005,32006,32007,32008,32009,32010,32011, |
| 95301 | 32012,32013,32014,32015,32016,32017,32018,32019,32020,32021,32022,32023, |
| 95302 | 32024,32025,32026,32027,32028,32029,32030,32031,32032,32033,32034,32035, |
| 95303 | 32036,32037,32038,32039,32040,32041,32042,32043,32044,32045,32046,32047, |
| 95304 | 32048,32049,32050,32051,32052,32053,32054,32055,32056,32057,32058,32059, |
| 95305 | 32060,32061,32062,32063,32064,32065,32066,32067,32068,32069,32070,32071, |
| 95306 | 32072,32073,32074,32075,32076,32077,32078,32079,32080,32081,32082,32083, |
| 95307 | 32084,32085,32086,32087,32088,32089,32090,32091,32092,32093,32094,32095, |
| 95308 | 32096,32097,32098,32099,32100,32101,32102,32103,32104,32105,32106,32107, |
| 95309 | 32108,32109,32110,32111,32112,32113,32114,32115,32116,32117,32118,32119, |
| 95310 | 32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131, |
| 95311 | 32132,32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143, |
| 95312 | 32144,32145,32146,32147,32148,32149,32150,32151,32152,32153,32154,32155, |
| 95313 | 32156,32157,32158,32159,32160,32161,32162,32163,32164,32165,32166,32167, |
| 95314 | 32168,32169,32170,32171,32172,32173,32174,32175,32176,32177,32178,32179, |
| 95315 | 32180,32181,32182,32183,32184,32185,32186,32187,32188,32189,32190,32191, |
| 95316 | 32192,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203, |
| 95317 | 32204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215, |
| 95318 | 32216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32227, |
| 95319 | 32228,32229,32230,32231,32232,32233,32234,32235,32236,32237,32238,32239, |
| 95320 | 32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250,32251, |
| 95321 | 32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263, |
| 95322 | 32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275, |
| 95323 | 32276,32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287, |
| 95324 | 32288,32289,32290,32291,32292,32293,32294,32295,32296,32297,32298,32299, |
| 95325 | 32300,32301,32302,32303,32304,32305,32306,32307,32308,32309,32310,32311, |
| 95326 | 32312,32313,32314,32315,32316,32317,32318,32319,32320,32321,32322,32323, |
| 95327 | 32324,32325,32326,32327,32328,32329,32330,32331,32332,32333,32334,32335, |
| 95328 | 32336,32337,32338,32339,32340,32341,32342,32343,32344,32345,32346,32347, |
| 95329 | 32348,32349,32350,32351,32352,32353,32354,32355,32356,32357,32358,32359, |
| 95330 | 32360,32361,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371, |
| 95331 | 32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383, |
| 95332 | 32384,32385,32386,32387,32388,32389,32390,32391,32392,32393,32394,32395, |
| 95333 | 32396,32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407, |
| 95334 | 32408,32409,32410,32411,32412,32413,32414,32415,32416,32417,32418,32419, |
| 95335 | 32420,32421,32422,32423,32424,32425,32426,32427,32428,32429,32430,32431, |
| 95336 | 32432,32433,32434,32435,32436,32437,32438,32439,32440,32441,32442,32443, |
| 95337 | 32444,32445,32446,32447,32448,32449,32450,32451,32452,32453,32454,32455, |
| 95338 | 32456,32457,32458,32459,32460,32461,32462,32463,32464,32465,32466,32467, |
| 95339 | 32468,32469,32470,32471,32472,32473,32474,32475,32476,32477,32478,32479, |
| 95340 | 32480,32481,32482,32483,32484,32485,32486,32487,32488,32489,32490,32491, |
| 95341 | 32492,32493,32494,32495,32496,32497,32498,32499,32500,32501,32502,32503, |
| 95342 | 32504,32505,32506,32507,32508,32509,32510,32511,32512,32513,32514,32515, |
| 95343 | 32516,32517,32518,32519,32520,32521,32522,32523,32524,32525,32526,32527, |
| 95344 | 32528,32529,32530,32531,32532,32533,32534,32535,32536,32537,32538,32539, |
| 95345 | 32540,32541,32542,32543,32544,32545,32546,32547,32548,32549,32550,32551, |
| 95346 | 32552,32553,32554,32555,32556,32557,32558,32559,32560,32561,32562,32563, |
| 95347 | 32564,32565,32566,32567,32568,32569,32570,32571,32572,32573,32574,32575, |
| 95348 | 32576,32577,32578,32579,32580,32581,32582,32583,32584,32585,32586,32587, |
| 95349 | 32588,32589,32590,32591,32592,32593,32594,32595,32596,32597,32598,32599, |
| 95350 | 32600,32601,32602,32603,32604,32605,32606,32607,32608,32609,32610,32611, |
| 95351 | 32612,32613,32614,32615,32616,32617,32618,32619,32620,32621,32622,32623, |
| 95352 | 32624,32625,32626,32627,32628,32629,32630,32631,32632,32633,32634,32635, |
| 95353 | 32636,32637,32638,32639,32640,32641,32642,32643,32644,32645,32646,32647, |
| 95354 | 32648,32649,32650,32651,32652,32653,32654,32655,32656,32657,32658,32659, |
| 95355 | 32660,32661,32662,32663,32664,32665,32666,32667,32668,32669,32670,32671, |
| 95356 | 32672,32673,32674,32675,32676,32677,32678,32679,32680,32681,32682,32683, |
| 95357 | 32684,32685,32686,32687,32688,32689,32690,32691,32692,32693,32694,32695, |
| 95358 | 32696,32697,32698,32699,32700,32701,32702,32703,32704,32705,32706,32707, |
| 95359 | 32708,32709,32710,32711,32712,32713,32714,32715,32716,32717,32718,32719, |
| 95360 | 32720,32721,32722,32723,32724,32725,32726,32727,32728,32729,32730,32731, |
| 95361 | 32732,32733,32734,32735,32736,32737,32738,32739,32740,32741,32742,32743, |
| 95362 | 32744,32745,32746,32747,32748,32749,32750,32751,32752,32753,32754,32755, |
| 95363 | 32756,32757,32758,32759,32760,32761,32762,32763,32764,32765,32766,32767, |
| 95364 | 32768L,32769L,32770L,32771L,32772L,32773L,32774L,32775L,32776L,32777L, |
| 95365 | 32778L,32779L,32780L,32781L,32782L,32783L,32784L,32785L,32786L,32787L, |
| 95366 | 32788L,32789L,32790L,32791L,32792L,32793L,32794L,32795L,32796L,32797L, |
| 95367 | 32798L,32799L,32800L,32801L,32802L,32803L,32804L,32805L,32806L,32807L, |
| 95368 | 32808L,32809L,32810L,32811L,32812L,32813L,32814L,32815L,32816L,32817L, |
| 95369 | 32818L,32819L,32820L,32821L,32822L,32823L,32824L,32825L,32826L,32827L, |
| 95370 | 32828L,32829L,32830L,32831L,32832L,32833L,32834L,32835L,32836L,32837L, |
| 95371 | 32838L,32839L,32840L,32841L,32842L,32843L,32844L,32845L,32846L,32847L, |
| 95372 | 32848L,32849L,32850L,32851L,32852L,32853L,32854L,32855L,32856L,32857L, |
| 95373 | 32858L,32859L,32860L,32861L,32862L,32863L,32864L,32865L,32866L,32867L, |
| 95374 | 32868L,32869L,32870L,32871L,32872L,32873L,32874L,32875L,32876L,32877L, |
| 95375 | 32878L,32879L,32880L,32881L,32882L,32883L,32884L,32885L,32886L,32887L, |
| 95376 | 32888L,32889L,32890L,32891L,32892L,32893L,32894L,32895L,32896L,32897L, |
| 95377 | 32898L,32899L,32900L,32901L,32902L,32903L,32904L,32905L,32906L,32907L, |
| 95378 | 32908L,32909L,32910L,32911L,32912L,32913L,32914L,32915L,32916L,32917L, |
| 95379 | 32918L,32919L,32920L,32921L,32922L,32923L,32924L,32925L,32926L,32927L, |
| 95380 | 32928L,32929L,32930L,32931L,32932L,32933L,32934L,32935L,32936L,32937L, |
| 95381 | 32938L,32939L,32940L,32941L,32942L,32943L,32944L,32945L,32946L,32947L, |
| 95382 | 32948L,32949L,32950L,32951L,32952L,32953L,32954L,32955L,32956L,32957L, |
| 95383 | 32958L,32959L,32960L,32961L,32962L,32963L,32964L,32965L,32966L,32967L, |
| 95384 | 32968L,32969L,32970L,32971L,32972L,32973L,32974L,32975L,32976L,32977L, |
| 95385 | 32978L,32979L,32980L,32981L,32982L,32983L,32984L,32985L,32986L,32987L, |
| 95386 | 32988L,32989L,32990L,32991L,32992L,32993L,32994L,32995L,32996L,32997L, |
| 95387 | 32998L,32999L,33000L,33001L,33002L,33003L,33004L,33005L,33006L,33007L, |
| 95388 | 33008L,33009L,33010L,33011L,33012L,33013L,33014L,33015L,33016L,33017L, |
| 95389 | 33018L,33019L,33020L,33021L,33022L,33023L,33024L,33025L,33026L,33027L, |
| 95390 | 33028L,33029L,33030L,33031L,33032L,33033L,33034L,33035L,33036L,33037L, |
| 95391 | 33038L,33039L,33040L,33041L,33042L,33043L,33044L,33045L,33046L,33047L, |
| 95392 | 33048L,33049L,33050L,33051L,33052L,33053L,33054L,33055L,33056L,33057L, |
| 95393 | 33058L,33059L,33060L,33061L,33062L,33063L,33064L,33065L,33066L,33067L, |
| 95394 | 33068L,33069L,33070L,33071L,33072L,33073L,33074L,33075L,33076L,33077L, |
| 95395 | 33078L,33079L,33080L,33081L,33082L,33083L,33084L,33085L,33086L,33087L, |
| 95396 | 33088L,33089L,33090L,33091L,33092L,33093L,33094L,33095L,33096L,33097L, |
| 95397 | 33098L,33099L,33100L,33101L,33102L,33103L,33104L,33105L,33106L,33107L, |
| 95398 | 33108L,33109L,33110L,33111L,33112L,33113L,33114L,33115L,33116L,33117L, |
| 95399 | 33118L,33119L,33120L,33121L,33122L,33123L,33124L,33125L,33126L,33127L, |
| 95400 | 33128L,33129L,33130L,33131L,33132L,33133L,33134L,33135L,33136L,33137L, |
| 95401 | 33138L,33139L,33140L,33141L,33142L,33143L,33144L,33145L,33146L,33147L, |
| 95402 | 33148L,33149L,33150L,33151L,33152L,33153L,33154L,33155L,33156L,33157L, |
| 95403 | 33158L,33159L,33160L,33161L,33162L,33163L,33164L,33165L,33166L,33167L, |
| 95404 | 33168L,33169L,33170L,33171L,33172L,33173L,33174L,33175L,33176L,33177L, |
| 95405 | 33178L,33179L,33180L,33181L,33182L,33183L,33184L,33185L,33186L,33187L, |
| 95406 | 33188L,33189L,33190L,33191L,33192L,33193L,33194L,33195L,33196L,33197L, |
| 95407 | 33198L,33199L,33200L,33201L,33202L,33203L,33204L,33205L,33206L,33207L, |
| 95408 | 33208L,33209L,33210L,33211L,33212L,33213L,33214L,33215L,33216L,33217L, |
| 95409 | 33218L,33219L,33220L,33221L,33222L,33223L,33224L,33225L,33226L,33227L, |
| 95410 | 33228L,33229L,33230L,33231L,33232L,33233L,33234L,33235L,33236L,33237L, |
| 95411 | 33238L,33239L,33240L,33241L,33242L,33243L,33244L,33245L,33246L,33247L, |
| 95412 | 33248L,33249L,33250L,33251L,33252L,33253L,33254L,33255L,33256L,33257L, |
| 95413 | 33258L,33259L,33260L,33261L,33262L,33263L,33264L,33265L,33266L,33267L, |
| 95414 | 33268L,33269L,33270L,33271L,33272L,33273L,33274L,33275L,33276L,33277L, |
| 95415 | 33278L,33279L,33280L,33281L,33282L,33283L,33284L,33285L,33286L,33287L, |
| 95416 | 33288L,33289L,33290L,33291L,33292L,33293L,33294L,33295L,33296L,33297L, |
| 95417 | 33298L,33299L,33300L,33301L,33302L,33303L,33304L,33305L,33306L,33307L, |
| 95418 | 33308L,33309L,33310L,33311L,33312L,33313L,33314L,33315L,33316L,33317L, |
| 95419 | 33318L,33319L,33320L,33321L,33322L,33323L,33324L,33325L,33326L,33327L, |
| 95420 | 33328L,33329L,33330L,33331L,33332L,33333L,33334L,33335L,33336L,33337L, |
| 95421 | 33338L,33339L,33340L,33341L,33342L,33343L,33344L,33345L,33346L,33347L, |
| 95422 | 33348L,33349L,33350L,33351L,33352L,33353L,33354L,33355L,33356L,33357L, |
| 95423 | 33358L,33359L,33360L,33361L,33362L,33363L,33364L,33365L,33366L,33367L, |
| 95424 | 33368L,33369L,33370L,33371L,33372L,33373L,33374L,33375L,33376L,33377L, |
| 95425 | 33378L,33379L,33380L,33381L,33382L,33383L,33384L,33385L,33386L,33387L, |
| 95426 | 33388L,33389L,33390L,33391L,33392L,33393L,33394L,33395L,33396L,33397L, |
| 95427 | 33398L,33399L,33400L,33401L,33402L,33403L,33404L,33405L,33406L,33407L, |
| 95428 | 33408L,33409L,33410L,33411L,33412L,33413L,33414L,33415L,33416L,33417L, |
| 95429 | 33418L,33419L,33420L,33421L,33422L,33423L,33424L,33425L,33426L,33427L, |
| 95430 | 33428L,33429L,33430L,33431L,33432L,33433L,33434L,33435L,33436L,33437L, |
| 95431 | 33438L,33439L,33440L,33441L,33442L,33443L,33444L,33445L,33446L,33447L, |
| 95432 | 33448L,33449L,33450L,33451L,33452L,33453L,33454L,33455L,33456L,33457L, |
| 95433 | 33458L,33459L,33460L,33461L,33462L,33463L,33464L,33465L,33466L,33467L, |
| 95434 | 33468L,33469L,33470L,33471L,33472L,33473L,33474L,33475L,33476L,33477L, |
| 95435 | 33478L,33479L,33480L,33481L,33482L,33483L,33484L,33485L,33486L,33487L, |
| 95436 | 33488L,33489L,33490L,33491L,33492L,33493L,33494L,33495L,33496L,33497L, |
| 95437 | 33498L,33499L,33500L,33501L,33502L,33503L,33504L,33505L,33506L,33507L, |
| 95438 | 33508L,33509L,33510L,33511L,33512L,33513L,33514L,33515L,33516L,33517L, |
| 95439 | 33518L,33519L,33520L,33521L,33522L,33523L,33524L,33525L,33526L,33527L, |
| 95440 | 33528L,33529L,33530L,33531L,33532L,33533L,33534L,33535L,33536L,33537L, |
| 95441 | 33538L,33539L,33540L,33541L,33542L,33543L,33544L,33545L,33546L,33547L, |
| 95442 | 33548L,33549L,33550L,33551L,33552L,33553L,33554L,33555L,33556L,33557L, |
| 95443 | 33558L,33559L,33560L,33561L,33562L,33563L,33564L,33565L,33566L,33567L, |
| 95444 | 33568L,33569L,33570L,33571L,33572L,33573L,33574L,33575L,33576L,33577L, |
| 95445 | 33578L,33579L,33580L,33581L,33582L,33583L,33584L,33585L,33586L,33587L, |
| 95446 | 33588L,33589L,33590L,33591L,33592L,33593L,33594L,33595L,33596L,33597L, |
| 95447 | 33598L,33599L,33600L,33601L,33602L,33603L,33604L,33605L,33606L,33607L, |
| 95448 | 33608L,33609L,33610L,33611L,33612L,33613L,33614L,33615L,33616L,33617L, |
| 95449 | 33618L,33619L,33620L,33621L,33622L,33623L,33624L,33625L,33626L,33627L, |
| 95450 | 33628L,33629L,33630L,33631L,33632L,33633L,33634L,33635L,33636L,33637L, |
| 95451 | 33638L,33639L,33640L,33641L,33642L,33643L,33644L,33645L,33646L,33647L, |
| 95452 | 33648L,33649L,33650L,33651L,33652L,33653L,33654L,33655L,33656L,33657L, |
| 95453 | 33658L,33659L,33660L,33661L,33662L,33663L,33664L,33665L,33666L,33667L, |
| 95454 | 33668L,33669L,33670L,33671L,33672L,33673L,33674L,33675L,33676L,33677L, |
| 95455 | 33678L,33679L,33680L,33681L,33682L,33683L,33684L,33685L,33686L,33687L, |
| 95456 | 33688L,33689L,33690L,33691L,33692L,33693L,33694L,33695L,33696L,33697L, |
| 95457 | 33698L,33699L,33700L,33701L,33702L,33703L,33704L,33705L,33706L,33707L, |
| 95458 | 33708L,33709L,33710L,33711L,33712L,33713L,33714L,33715L,33716L,33717L, |
| 95459 | 33718L,33719L,33720L,33721L,33722L,33723L,33724L,33725L,33726L,33727L, |
| 95460 | 33728L,33729L,33730L,33731L,33732L,33733L,33734L,33735L,33736L,33737L, |
| 95461 | 33738L,33739L,33740L,33741L,33742L,33743L,33744L,33745L,33746L,33747L, |
| 95462 | 33748L,33749L,33750L,33751L,33752L,33753L,33754L,33755L,33756L,33757L, |
| 95463 | 33758L,33759L,33760L,33761L,33762L,33763L,33764L,33765L,33766L,33767L, |
| 95464 | 33768L,33769L,33770L,33771L,33772L,33773L,33774L,33775L,33776L,33777L, |
| 95465 | 33778L,33779L,33780L,33781L,33782L,33783L,33784L,33785L,33786L,33787L, |
| 95466 | 33788L,33789L,33790L,33791L,33792L,33793L,33794L,33795L,33796L,33797L, |
| 95467 | 33798L,33799L,33800L,33801L,33802L,33803L,33804L,33805L,33806L,33807L, |
| 95468 | 33808L,33809L,33810L,33811L,33812L,33813L,33814L,33815L,33816L,33817L, |
| 95469 | 33818L,33819L,33820L,33821L,33822L,33823L,33824L,33825L,33826L,33827L, |
| 95470 | 33828L,33829L,33830L,33831L,33832L,33833L,33834L,33835L,33836L,33837L, |
| 95471 | 33838L,33839L,33840L,33841L,33842L,33843L,33844L,33845L,33846L,33847L, |
| 95472 | 33848L,33849L,33850L,33851L,33852L,33853L,33854L,33855L,33856L,33857L, |
| 95473 | 33858L,33859L,33860L,33861L,33862L,33863L,33864L,33865L,33866L,33867L, |
| 95474 | 33868L,33869L,33870L,33871L,33872L,33873L,33874L,33875L,33876L,33877L, |
| 95475 | 33878L,33879L,33880L,33881L,33882L,33883L,33884L,33885L,33886L,33887L, |
| 95476 | 33888L,33889L,33890L,33891L,33892L,33893L,33894L,33895L,33896L,33897L, |
| 95477 | 33898L,33899L,33900L,33901L,33902L,33903L,33904L,33905L,33906L,33907L, |
| 95478 | 33908L,33909L,33910L,33911L,33912L,33913L,33914L,33915L,33916L,33917L, |
| 95479 | 33918L,33919L,33920L,33921L,33922L,33923L,33924L,33925L,33926L,33927L, |
| 95480 | 33928L,33929L,33930L,33931L,33932L,33933L,33934L,33935L,33936L,33937L, |
| 95481 | 33938L,33939L,33940L,33941L,33942L,33943L,33944L,33945L,33946L,33947L, |
| 95482 | 33948L,33949L,33950L,33951L,33952L,33953L,33954L,33955L,33956L,33957L, |
| 95483 | 33958L,33959L,33960L,33961L,33962L,33963L,33964L,33965L,33966L,33967L, |
| 95484 | 33968L,33969L,33970L,33971L,33972L,33973L,33974L,33975L,33976L,33977L, |
| 95485 | 33978L,33979L,33980L,33981L,33982L,33983L,33984L,33985L,33986L,33987L, |
| 95486 | 33988L,33989L,33990L,33991L,33992L,33993L,33994L,33995L,33996L,33997L, |
| 95487 | 33998L,33999L,34000L,34001L,34002L,34003L,34004L,34005L,34006L,34007L, |
| 95488 | 34008L,34009L,34010L,34011L,34012L,34013L,34014L,34015L,34016L,34017L, |
| 95489 | 34018L,34019L,34020L,34021L,34022L,34023L,34024L,34025L,34026L,34027L, |
| 95490 | 34028L,34029L,34030L,34031L,34032L,34033L,34034L,34035L,34036L,34037L, |
| 95491 | 34038L,34039L,34040L,34041L,34042L,34043L,34044L,34045L,34046L,34047L, |
| 95492 | 34048L,34049L,34050L,34051L,34052L,34053L,34054L,34055L,34056L,34057L, |
| 95493 | 34058L,34059L,34060L,34061L,34062L,34063L,34064L,34065L,34066L,34067L, |
| 95494 | 34068L,34069L,34070L,34071L,34072L,34073L,34074L,34075L,34076L,34077L, |
| 95495 | 34078L,34079L,34080L,34081L,34082L,34083L,34084L,34085L,34086L,34087L, |
| 95496 | 34088L,34089L,34090L,34091L,34092L,34093L,34094L,34095L,34096L,34097L, |
| 95497 | 34098L,34099L,34100L,34101L,34102L,34103L,34104L,34105L,34106L,34107L, |
| 95498 | 34108L,34109L,34110L,34111L,34112L,34113L,34114L,34115L,34116L,34117L, |
| 95499 | 34118L,34119L,34120L,34121L,34122L,34123L,34124L,34125L,34126L,34127L, |
| 95500 | 34128L,34129L,34130L,34131L,34132L,34133L,34134L,34135L,34136L,34137L, |
| 95501 | 34138L,34139L,34140L,34141L,34142L,34143L,34144L,34145L,34146L,34147L, |
| 95502 | 34148L,34149L,34150L,34151L,34152L,34153L,34154L,34155L,34156L,34157L, |
| 95503 | 34158L,34159L,34160L,34161L,34162L,34163L,34164L,34165L,34166L,34167L, |
| 95504 | 34168L,34169L,34170L,34171L,34172L,34173L,34174L,34175L,34176L,34177L, |
| 95505 | 34178L,34179L,34180L,34181L,34182L,34183L,34184L,34185L,34186L,34187L, |
| 95506 | 34188L,34189L,34190L,34191L,34192L,34193L,34194L,34195L,34196L,34197L, |
| 95507 | 34198L,34199L,34200L,34201L,34202L,34203L,34204L,34205L,34206L,34207L, |
| 95508 | 34208L,34209L,34210L,34211L,34212L,34213L,34214L,34215L,34216L,34217L, |
| 95509 | 34218L,34219L,34220L,34221L,34222L,34223L,34224L,34225L,34226L,34227L, |
| 95510 | 34228L,34229L,34230L,34231L,34232L,34233L,34234L,34235L,34236L,34237L, |
| 95511 | 34238L,34239L,34240L,34241L,34242L,34243L,34244L,34245L,34246L,34247L, |
| 95512 | 34248L,34249L,34250L,34251L,34252L,34253L,34254L,34255L,34256L,34257L, |
| 95513 | 34258L,34259L,34260L,34261L,34262L,34263L,34264L,34265L,34266L,34267L, |
| 95514 | 34268L,34269L,34270L,34271L,34272L,34273L,34274L,34275L,34276L,34277L, |
| 95515 | 34278L,34279L,34280L,34281L,34282L,34283L,34284L,34285L,34286L,34287L, |
| 95516 | 34288L,34289L,34290L,34291L,34292L,34293L,34294L,34295L,34296L,34297L, |
| 95517 | 34298L,34299L,34300L,34301L,34302L,34303L,34304L,34305L,34306L,34307L, |
| 95518 | 34308L,34309L,34310L,34311L,34312L,34313L,34314L,34315L,34316L,34317L, |
| 95519 | 34318L,34319L,34320L,34321L,34322L,34323L,34324L,34325L,34326L,34327L, |
| 95520 | 34328L,34329L,34330L,34331L,34332L,34333L,34334L,34335L,34336L,34337L, |
| 95521 | 34338L,34339L,34340L,34341L,34342L,34343L,34344L,34345L,34346L,34347L, |
| 95522 | 34348L,34349L,34350L,34351L,34352L,34353L,34354L,34355L,34356L,34357L, |
| 95523 | 34358L,34359L,34360L,34361L,34362L,34363L,34364L,34365L,34366L,34367L, |
| 95524 | 34368L,34369L,34370L,34371L,34372L,34373L,34374L,34375L,34376L,34377L, |
| 95525 | 34378L,34379L,34380L,34381L,34382L,34383L,34384L,34385L,34386L,34387L, |
| 95526 | 34388L,34389L,34390L,34391L,34392L,34393L,34394L,34395L,34396L,34397L, |
| 95527 | 34398L,34399L,34400L,34401L,34402L,34403L,34404L,34405L,34406L,34407L, |
| 95528 | 34408L,34409L,34410L,34411L,34412L,34413L,34414L,34415L,34416L,34417L, |
| 95529 | 34418L,34419L,34420L,34421L,34422L,34423L,34424L,34425L,34426L,34427L, |
| 95530 | 34428L,34429L,34430L,34431L,34432L,34433L,34434L,34435L,34436L,34437L, |
| 95531 | 34438L,34439L,34440L,34441L,34442L,34443L,34444L,34445L,34446L,34447L, |
| 95532 | 34448L,34449L,34450L,34451L,34452L,34453L,34454L,34455L,34456L,34457L, |
| 95533 | 34458L,34459L,34460L,34461L,34462L,34463L,34464L,34465L,34466L,34467L, |
| 95534 | 34468L,34469L,34470L,34471L,34472L,34473L,34474L,34475L,34476L,34477L, |
| 95535 | 34478L,34479L,34480L,34481L,34482L,34483L,34484L,34485L,34486L,34487L, |
| 95536 | 34488L,34489L,34490L,34491L,34492L,34493L,34494L,34495L,34496L,34497L, |
| 95537 | 34498L,34499L,34500L,34501L,34502L,34503L,34504L,34505L,34506L,34507L, |
| 95538 | 34508L,34509L,34510L,34511L,34512L,34513L,34514L,34515L,34516L,34517L, |
| 95539 | 34518L,34519L,34520L,34521L,34522L,34523L,34524L,34525L,34526L,34527L, |
| 95540 | 34528L,34529L,34530L,34531L,34532L,34533L,34534L,34535L,34536L,34537L, |
| 95541 | 34538L,34539L,34540L,34541L,34542L,34543L,34544L,34545L,34546L,34547L, |
| 95542 | 34548L,34549L,34550L,34551L,34552L,34553L,34554L,34555L,34556L,34557L, |
| 95543 | 34558L,34559L,34560L,34561L,34562L,34563L,34564L,34565L,34566L,34567L, |
| 95544 | 34568L,34569L,34570L,34571L,34572L,34573L,34574L,34575L,34576L,34577L, |
| 95545 | 34578L,34579L,34580L,34581L,34582L,34583L,34584L,34585L,34586L,34587L, |
| 95546 | 34588L,34589L,34590L,34591L,34592L,34593L,34594L,34595L,34596L,34597L, |
| 95547 | 34598L,34599L,34600L,34601L,34602L,34603L,34604L,34605L,34606L,34607L, |
| 95548 | 34608L,34609L,34610L,34611L,34612L,34613L,34614L,34615L,34616L,34617L, |
| 95549 | 34618L,34619L,34620L,34621L,34622L,34623L,34624L,34625L,34626L,34627L, |
| 95550 | 34628L,34629L,34630L,34631L,34632L,34633L,34634L,34635L,34636L,34637L, |
| 95551 | 34638L,34639L,34640L,34641L,34642L,34643L,34644L,34645L,34646L,34647L, |
| 95552 | 34648L,34649L,34650L,34651L,34652L,34653L,34654L,34655L,34656L,34657L, |
| 95553 | 34658L,34659L,34660L,34661L,34662L,34663L,34664L,34665L,34666L,34667L, |
| 95554 | 34668L,34669L,34670L,34671L,34672L,34673L,34674L,34675L,34676L,34677L, |
| 95555 | 34678L,34679L,34680L,34681L,34682L,34683L,34684L,34685L,34686L,34687L, |
| 95556 | 34688L,34689L,34690L,34691L,34692L,34693L,34694L,34695L,34696L,34697L, |
| 95557 | 34698L,34699L,34700L,34701L,34702L,34703L,34704L,34705L,34706L,34707L, |
| 95558 | 34708L,34709L,34710L,34711L,34712L,34713L,34714L,34715L,34716L,34717L, |
| 95559 | 34718L,34719L,34720L,34721L,34722L,34723L,34724L,34725L,34726L,34727L, |
| 95560 | 34728L,34729L,34730L,34731L,34732L,34733L,34734L,34735L,34736L,34737L, |
| 95561 | 34738L,34739L,34740L,34741L,34742L,34743L,34744L,34745L,34746L,34747L, |
| 95562 | 34748L,34749L,34750L,34751L,34752L,34753L,34754L,34755L,34756L,34757L, |
| 95563 | 34758L,34759L,34760L,34761L,34762L,34763L,34764L,34765L,34766L,34767L, |
| 95564 | 34768L,34769L,34770L,34771L,34772L,34773L,34774L,34775L,34776L,34777L, |
| 95565 | 34778L,34779L,34780L,34781L,34782L,34783L,34784L,34785L,34786L,34787L, |
| 95566 | 34788L,34789L,34790L,34791L,34792L,34793L,34794L,34795L,34796L,34797L, |
| 95567 | 34798L,34799L,34800L,34801L,34802L,34803L,34804L,34805L,34806L,34807L, |
| 95568 | 34808L,34809L,34810L,34811L,34812L,34813L,34814L,34815L,34816L,34817L, |
| 95569 | 34818L,34819L,34820L,34821L,34822L,34823L,34824L,34825L,34826L,34827L, |
| 95570 | 34828L,34829L,34830L,34831L,34832L,34833L,34834L,34835L,34836L,34837L, |
| 95571 | 34838L,34839L,34840L,34841L,34842L,34843L,34844L,34845L,34846L,34847L, |
| 95572 | 34848L,34849L,34850L,34851L,34852L,34853L,34854L,34855L,34856L,34857L, |
| 95573 | 34858L,34859L,34860L,34861L,34862L,34863L,34864L,34865L,34866L,34867L, |
| 95574 | 34868L,34869L,34870L,34871L,34872L,34873L,34874L,34875L,34876L,34877L, |
| 95575 | 34878L,34879L,34880L,34881L,34882L,34883L,34884L,34885L,34886L,34887L, |
| 95576 | 34888L,34889L,34890L,34891L,34892L,34893L,34894L,34895L,34896L,34897L, |
| 95577 | 34898L,34899L,34900L,34901L,34902L,34903L,34904L,34905L,34906L,34907L, |
| 95578 | 34908L,34909L,34910L,34911L,34912L,34913L,34914L,34915L,34916L,34917L, |
| 95579 | 34918L,34919L,34920L,34921L,34922L,34923L,34924L,34925L,34926L,34927L, |
| 95580 | 34928L,34929L,34930L,34931L,34932L,34933L,34934L,34935L,34936L,34937L, |
| 95581 | 34938L,34939L,34940L,34941L,34942L,34943L,34944L,34945L,34946L,34947L, |
| 95582 | 34948L,34949L,34950L,34951L,34952L,34953L,34954L,34955L,34956L,34957L, |
| 95583 | 34958L,34959L,34960L,34961L,34962L,34963L,34964L,34965L,34966L,34967L, |
| 95584 | 34968L,34969L,34970L,34971L,34972L,34973L,34974L,34975L,34976L,34977L, |
| 95585 | 34978L,34979L,34980L,34981L,34982L,34983L,34984L,34985L,34986L,34987L, |
| 95586 | 34988L,34989L,34990L,34991L,34992L,34993L,34994L,34995L,34996L,34997L, |
| 95587 | 34998L,34999L,35000L,35001L,35002L,35003L,35004L,35005L,35006L,35007L, |
| 95588 | 35008L,35009L,35010L,35011L,35012L,35013L,35014L,35015L,35016L,35017L, |
| 95589 | 35018L,35019L,35020L,35021L,35022L,35023L,35024L,35025L,35026L,35027L, |
| 95590 | 35028L,35029L,35030L,35031L,35032L,35033L,35034L,35035L,35036L,35037L, |
| 95591 | 35038L,35039L,35040L,35041L,35042L,35043L,35044L,35045L,35046L,35047L, |
| 95592 | 35048L,35049L,35050L,35051L,35052L,35053L,35054L,35055L,35056L,35057L, |
| 95593 | 35058L,35059L,35060L,35061L,35062L,35063L,35064L,35065L,35066L,35067L, |
| 95594 | 35068L,35069L,35070L,35071L,35072L,35073L,35074L,35075L,35076L,35077L, |
| 95595 | 35078L,35079L,35080L,35081L,35082L,35083L,35084L,35085L,35086L,35087L, |
| 95596 | 35088L,35089L,35090L,35091L,35092L,35093L,35094L,35095L,35096L,35097L, |
| 95597 | 35098L,35099L,35100L,35101L,35102L,35103L,35104L,35105L,35106L,35107L, |
| 95598 | 35108L,35109L,35110L,35111L,35112L,35113L,35114L,35115L,35116L,35117L, |
| 95599 | 35118L,35119L,35120L,35121L,35122L,35123L,35124L,35125L,35126L,35127L, |
| 95600 | 35128L,35129L,35130L,35131L,35132L,35133L,35134L,35135L,35136L,35137L, |
| 95601 | 35138L,35139L,35140L,35141L,35142L,35143L,35144L,35145L,35146L,35147L, |
| 95602 | 35148L,35149L,35150L,35151L,35152L,35153L,35154L,35155L,35156L,35157L, |
| 95603 | 35158L,35159L,35160L,35161L,35162L,35163L,35164L,35165L,35166L,35167L, |
| 95604 | 35168L,35169L,35170L,35171L,35172L,35173L,35174L,35175L,35176L,35177L, |
| 95605 | 35178L,35179L,35180L,35181L,35182L,35183L,35184L,35185L,35186L,35187L, |
| 95606 | 35188L,35189L,35190L,35191L,35192L,35193L,35194L,35195L,35196L,35197L, |
| 95607 | 35198L,35199L,35200L,35201L,35202L,35203L,35204L,35205L,35206L,35207L, |
| 95608 | 35208L,35209L,35210L,35211L,35212L,35213L,35214L,35215L,35216L,35217L, |
| 95609 | 35218L,35219L,35220L,35221L,35222L,35223L,35224L,35225L,35226L,35227L, |
| 95610 | 35228L,35229L,35230L,35231L,35232L,35233L,35234L,35235L,35236L,35237L, |
| 95611 | 35238L,35239L,35240L,35241L,35242L,35243L,35244L,35245L,35246L,35247L, |
| 95612 | 35248L,35249L,35250L,35251L,35252L,35253L,35254L,35255L,35256L,35257L, |
| 95613 | 35258L,35259L,35260L,35261L,35262L,35263L,35264L,35265L,35266L,35267L, |
| 95614 | 35268L,35269L,35270L,35271L,35272L,35273L,35274L,35275L,35276L,35277L, |
| 95615 | 35278L,35279L,35280L,35281L,35282L,35283L,35284L,35285L,35286L,35287L, |
| 95616 | 35288L,35289L,35290L,35291L,35292L,35293L,35294L,35295L,35296L,35297L, |
| 95617 | 35298L,35299L,35300L,35301L,35302L,35303L,35304L,35305L,35306L,35307L, |
| 95618 | 35308L,35309L,35310L,35311L,35312L,35313L,35314L,35315L,35316L,35317L, |
| 95619 | 35318L,35319L,35320L,35321L,35322L,35323L,35324L,35325L,35326L,35327L, |
| 95620 | 35328L,35329L,35330L,35331L,35332L,35333L,35334L,35335L,35336L,35337L, |
| 95621 | 35338L,35339L,35340L,35341L,35342L,35343L,35344L,35345L,35346L,35347L, |
| 95622 | 35348L,35349L,35350L,35351L,35352L,35353L,35354L,35355L,35356L,35357L, |
| 95623 | 35358L,35359L,35360L,35361L,35362L,35363L,35364L,35365L,35366L,35367L, |
| 95624 | 35368L,35369L,35370L,35371L,35372L,35373L,35374L,35375L,35376L,35377L, |
| 95625 | 35378L,35379L,35380L,35381L,35382L,35383L,35384L,35385L,35386L,35387L, |
| 95626 | 35388L,35389L,35390L,35391L,35392L,35393L,35394L,35395L,35396L,35397L, |
| 95627 | 35398L,35399L,35400L,35401L,35402L,35403L,35404L,35405L,35406L,35407L, |
| 95628 | 35408L,35409L,35410L,35411L,35412L,35413L,35414L,35415L,35416L,35417L, |
| 95629 | 35418L,35419L,35420L,35421L,35422L,35423L,35424L,35425L,35426L,35427L, |
| 95630 | 35428L,35429L,35430L,35431L,35432L,35433L,35434L,35435L,35436L,35437L, |
| 95631 | 35438L,35439L,35440L,35441L,35442L,35443L,35444L,35445L,35446L,35447L, |
| 95632 | 35448L,35449L,35450L,35451L,35452L,35453L,35454L,35455L,35456L,35457L, |
| 95633 | 35458L,35459L,35460L,35461L,35462L,35463L,35464L,35465L,35466L,35467L, |
| 95634 | 35468L,35469L,35470L,35471L,35472L,35473L,35474L,35475L,35476L,35477L, |
| 95635 | 35478L,35479L,35480L,35481L,35482L,35483L,35484L,35485L,35486L,35487L, |
| 95636 | 35488L,35489L,35490L,35491L,35492L,35493L,35494L,35495L,35496L,35497L, |
| 95637 | 35498L,35499L,35500L,35501L,35502L,35503L,35504L,35505L,35506L,35507L, |
| 95638 | 35508L,35509L,35510L,35511L,35512L,35513L,35514L,35515L,35516L,35517L, |
| 95639 | 35518L,35519L,35520L,35521L,35522L,35523L,35524L,35525L,35526L,35527L, |
| 95640 | 35528L,35529L,35530L,35531L,35532L,35533L,35534L,35535L,35536L,35537L, |
| 95641 | 35538L,35539L,35540L,35541L,35542L,35543L,35544L,35545L,35546L,35547L, |
| 95642 | 35548L,35549L,35550L,35551L,35552L,35553L,35554L,35555L,35556L,35557L, |
| 95643 | 35558L,35559L,35560L,35561L,35562L,35563L,35564L,35565L,35566L,35567L, |
| 95644 | 35568L,35569L,35570L,35571L,35572L,35573L,35574L,35575L,35576L,35577L, |
| 95645 | 35578L,35579L,35580L,35581L,35582L,35583L,35584L,35585L,35586L,35587L, |
| 95646 | 35588L,35589L,35590L,35591L,35592L,35593L,35594L,35595L,35596L,35597L, |
| 95647 | 35598L,35599L,35600L,35601L,35602L,35603L,35604L,35605L,35606L,35607L, |
| 95648 | 35608L,35609L,35610L,35611L,35612L,35613L,35614L,35615L,35616L,35617L, |
| 95649 | 35618L,35619L,35620L,35621L,35622L,35623L,35624L,35625L,35626L,35627L, |
| 95650 | 35628L,35629L,35630L,35631L,35632L,35633L,35634L,35635L,35636L,35637L, |
| 95651 | 35638L,35639L,35640L,35641L,35642L,35643L,35644L,35645L,35646L,35647L, |
| 95652 | 35648L,35649L,35650L,35651L,35652L,35653L,35654L,35655L,35656L,35657L, |
| 95653 | 35658L,35659L,35660L,35661L,35662L,35663L,35664L,35665L,35666L,35667L, |
| 95654 | 35668L,35669L,35670L,35671L,35672L,35673L,35674L,35675L,35676L,35677L, |
| 95655 | 35678L,35679L,35680L,35681L,35682L,35683L,35684L,35685L,35686L,35687L, |
| 95656 | 35688L,35689L,35690L,35691L,35692L,35693L,35694L,35695L,35696L,35697L, |
| 95657 | 35698L,35699L,35700L,35701L,35702L,35703L,35704L,35705L,35706L,35707L, |
| 95658 | 35708L,35709L,35710L,35711L,35712L,35713L,35714L,35715L,35716L,35717L, |
| 95659 | 35718L,35719L,35720L,35721L,35722L,35723L,35724L,35725L,35726L,35727L, |
| 95660 | 35728L,35729L,35730L,35731L,35732L,35733L,35734L,35735L,35736L,35737L, |
| 95661 | 35738L,35739L,35740L,35741L,35742L,35743L,35744L,35745L,35746L,35747L, |
| 95662 | 35748L,35749L,35750L,35751L,35752L,35753L,35754L,35755L,35756L,35757L, |
| 95663 | 35758L,35759L,35760L,35761L,35762L,35763L,35764L,35765L,35766L,35767L, |
| 95664 | 35768L,35769L,35770L,35771L,35772L,35773L,35774L,35775L,35776L,35777L, |
| 95665 | 35778L,35779L,35780L,35781L,35782L,35783L,35784L,35785L,35786L,35787L, |
| 95666 | 35788L,35789L,35790L,35791L,35792L,35793L,35794L,35795L,35796L,35797L, |
| 95667 | 35798L,35799L,35800L,35801L,35802L,35803L,35804L,35805L,35806L,35807L, |
| 95668 | 35808L,35809L,35810L,35811L,35812L,35813L,35814L,35815L,35816L,35817L, |
| 95669 | 35818L,35819L,35820L,35821L,35822L,35823L,35824L,35825L,35826L,35827L, |
| 95670 | 35828L,35829L,35830L,35831L,35832L,35833L,35834L,35835L,35836L,35837L, |
| 95671 | 35838L,35839L,35840L,35841L,35842L,35843L,35844L,35845L,35846L,35847L, |
| 95672 | 35848L,35849L,35850L,35851L,35852L,35853L,35854L,35855L,35856L,35857L, |
| 95673 | 35858L,35859L,35860L,35861L,35862L,35863L,35864L,35865L,35866L,35867L, |
| 95674 | 35868L,35869L,35870L,35871L,35872L,35873L,35874L,35875L,35876L,35877L, |
| 95675 | 35878L,35879L,35880L,35881L,35882L,35883L,35884L,35885L,35886L,35887L, |
| 95676 | 35888L,35889L,35890L,35891L,35892L,35893L,35894L,35895L,35896L,35897L, |
| 95677 | 35898L,35899L,35900L,35901L,35902L,35903L,35904L,35905L,35906L,35907L, |
| 95678 | 35908L,35909L,35910L,35911L,35912L,35913L,35914L,35915L,35916L,35917L, |
| 95679 | 35918L,35919L,35920L,35921L,35922L,35923L,35924L,35925L,35926L,35927L, |
| 95680 | 35928L,35929L,35930L,35931L,35932L,35933L,35934L,35935L,35936L,35937L, |
| 95681 | 35938L,35939L,35940L,35941L,35942L,35943L,35944L,35945L,35946L,35947L, |
| 95682 | 35948L,35949L,35950L,35951L,35952L,35953L,35954L,35955L,35956L,35957L, |
| 95683 | 35958L,35959L,35960L,35961L,35962L,35963L,35964L,35965L,35966L,35967L, |
| 95684 | 35968L,35969L,35970L,35971L,35972L,35973L,35974L,35975L,35976L,35977L, |
| 95685 | 35978L,35979L,35980L,35981L,35982L,35983L,35984L,35985L,35986L,35987L, |
| 95686 | 35988L,35989L,35990L,35991L,35992L,35993L,35994L,35995L,35996L,35997L, |
| 95687 | 35998L,35999L,36000L,36001L,36002L,36003L,36004L,36005L,36006L,36007L, |
| 95688 | 36008L,36009L,36010L,36011L,36012L,36013L,36014L,36015L,36016L,36017L, |
| 95689 | 36018L,36019L,36020L,36021L,36022L,36023L,36024L,36025L,36026L,36027L, |
| 95690 | 36028L,36029L,36030L,36031L,36032L,36033L,36034L,36035L,36036L,36037L, |
| 95691 | 36038L,36039L,36040L,36041L,36042L,36043L,36044L,36045L,36046L,36047L, |
| 95692 | 36048L,36049L,36050L,36051L,36052L,36053L,36054L,36055L,36056L,36057L, |
| 95693 | 36058L,36059L,36060L,36061L,36062L,36063L,36064L,36065L,36066L,36067L, |
| 95694 | 36068L,36069L,36070L,36071L,36072L,36073L,36074L,36075L,36076L,36077L, |
| 95695 | 36078L,36079L,36080L,36081L,36082L,36083L,36084L,36085L,36086L,36087L, |
| 95696 | 36088L,36089L,36090L,36091L,36092L,36093L,36094L,36095L,36096L,36097L, |
| 95697 | 36098L,36099L,36100L,36101L,36102L,36103L,36104L,36105L,36106L,36107L, |
| 95698 | 36108L,36109L,36110L,36111L,36112L,36113L,36114L,36115L,36116L,36117L, |
| 95699 | 36118L,36119L,36120L,36121L,36122L,36123L,36124L,36125L,36126L,36127L, |
| 95700 | 36128L,36129L,36130L,36131L,36132L,36133L,36134L,36135L,36136L,36137L, |
| 95701 | 36138L,36139L,36140L,36141L,36142L,36143L,36144L,36145L,36146L,36147L, |
| 95702 | 36148L,36149L,36150L,36151L,36152L,36153L,36154L,36155L,36156L,36157L, |
| 95703 | 36158L,36159L,36160L,36161L,36162L,36163L,36164L,36165L,36166L,36167L, |
| 95704 | 36168L,36169L,36170L,36171L,36172L,36173L,36174L,36175L,36176L,36177L, |
| 95705 | 36178L,36179L,36180L,36181L,36182L,36183L,36184L,36185L,36186L,36187L, |
| 95706 | 36188L,36189L,36190L,36191L,36192L,36193L,36194L,36195L,36196L,36197L, |
| 95707 | 36198L,36199L,36200L,36201L,36202L,36203L,36204L,36205L,36206L,36207L, |
| 95708 | 36208L,36209L,36210L,36211L,36212L,36213L,36214L,36215L,36216L,36217L, |
| 95709 | 36218L,36219L,36220L,36221L,36222L,36223L,36224L,36225L,36226L,36227L, |
| 95710 | 36228L,36229L,36230L,36231L,36232L,36233L,36234L,36235L,36236L,36237L, |
| 95711 | 36238L,36239L,36240L,36241L,36242L,36243L,36244L,36245L,36246L,36247L, |
| 95712 | 36248L,36249L,36250L,36251L,36252L,36253L,36254L,36255L,36256L,36257L, |
| 95713 | 36258L,36259L,36260L,36261L,36262L,36263L,36264L,36265L,36266L,36267L, |
| 95714 | 36268L,36269L,36270L,36271L,36272L,36273L,36274L,36275L,36276L,36277L, |
| 95715 | 36278L,36279L,36280L,36281L,36282L,36283L,36284L,36285L,36286L,36287L, |
| 95716 | 36288L,36289L,36290L,36291L,36292L,36293L,36294L,36295L,36296L,36297L, |
| 95717 | 36298L,36299L,36300L,36301L,36302L,36303L,36304L,36305L,36306L,36307L, |
| 95718 | 36308L,36309L,36310L,36311L,36312L,36313L,36314L,36315L,36316L,36317L, |
| 95719 | 36318L,36319L,36320L,36321L,36322L,36323L,36324L,36325L,36326L,36327L, |
| 95720 | 36328L,36329L,36330L,36331L,36332L,36333L,36334L,36335L,36336L,36337L, |
| 95721 | 36338L,36339L,36340L,36341L,36342L,36343L,36344L,36345L,36346L,36347L, |
| 95722 | 36348L,36349L,36350L,36351L,36352L,36353L,36354L,36355L,36356L,36357L, |
| 95723 | 36358L,36359L,36360L,36361L,36362L,36363L,36364L,36365L,36366L,36367L, |
| 95724 | 36368L,36369L,36370L,36371L,36372L,36373L,36374L,36375L,36376L,36377L, |
| 95725 | 36378L,36379L,36380L,36381L,36382L,36383L,36384L,36385L,36386L,36387L, |
| 95726 | 36388L,36389L,36390L,36391L,36392L,36393L,36394L,36395L,36396L,36397L, |
| 95727 | 36398L,36399L,36400L,36401L,36402L,36403L,36404L,36405L,36406L,36407L, |
| 95728 | 36408L,36409L,36410L,36411L,36412L,36413L,36414L,36415L,36416L,36417L, |
| 95729 | 36418L,36419L,36420L,36421L,36422L,36423L,36424L,36425L,36426L,36427L, |
| 95730 | 36428L,36429L,36430L,36431L,36432L,36433L,36434L,36435L,36436L,36437L, |
| 95731 | 36438L,36439L,36440L,36441L,36442L,36443L,36444L,36445L,36446L,36447L, |
| 95732 | 36448L,36449L,36450L,36451L,36452L,36453L,36454L,36455L,36456L,36457L, |
| 95733 | 36458L,36459L,36460L,36461L,36462L,36463L,36464L,36465L,36466L,36467L, |
| 95734 | 36468L,36469L,36470L,36471L,36472L,36473L,36474L,36475L,36476L,36477L, |
| 95735 | 36478L,36479L,36480L,36481L,36482L,36483L,36484L,36485L,36486L,36487L, |
| 95736 | 36488L,36489L,36490L,36491L,36492L,36493L,36494L,36495L,36496L,36497L, |
| 95737 | 36498L,36499L,36500L,36501L,36502L,36503L,36504L,36505L,36506L,36507L, |
| 95738 | 36508L,36509L,36510L,36511L,36512L,36513L,36514L,36515L,36516L,36517L, |
| 95739 | 36518L,36519L,36520L,36521L,36522L,36523L,36524L,36525L,36526L,36527L, |
| 95740 | 36528L,36529L,36530L,36531L,36532L,36533L,36534L,36535L,36536L,36537L, |
| 95741 | 36538L,36539L,36540L,36541L,36542L,36543L,36544L,36545L,36546L,36547L, |
| 95742 | 36548L,36549L,36550L,36551L,36552L,36553L,36554L,36555L,36556L,36557L, |
| 95743 | 36558L,36559L,36560L,36561L,36562L,36563L,36564L,36565L,36566L,36567L, |
| 95744 | 36568L,36569L,36570L,36571L,36572L,36573L,36574L,36575L,36576L,36577L, |
| 95745 | 36578L,36579L,36580L,36581L,36582L,36583L,36584L,36585L,36586L,36587L, |
| 95746 | 36588L,36589L,36590L,36591L,36592L,36593L,36594L,36595L,36596L,36597L, |
| 95747 | 36598L,36599L,36600L,36601L,36602L,36603L,36604L,36605L,36606L,36607L, |
| 95748 | 36608L,36609L,36610L,36611L,36612L,36613L,36614L,36615L,36616L,36617L, |
| 95749 | 36618L,36619L,36620L,36621L,36622L,36623L,36624L,36625L,36626L,36627L, |
| 95750 | 36628L,36629L,36630L,36631L,36632L,36633L,36634L,36635L,36636L,36637L, |
| 95751 | 36638L,36639L,36640L,36641L,36642L,36643L,36644L,36645L,36646L,36647L, |
| 95752 | 36648L,36649L,36650L,36651L,36652L,36653L,36654L,36655L,36656L,36657L, |
| 95753 | 36658L,36659L,36660L,36661L,36662L,36663L,36664L,36665L,36666L,36667L, |
| 95754 | 36668L,36669L,36670L,36671L,36672L,36673L,36674L,36675L,36676L,36677L, |
| 95755 | 36678L,36679L,36680L,36681L,36682L,36683L,36684L,36685L,36686L,36687L, |
| 95756 | 36688L,36689L,36690L,36691L,36692L,36693L,36694L,36695L,36696L,36697L, |
| 95757 | 36698L,36699L,36700L,36701L,36702L,36703L,36704L,36705L,36706L,36707L, |
| 95758 | 36708L,36709L,36710L,36711L,36712L,36713L,36714L,36715L,36716L,36717L, |
| 95759 | 36718L,36719L,36720L,36721L,36722L,36723L,36724L,36725L,36726L,36727L, |
| 95760 | 36728L,36729L,36730L,36731L,36732L,36733L,36734L,36735L,36736L,36737L, |
| 95761 | 36738L,36739L,36740L,36741L,36742L,36743L,36744L,36745L,36746L,36747L, |
| 95762 | 36748L,36749L,36750L,36751L,36752L,36753L,36754L,36755L,36756L,36757L, |
| 95763 | 36758L,36759L,36760L,36761L,36762L,36763L,36764L,36765L,36766L,36767L, |
| 95764 | 36768L,36769L,36770L,36771L,36772L,36773L,36774L,36775L,36776L,36777L, |
| 95765 | 36778L,36779L,36780L,36781L,36782L,36783L,36784L,36785L,36786L,36787L, |
| 95766 | 36788L,36789L,36790L,36791L,36792L,36793L,36794L,36795L,36796L,36797L, |
| 95767 | 36798L,36799L,36800L,36801L,36802L,36803L,36804L,36805L,36806L,36807L, |
| 95768 | 36808L,36809L,36810L,36811L,36812L,36813L,36814L,36815L,36816L,36817L, |
| 95769 | 36818L,36819L,36820L,36821L,36822L,36823L,36824L,36825L,36826L,36827L, |
| 95770 | 36828L,36829L,36830L,36831L,36832L,36833L,36834L,36835L,36836L,36837L, |
| 95771 | 36838L,36839L,36840L,36841L,36842L,36843L,36844L,36845L,36846L,36847L, |
| 95772 | 36848L,36849L,36850L,36851L,36852L,36853L,36854L,36855L,36856L,36857L, |
| 95773 | 36858L,36859L,36860L,36861L,36862L,36863L,36864L,36865L,36866L,36867L, |
| 95774 | 36868L,36869L,36870L,36871L,36872L,36873L,36874L,36875L,36876L,36877L, |
| 95775 | 36878L,36879L,36880L,36881L,36882L,36883L,36884L,36885L,36886L,36887L, |
| 95776 | 36888L,36889L,36890L,36891L,36892L,36893L,36894L,36895L,36896L,36897L, |
| 95777 | 36898L,36899L,36900L,36901L,36902L,36903L,36904L,36905L,36906L,36907L, |
| 95778 | 36908L,36909L,36910L,36911L,36912L,36913L,36914L,36915L,36916L,36917L, |
| 95779 | 36918L,36919L,36920L,36921L,36922L,36923L,36924L,36925L,36926L,36927L, |
| 95780 | 36928L,36929L,36930L,36931L,36932L,36933L,36934L,36935L,36936L,36937L, |
| 95781 | 36938L,36939L,36940L,36941L,36942L,36943L,36944L,36945L,36946L,36947L, |
| 95782 | 36948L,36949L,36950L,36951L,36952L,36953L,36954L,36955L,36956L,36957L, |
| 95783 | 36958L,36959L,36960L,36961L,36962L,36963L,36964L,36965L,36966L,36967L, |
| 95784 | 36968L,36969L,36970L,36971L,36972L,36973L,36974L,36975L,36976L,36977L, |
| 95785 | 36978L,36979L,36980L,36981L,36982L,36983L,36984L,36985L,36986L,36987L, |
| 95786 | 36988L,36989L,36990L,36991L,36992L,36993L,36994L,36995L,36996L,36997L, |
| 95787 | 36998L,36999L,37000L,37001L,37002L,37003L,37004L,37005L,37006L,37007L, |
| 95788 | 37008L,37009L,37010L,37011L,37012L,37013L,37014L,37015L,37016L,37017L, |
| 95789 | 37018L,37019L,37020L,37021L,37022L,37023L,37024L,37025L,37026L,37027L, |
| 95790 | 37028L,37029L,37030L,37031L,37032L,37033L,37034L,37035L,37036L,37037L, |
| 95791 | 37038L,37039L,37040L,37041L,37042L,37043L,37044L,37045L,37046L,37047L, |
| 95792 | 37048L,37049L,37050L,37051L,37052L,37053L,37054L,37055L,37056L,37057L, |
| 95793 | 37058L,37059L,37060L,37061L,37062L,37063L,37064L,37065L,37066L,37067L, |
| 95794 | 37068L,37069L,37070L,37071L,37072L,37073L,37074L,37075L,37076L,37077L, |
| 95795 | 37078L,37079L,37080L,37081L,37082L,37083L,37084L,37085L,37086L,37087L, |
| 95796 | 37088L,37089L,37090L,37091L,37092L,37093L,37094L,37095L,37096L,37097L, |
| 95797 | 37098L,37099L,37100L,37101L,37102L,37103L,37104L,37105L,37106L,37107L, |
| 95798 | 37108L,37109L,37110L,37111L,37112L,37113L,37114L,37115L,37116L,37117L, |
| 95799 | 37118L,37119L,37120L,37121L,37122L,37123L,37124L,37125L,37126L,37127L, |
| 95800 | 37128L,37129L,37130L,37131L,37132L,37133L,37134L,37135L,37136L,37137L, |
| 95801 | 37138L,37139L,37140L,37141L,37142L,37143L,37144L,37145L,37146L,37147L, |
| 95802 | 37148L,37149L,37150L,37151L,37152L,37153L,37154L,37155L,37156L,37157L, |
| 95803 | 37158L,37159L,37160L,37161L,37162L,37163L,37164L,37165L,37166L,37167L, |
| 95804 | 37168L,37169L,37170L,37171L,37172L,37173L,37174L,37175L,37176L,37177L, |
| 95805 | 37178L,37179L,37180L,37181L,37182L,37183L,37184L,37185L,37186L,37187L, |
| 95806 | 37188L,37189L,37190L,37191L,37192L,37193L,37194L,37195L,37196L,37197L, |
| 95807 | 37198L,37199L,37200L,37201L,37202L,37203L,37204L,37205L,37206L,37207L, |
| 95808 | 37208L,37209L,37210L,37211L,37212L,37213L,37214L,37215L,37216L,37217L, |
| 95809 | 37218L,37219L,37220L,37221L,37222L,37223L,37224L,37225L,37226L,37227L, |
| 95810 | 37228L,37229L,37230L,37231L,37232L,37233L,37234L,37235L,37236L,37237L, |
| 95811 | 37238L,37239L,37240L,37241L,37242L,37243L,37244L,37245L,37246L,37247L, |
| 95812 | 37248L,37249L,37250L,37251L,37252L,37253L,37254L,37255L,37256L,37257L, |
| 95813 | 37258L,37259L,37260L,37261L,37262L,37263L,37264L,37265L,37266L,37267L, |
| 95814 | 37268L,37269L,37270L,37271L,37272L,37273L,37274L,37275L,37276L,37277L, |
| 95815 | 37278L,37279L,37280L,37281L,37282L,37283L,37284L,37285L,37286L,37287L, |
| 95816 | 37288L,37289L,37290L,37291L,37292L,37293L,37294L,37295L,37296L,37297L, |
| 95817 | 37298L,37299L,37300L,37301L,37302L,37303L,37304L,37305L,37306L,37307L, |
| 95818 | 37308L,37309L,37310L,37311L,37312L,37313L,37314L,37315L,37316L,37317L, |
| 95819 | 37318L,37319L,37320L,37321L,37322L,37323L,37324L,37325L,37326L,37327L, |
| 95820 | 37328L,37329L,37330L,37331L,37332L,37333L,37334L,37335L,37336L,37337L, |
| 95821 | 37338L,37339L,37340L,37341L,37342L,37343L,37344L,37345L,37346L,37347L, |
| 95822 | 37348L,37349L,37350L,37351L,37352L,37353L,37354L,37355L,37356L,37357L, |
| 95823 | 37358L,37359L,37360L,37361L,37362L,37363L,37364L,37365L,37366L,37367L, |
| 95824 | 37368L,37369L,37370L,37371L,37372L,37373L,37374L,37375L,37376L,37377L, |
| 95825 | 37378L,37379L,37380L,37381L,37382L,37383L,37384L,37385L,37386L,37387L, |
| 95826 | 37388L,37389L,37390L,37391L,37392L,37393L,37394L,37395L,37396L,37397L, |
| 95827 | 37398L,37399L,37400L,37401L,37402L,37403L,37404L,37405L,37406L,37407L, |
| 95828 | 37408L,37409L,37410L,37411L,37412L,37413L,37414L,37415L,37416L,37417L, |
| 95829 | 37418L,37419L,37420L,37421L,37422L,37423L,37424L,37425L,37426L,37427L, |
| 95830 | 37428L,37429L,37430L,37431L,37432L,37433L,37434L,37435L,37436L,37437L, |
| 95831 | 37438L,37439L,37440L,37441L,37442L,37443L,37444L,37445L,37446L,37447L, |
| 95832 | 37448L,37449L,37450L,37451L,37452L,37453L,37454L,37455L,37456L,37457L, |
| 95833 | 37458L,37459L,37460L,37461L,37462L,37463L,37464L,37465L,37466L,37467L, |
| 95834 | 37468L,37469L,37470L,37471L,37472L,37473L,37474L,37475L,37476L,37477L, |
| 95835 | 37478L,37479L,37480L,37481L,37482L,37483L,37484L,37485L,37486L,37487L, |
| 95836 | 37488L,37489L,37490L,37491L,37492L,37493L,37494L,37495L,37496L,37497L, |
| 95837 | 37498L,37499L,37500L,37501L,37502L,37503L,37504L,37505L,37506L,37507L, |
| 95838 | 37508L,37509L,37510L,37511L,37512L,37513L,37514L,37515L,37516L,37517L, |
| 95839 | 37518L,37519L,37520L,37521L,37522L,37523L,37524L,37525L,37526L,37527L, |
| 95840 | 37528L,37529L,37530L,37531L,37532L,37533L,37534L,37535L,37536L,37537L, |
| 95841 | 37538L,37539L,37540L,37541L,37542L,37543L,37544L,37545L,37546L,37547L, |
| 95842 | 37548L,37549L,37550L,37551L,37552L,37553L,37554L,37555L,37556L,37557L, |
| 95843 | 37558L,37559L,37560L,37561L,37562L,37563L,37564L,37565L,37566L,37567L, |
| 95844 | 37568L,37569L,37570L,37571L,37572L,37573L,37574L,37575L,37576L,37577L, |
| 95845 | 37578L,37579L,37580L,37581L,37582L,37583L,37584L,37585L,37586L,37587L, |
| 95846 | 37588L,37589L,37590L,37591L,37592L,37593L,37594L,37595L,37596L,37597L, |
| 95847 | 37598L,37599L,37600L,37601L,37602L,37603L,37604L,37605L,37606L,37607L, |
| 95848 | 37608L,37609L,37610L,37611L,37612L,37613L,37614L,37615L,37616L,37617L, |
| 95849 | 37618L,37619L,37620L,37621L,37622L,37623L,37624L,37625L,37626L,37627L, |
| 95850 | 37628L,37629L,37630L,37631L,37632L,37633L,37634L,37635L,37636L,37637L, |
| 95851 | 37638L,37639L,37640L,37641L,37642L,37643L,37644L,37645L,37646L,37647L, |
| 95852 | 37648L,37649L,37650L,37651L,37652L,37653L,37654L,37655L,37656L,37657L, |
| 95853 | 37658L,37659L,37660L,37661L,37662L,37663L,37664L,37665L,37666L,37667L, |
| 95854 | 37668L,37669L,37670L,37671L,37672L,37673L,37674L,37675L,37676L,37677L, |
| 95855 | 37678L,37679L,37680L,37681L,37682L,37683L,37684L,37685L,37686L,37687L, |
| 95856 | 37688L,37689L,37690L,37691L,37692L,37693L,37694L,37695L,37696L,37697L, |
| 95857 | 37698L,37699L,37700L,37701L,37702L,37703L,37704L,37705L,37706L,37707L, |
| 95858 | 37708L,37709L,37710L,37711L,37712L,37713L,37714L,37715L,37716L,37717L, |
| 95859 | 37718L,37719L,37720L,37721L,37722L,37723L,37724L,37725L,37726L,37727L, |
| 95860 | 37728L,37729L,37730L,37731L,37732L,37733L,37734L,37735L,37736L,37737L, |
| 95861 | 37738L,37739L,37740L,37741L,37742L,37743L,37744L,37745L,37746L,37747L, |
| 95862 | 37748L,37749L,37750L,37751L,37752L,37753L,37754L,37755L,37756L,37757L, |
| 95863 | 37758L,37759L,37760L,37761L,37762L,37763L,37764L,37765L,37766L,37767L, |
| 95864 | 37768L,37769L,37770L,37771L,37772L,37773L,37774L,37775L,37776L,37777L, |
| 95865 | 37778L,37779L,37780L,37781L,37782L,37783L,37784L,37785L,37786L,37787L, |
| 95866 | 37788L,37789L,37790L,37791L,37792L,37793L,37794L,37795L,37796L,37797L, |
| 95867 | 37798L,37799L,37800L,37801L,37802L,37803L,37804L,37805L,37806L,37807L, |
| 95868 | 37808L,37809L,37810L,37811L,37812L,37813L,37814L,37815L,37816L,37817L, |
| 95869 | 37818L,37819L,37820L,37821L,37822L,37823L,37824L,37825L,37826L,37827L, |
| 95870 | 37828L,37829L,37830L,37831L,37832L,37833L,37834L,37835L,37836L,37837L, |
| 95871 | 37838L,37839L,37840L,37841L,37842L,37843L,37844L,37845L,37846L,37847L, |
| 95872 | 37848L,37849L,37850L,37851L,37852L,37853L,37854L,37855L,37856L,37857L, |
| 95873 | 37858L,37859L,37860L,37861L,37862L,37863L,37864L,37865L,37866L,37867L, |
| 95874 | 37868L,37869L,37870L,37871L,37872L,37873L,37874L,37875L,37876L,37877L, |
| 95875 | 37878L,37879L,37880L,37881L,37882L,37883L,37884L,37885L,37886L,37887L, |
| 95876 | 37888L,37889L,37890L,37891L,37892L,37893L,37894L,37895L,37896L,37897L, |
| 95877 | 37898L,37899L,37900L,37901L,37902L,37903L,37904L,37905L,37906L,37907L, |
| 95878 | 37908L,37909L,37910L,37911L,37912L,37913L,37914L,37915L,37916L,37917L, |
| 95879 | 37918L,37919L,37920L,37921L,37922L,37923L,37924L,37925L,37926L,37927L, |
| 95880 | 37928L,37929L,37930L,37931L,37932L,37933L,37934L,37935L,37936L,37937L, |
| 95881 | 37938L,37939L,37940L,37941L,37942L,37943L,37944L,37945L,37946L,37947L, |
| 95882 | 37948L,37949L,37950L,37951L,37952L,37953L,37954L,37955L,37956L,37957L, |
| 95883 | 37958L,37959L,37960L,37961L,37962L,37963L,37964L,37965L,37966L,37967L, |
| 95884 | 37968L,37969L,37970L,37971L,37972L,37973L,37974L,37975L,37976L,37977L, |
| 95885 | 37978L,37979L,37980L,37981L,37982L,37983L,37984L,37985L,37986L,37987L, |
| 95886 | 37988L,37989L,37990L,37991L,37992L,37993L,37994L,37995L,37996L,37997L, |
| 95887 | 37998L,37999L,38000L,38001L,38002L,38003L,38004L,38005L,38006L,38007L, |
| 95888 | 38008L,38009L,38010L,38011L,38012L,38013L,38014L,38015L,38016L,38017L, |
| 95889 | 38018L,38019L,38020L,38021L,38022L,38023L,38024L,38025L,38026L,38027L, |
| 95890 | 38028L,38029L,38030L,38031L,38032L,38033L,38034L,38035L,38036L,38037L, |
| 95891 | 38038L,38039L,38040L,38041L,38042L,38043L,38044L,38045L,38046L,38047L, |
| 95892 | 38048L,38049L,38050L,38051L,38052L,38053L,38054L,38055L,38056L,38057L, |
| 95893 | 38058L,38059L,38060L,38061L,38062L,38063L,38064L,38065L,38066L,38067L, |
| 95894 | 38068L,38069L,38070L,38071L,38072L,38073L,38074L,38075L,38076L,38077L, |
| 95895 | 38078L,38079L,38080L,38081L,38082L,38083L,38084L,38085L,38086L,38087L, |
| 95896 | 38088L,38089L,38090L,38091L,38092L,38093L,38094L,38095L,38096L,38097L, |
| 95897 | 38098L,38099L,38100L,38101L,38102L,38103L,38104L,38105L,38106L,38107L, |
| 95898 | 38108L,38109L,38110L,38111L,38112L,38113L,38114L,38115L,38116L,38117L, |
| 95899 | 38118L,38119L,38120L,38121L,38122L,38123L,38124L,38125L,38126L,38127L, |
| 95900 | 38128L,38129L,38130L,38131L,38132L,38133L,38134L,38135L,38136L,38137L, |
| 95901 | 38138L,38139L,38140L,38141L,38142L,38143L,38144L,38145L,38146L,38147L, |
| 95902 | 38148L,38149L,38150L,38151L,38152L,38153L,38154L,38155L,38156L,38157L, |
| 95903 | 38158L,38159L,38160L,38161L,38162L,38163L,38164L,38165L,38166L,38167L, |
| 95904 | 38168L,38169L,38170L,38171L,38172L,38173L,38174L,38175L,38176L,38177L, |
| 95905 | 38178L,38179L,38180L,38181L,38182L,38183L,38184L,38185L,38186L,38187L, |
| 95906 | 38188L,38189L,38190L,38191L,38192L,38193L,38194L,38195L,38196L,38197L, |
| 95907 | 38198L,38199L,38200L,38201L,38202L,38203L,38204L,38205L,38206L,38207L, |
| 95908 | 38208L,38209L,38210L,38211L,38212L,38213L,38214L,38215L,38216L,38217L, |
| 95909 | 38218L,38219L,38220L,38221L,38222L,38223L,38224L,38225L,38226L,38227L, |
| 95910 | 38228L,38229L,38230L,38231L,38232L,38233L,38234L,38235L,38236L,38237L, |
| 95911 | 38238L,38239L,38240L,38241L,38242L,38243L,38244L,38245L,38246L,38247L, |
| 95912 | 38248L,38249L,38250L,38251L,38252L,38253L,38254L,38255L,38256L,38257L, |
| 95913 | 38258L,38259L,38260L,38261L,38262L,38263L,38264L,38265L,38266L,38267L, |
| 95914 | 38268L,38269L,38270L,38271L,38272L,38273L,38274L,38275L,38276L,38277L, |
| 95915 | 38278L,38279L,38280L,38281L,38282L,38283L,38284L,38285L,38286L,38287L, |
| 95916 | 38288L,38289L,38290L,38291L,38292L,38293L,38294L,38295L,38296L,38297L, |
| 95917 | 38298L,38299L,38300L,38301L,38302L,38303L,38304L,38305L,38306L,38307L, |
| 95918 | 38308L,38309L,38310L,38311L,38312L,38313L,38314L,38315L,38316L,38317L, |
| 95919 | 38318L,38319L,38320L,38321L,38322L,38323L,38324L,38325L,38326L,38327L, |
| 95920 | 38328L,38329L,38330L,38331L,38332L,38333L,38334L,38335L,38336L,38337L, |
| 95921 | 38338L,38339L,38340L,38341L,38342L,38343L,38344L,38345L,38346L,38347L, |
| 95922 | 38348L,38349L,38350L,38351L,38352L,38353L,38354L,38355L,38356L,38357L, |
| 95923 | 38358L,38359L,38360L,38361L,38362L,38363L,38364L,38365L,38366L,38367L, |
| 95924 | 38368L,38369L,38370L,38371L,38372L,38373L,38374L,38375L,38376L,38377L, |
| 95925 | 38378L,38379L,38380L,38381L,38382L,38383L,38384L,38385L,38386L,38387L, |
| 95926 | 38388L,38389L,38390L,38391L,38392L,38393L,38394L,38395L,38396L,38397L, |
| 95927 | 38398L,38399L,38400L,38401L,38402L,38403L,38404L,38405L,38406L,38407L, |
| 95928 | 38408L,38409L,38410L,38411L,38412L,38413L,38414L,38415L,38416L,38417L, |
| 95929 | 38418L,38419L,38420L,38421L,38422L,38423L,38424L,38425L,38426L,38427L, |
| 95930 | 38428L,38429L,38430L,38431L,38432L,38433L,38434L,38435L,38436L,38437L, |
| 95931 | 38438L,38439L,38440L,38441L,38442L,38443L,38444L,38445L,38446L,38447L, |
| 95932 | 38448L,38449L,38450L,38451L,38452L,38453L,38454L,38455L,38456L,38457L, |
| 95933 | 38458L,38459L,38460L,38461L,38462L,38463L,38464L,38465L,38466L,38467L, |
| 95934 | 38468L,38469L,38470L,38471L,38472L,38473L,38474L,38475L,38476L,38477L, |
| 95935 | 38478L,38479L,38480L,38481L,38482L,38483L,38484L,38485L,38486L,38487L, |
| 95936 | 38488L,38489L,38490L,38491L,38492L,38493L,38494L,38495L,38496L,38497L, |
| 95937 | 38498L,38499L,38500L,38501L,38502L,38503L,38504L,38505L,38506L,38507L, |
| 95938 | 38508L,38509L,38510L,38511L,38512L,38513L,38514L,38515L,38516L,38517L, |
| 95939 | 38518L,38519L,38520L,38521L,38522L,38523L,38524L,38525L,38526L,38527L, |
| 95940 | 38528L,38529L,38530L,38531L,38532L,38533L,38534L,38535L,38536L,38537L, |
| 95941 | 38538L,38539L,38540L,38541L,38542L,38543L,38544L,38545L,38546L,38547L, |
| 95942 | 38548L,38549L,38550L,38551L,38552L,38553L,38554L,38555L,38556L,38557L, |
| 95943 | 38558L,38559L,38560L,38561L,38562L,38563L,38564L,38565L,38566L,38567L, |
| 95944 | 38568L,38569L,38570L,38571L,38572L,38573L,38574L,38575L,38576L,38577L, |
| 95945 | 38578L,38579L,38580L,38581L,38582L,38583L,38584L,38585L,38586L,38587L, |
| 95946 | 38588L,38589L,38590L,38591L,38592L,38593L,38594L,38595L,38596L,38597L, |
| 95947 | 38598L,38599L,38600L,38601L,38602L,38603L,38604L,38605L,38606L,38607L, |
| 95948 | 38608L,38609L,38610L,38611L,38612L,38613L,38614L,38615L,38616L,38617L, |
| 95949 | 38618L,38619L,38620L,38621L,38622L,38623L,38624L,38625L,38626L,38627L, |
| 95950 | 38628L,38629L,38630L,38631L,38632L,38633L,38634L,38635L,38636L,38637L, |
| 95951 | 38638L,38639L,38640L,38641L,38642L,38643L,38644L,38645L,38646L,38647L, |
| 95952 | 38648L,38649L,38650L,38651L,38652L,38653L,38654L,38655L,38656L,38657L, |
| 95953 | 38658L,38659L,38660L,38661L,38662L,38663L,38664L,38665L,38666L,38667L, |
| 95954 | 38668L,38669L,38670L,38671L,38672L,38673L,38674L,38675L,38676L,38677L, |
| 95955 | 38678L,38679L,38680L,38681L,38682L,38683L,38684L,38685L,38686L,38687L, |
| 95956 | 38688L,38689L,38690L,38691L,38692L,38693L,38694L,38695L,38696L,38697L, |
| 95957 | 38698L,38699L,38700L,38701L,38702L,38703L,38704L,38705L,38706L,38707L, |
| 95958 | 38708L,38709L,38710L,38711L,38712L,38713L,38714L,38715L,38716L,38717L, |
| 95959 | 38718L,38719L,38720L,38721L,38722L,38723L,38724L,38725L,38726L,38727L, |
| 95960 | 38728L,38729L,38730L,38731L,38732L,38733L,38734L,38735L,38736L,38737L, |
| 95961 | 38738L,38739L,38740L,38741L,38742L,38743L,38744L,38745L,38746L,38747L, |
| 95962 | 38748L,38749L,38750L,38751L,38752L,38753L,38754L,38755L,38756L,38757L, |
| 95963 | 38758L,38759L,38760L,38761L,38762L,38763L,38764L,38765L,38766L,38767L, |
| 95964 | 38768L,38769L,38770L,38771L,38772L,38773L,38774L,38775L,38776L,38777L, |
| 95965 | 38778L,38779L,38780L,38781L,38782L,38783L,38784L,38785L,38786L,38787L, |
| 95966 | 38788L,38789L,38790L,38791L,38792L,38793L,38794L,38795L,38796L,38797L, |
| 95967 | 38798L,38799L,38800L,38801L,38802L,38803L,38804L,38805L,38806L,38807L, |
| 95968 | 38808L,38809L,38810L,38811L,38812L,38813L,38814L,38815L,38816L,38817L, |
| 95969 | 38818L,38819L,38820L,38821L,38822L,38823L,38824L,38825L,38826L,38827L, |
| 95970 | 38828L,38829L,38830L,38831L,38832L,38833L,38834L,38835L,38836L,38837L, |
| 95971 | 38838L,38839L,38840L,38841L,38842L,38843L,38844L,38845L,38846L,38847L, |
| 95972 | 38848L,38849L,38850L,38851L,38852L,38853L,38854L,38855L,38856L,38857L, |
| 95973 | 38858L,38859L,38860L,38861L,38862L,38863L,38864L,38865L,38866L,38867L, |
| 95974 | 38868L,38869L,38870L,38871L,38872L,38873L,38874L,38875L,38876L,38877L, |
| 95975 | 38878L,38879L,38880L,38881L,38882L,38883L,38884L,38885L,38886L,38887L, |
| 95976 | 38888L,38889L,38890L,38891L,38892L,38893L,38894L,38895L,38896L,38897L, |
| 95977 | 38898L,38899L,38900L,38901L,38902L,38903L,38904L,38905L,38906L,38907L, |
| 95978 | 38908L,38909L,38910L,38911L,38912L,38913L,38914L,38915L,38916L,38917L, |
| 95979 | 38918L,38919L,38920L,38921L,38922L,38923L,38924L,38925L,38926L,38927L, |
| 95980 | 38928L,38929L,38930L,38931L,38932L,38933L,38934L,38935L,38936L,38937L, |
| 95981 | 38938L,38939L,38940L,38941L,38942L,38943L,38944L,38945L,38946L,38947L, |
| 95982 | 38948L,38949L,38950L,38951L,38952L,38953L,38954L,38955L,38956L,38957L, |
| 95983 | 38958L,38959L,38960L,38961L,38962L,38963L,38964L,38965L,38966L,38967L, |
| 95984 | 38968L,38969L,38970L,38971L,38972L,38973L,38974L,38975L,38976L,38977L, |
| 95985 | 38978L,38979L,38980L,38981L,38982L,38983L,38984L,38985L,38986L,38987L, |
| 95986 | 38988L,38989L,38990L,38991L,38992L,38993L,38994L,38995L,38996L,38997L, |
| 95987 | 38998L,38999L,39000L,39001L,39002L,39003L,39004L,39005L,39006L,39007L, |
| 95988 | 39008L,39009L,39010L,39011L,39012L,39013L,39014L,39015L,39016L,39017L, |
| 95989 | 39018L,39019L,39020L,39021L,39022L,39023L,39024L,39025L,39026L,39027L, |
| 95990 | 39028L,39029L,39030L,39031L,39032L,39033L,39034L,39035L,39036L,39037L, |
| 95991 | 39038L,39039L,39040L,39041L,39042L,39043L,39044L,39045L,39046L,39047L, |
| 95992 | 39048L,39049L,39050L,39051L,39052L,39053L,39054L,39055L,39056L,39057L, |
| 95993 | 39058L,39059L,39060L,39061L,39062L,39063L,39064L,39065L,39066L,39067L, |
| 95994 | 39068L,39069L,39070L,39071L,39072L,39073L,39074L,39075L,39076L,39077L, |
| 95995 | 39078L,39079L,39080L,39081L,39082L,39083L,39084L,39085L,39086L,39087L, |
| 95996 | 39088L,39089L,39090L,39091L,39092L,39093L,39094L,39095L,39096L,39097L, |
| 95997 | 39098L,39099L,39100L,39101L,39102L,39103L,39104L,39105L,39106L,39107L, |
| 95998 | 39108L,39109L,39110L,39111L,39112L,39113L,39114L,39115L,39116L,39117L, |
| 95999 | 39118L,39119L,39120L,39121L,39122L,39123L,39124L,39125L,39126L,39127L, |
| 96000 | 39128L,39129L,39130L,39131L,39132L,39133L,39134L,39135L,39136L,39137L, |
| 96001 | 39138L,39139L,39140L,39141L,39142L,39143L,39144L,39145L,39146L,39147L, |
| 96002 | 39148L,39149L,39150L,39151L,39152L,39153L,39154L,39155L,39156L,39157L, |
| 96003 | 39158L,39159L,39160L,39161L,39162L,39163L,39164L,39165L,39166L,39167L, |
| 96004 | 39168L,39169L,39170L,39171L,39172L,39173L,39174L,39175L,39176L,39177L, |
| 96005 | 39178L,39179L,39180L,39181L,39182L,39183L,39184L,39185L,39186L,39187L, |
| 96006 | 39188L,39189L,39190L,39191L,39192L,39193L,39194L,39195L,39196L,39197L, |
| 96007 | 39198L,39199L,39200L,39201L,39202L,39203L,39204L,39205L,39206L,39207L, |
| 96008 | 39208L,39209L,39210L,39211L,39212L,39213L,39214L,39215L,39216L,39217L, |
| 96009 | 39218L,39219L,39220L,39221L,39222L,39223L,39224L,39225L,39226L,39227L, |
| 96010 | 39228L,39229L,39230L,39231L,39232L,39233L,39234L,39235L,39236L,39237L, |
| 96011 | 39238L,39239L,39240L,39241L,39242L,39243L,39244L,39245L,39246L,39247L, |
| 96012 | 39248L,39249L,39250L,39251L,39252L,39253L,39254L,39255L,39256L,39257L, |
| 96013 | 39258L,39259L,39260L,39261L,39262L,39263L,39264L,39265L,39266L,39267L, |
| 96014 | 39268L,39269L,39270L,39271L,39272L,39273L,39274L,39275L,39276L,39277L, |
| 96015 | 39278L,39279L,39280L,39281L,39282L,39283L,39284L,39285L,39286L,39287L, |
| 96016 | 39288L,39289L,39290L,39291L,39292L,39293L,39294L,39295L,39296L,39297L, |
| 96017 | 39298L,39299L,39300L,39301L,39302L,39303L,39304L,39305L,39306L,39307L, |
| 96018 | 39308L,39309L,39310L,39311L,39312L,39313L,39314L,39315L,39316L,39317L, |
| 96019 | 39318L,39319L,39320L,39321L,39322L,39323L,39324L,39325L,39326L,39327L, |
| 96020 | 39328L,39329L,39330L,39331L,39332L,39333L,39334L,39335L,39336L,39337L, |
| 96021 | 39338L,39339L,39340L,39341L,39342L,39343L,39344L,39345L,39346L,39347L, |
| 96022 | 39348L,39349L,39350L,39351L,39352L,39353L,39354L,39355L,39356L,39357L, |
| 96023 | 39358L,39359L,39360L,39361L,39362L,39363L,39364L,39365L,39366L,39367L, |
| 96024 | 39368L,39369L,39370L,39371L,39372L,39373L,39374L,39375L,39376L,39377L, |
| 96025 | 39378L,39379L,39380L,39381L,39382L,39383L,39384L,39385L,39386L,39387L, |
| 96026 | 39388L,39389L,39390L,39391L,39392L,39393L,39394L,39395L,39396L,39397L, |
| 96027 | 39398L,39399L,39400L,39401L,39402L,39403L,39404L,39405L,39406L,39407L, |
| 96028 | 39408L,39409L,39410L,39411L,39412L,39413L,39414L,39415L,39416L,39417L, |
| 96029 | 39418L,39419L,39420L,39421L,39422L,39423L,39424L,39425L,39426L,39427L, |
| 96030 | 39428L,39429L,39430L,39431L,39432L,39433L,39434L,39435L,39436L,39437L, |
| 96031 | 39438L,39439L,39440L,39441L,39442L,39443L,39444L,39445L,39446L,39447L, |
| 96032 | 39448L,39449L,39450L,39451L,39452L,39453L,39454L,39455L,39456L,39457L, |
| 96033 | 39458L,39459L,39460L,39461L,39462L,39463L,39464L,39465L,39466L,39467L, |
| 96034 | 39468L,39469L,39470L,39471L,39472L,39473L,39474L,39475L,39476L,39477L, |
| 96035 | 39478L,39479L,39480L,39481L,39482L,39483L,39484L,39485L,39486L,39487L, |
| 96036 | 39488L,39489L,39490L,39491L,39492L,39493L,39494L,39495L,39496L,39497L, |
| 96037 | 39498L,39499L,39500L,39501L,39502L,39503L,39504L,39505L,39506L,39507L, |
| 96038 | 39508L,39509L,39510L,39511L,39512L,39513L,39514L,39515L,39516L,39517L, |
| 96039 | 39518L,39519L,39520L,39521L,39522L,39523L,39524L,39525L,39526L,39527L, |
| 96040 | 39528L,39529L,39530L,39531L,39532L,39533L,39534L,39535L,39536L,39537L, |
| 96041 | 39538L,39539L,39540L,39541L,39542L,39543L,39544L,39545L,39546L,39547L, |
| 96042 | 39548L,39549L,39550L,39551L,39552L,39553L,39554L,39555L,39556L,39557L, |
| 96043 | 39558L,39559L,39560L,39561L,39562L,39563L,39564L,39565L,39566L,39567L, |
| 96044 | 39568L,39569L,39570L,39571L,39572L,39573L,39574L,39575L,39576L,39577L, |
| 96045 | 39578L,39579L,39580L,39581L,39582L,39583L,39584L,39585L,39586L,39587L, |
| 96046 | 39588L,39589L,39590L,39591L,39592L,39593L,39594L,39595L,39596L,39597L, |
| 96047 | 39598L,39599L,39600L,39601L,39602L,39603L,39604L,39605L,39606L,39607L, |
| 96048 | 39608L,39609L,39610L,39611L,39612L,39613L,39614L,39615L,39616L,39617L, |
| 96049 | 39618L,39619L,39620L,39621L,39622L,39623L,39624L,39625L,39626L,39627L, |
| 96050 | 39628L,39629L,39630L,39631L,39632L,39633L,39634L,39635L,39636L,39637L, |
| 96051 | 39638L,39639L,39640L,39641L,39642L,39643L,39644L,39645L,39646L,39647L, |
| 96052 | 39648L,39649L,39650L,39651L,39652L,39653L,39654L,39655L,39656L,39657L, |
| 96053 | 39658L,39659L,39660L,39661L,39662L,39663L,39664L,39665L,39666L,39667L, |
| 96054 | 39668L,39669L,39670L,39671L,39672L,39673L,39674L,39675L,39676L,39677L, |
| 96055 | 39678L,39679L,39680L,39681L,39682L,39683L,39684L,39685L,39686L,39687L, |
| 96056 | 39688L,39689L,39690L,39691L,39692L,39693L,39694L,39695L,39696L,39697L, |
| 96057 | 39698L,39699L,39700L,39701L,39702L,39703L,39704L,39705L,39706L,39707L, |
| 96058 | 39708L,39709L,39710L,39711L,39712L,39713L,39714L,39715L,39716L,39717L, |
| 96059 | 39718L,39719L,39720L,39721L,39722L,39723L,39724L,39725L,39726L,39727L, |
| 96060 | 39728L,39729L,39730L,39731L,39732L,39733L,39734L,39735L,39736L,39737L, |
| 96061 | 39738L,39739L,39740L,39741L,39742L,39743L,39744L,39745L,39746L,39747L, |
| 96062 | 39748L,39749L,39750L,39751L,39752L,39753L,39754L,39755L,39756L,39757L, |
| 96063 | 39758L,39759L,39760L,39761L,39762L,39763L,39764L,39765L,39766L,39767L, |
| 96064 | 39768L,39769L,39770L,39771L,39772L,39773L,39774L,39775L,39776L,39777L, |
| 96065 | 39778L,39779L,39780L,39781L,39782L,39783L,39784L,39785L,39786L,39787L, |
| 96066 | 39788L,39789L,39790L,39791L,39792L,39793L,39794L,39795L,39796L,39797L, |
| 96067 | 39798L,39799L,39800L,39801L,39802L,39803L,39804L,39805L,39806L,39807L, |
| 96068 | 39808L,39809L,39810L,39811L,39812L,39813L,39814L,39815L,39816L,39817L, |
| 96069 | 39818L,39819L,39820L,39821L,39822L,39823L,39824L,39825L,39826L,39827L, |
| 96070 | 39828L,39829L,39830L,39831L,39832L,39833L,39834L,39835L,39836L,39837L, |
| 96071 | 39838L,39839L,39840L,39841L,39842L,39843L,39844L,39845L,39846L,39847L, |
| 96072 | 39848L,39849L,39850L,39851L,39852L,39853L,39854L,39855L,39856L,39857L, |
| 96073 | 39858L,39859L,39860L,39861L,39862L,39863L,39864L,39865L,39866L,39867L, |
| 96074 | 39868L,39869L,39870L,39871L,39872L,39873L,39874L,39875L,39876L,39877L, |
| 96075 | 39878L,39879L,39880L,39881L,39882L,39883L,39884L,39885L,39886L,39887L, |
| 96076 | 39888L,39889L,39890L,39891L,39892L,39893L,39894L,39895L,39896L,39897L, |
| 96077 | 39898L,39899L,39900L,39901L,39902L,39903L,39904L,39905L,39906L,39907L, |
| 96078 | 39908L,39909L,39910L,39911L,39912L,39913L,39914L,39915L,39916L,39917L, |
| 96079 | 39918L,39919L,39920L,39921L,39922L,39923L,39924L,39925L,39926L,39927L, |
| 96080 | 39928L,39929L,39930L,39931L,39932L,39933L,39934L,39935L,39936L,39937L, |
| 96081 | 39938L,39939L,39940L,39941L,39942L,39943L,39944L,39945L,39946L,39947L, |
| 96082 | 39948L,39949L,39950L,39951L,39952L,39953L,39954L,39955L,39956L,39957L, |
| 96083 | 39958L,39959L,39960L,39961L,39962L,39963L,39964L,39965L,39966L,39967L, |
| 96084 | 39968L,39969L,39970L,39971L,39972L,39973L,39974L,39975L,39976L,39977L, |
| 96085 | 39978L,39979L,39980L,39981L,39982L,39983L,39984L,39985L,39986L,39987L, |
| 96086 | 39988L,39989L,39990L,39991L,39992L,39993L,39994L,39995L,39996L,39997L, |
| 96087 | 39998L,39999L,40000L,40001L,40002L,40003L,40004L,40005L,40006L,40007L, |
| 96088 | 40008L,40009L,40010L,40011L,40012L,40013L,40014L,40015L,40016L,40017L, |
| 96089 | 40018L,40019L,40020L,40021L,40022L,40023L,40024L,40025L,40026L,40027L, |
| 96090 | 40028L,40029L,40030L,40031L,40032L,40033L,40034L,40035L,40036L,40037L, |
| 96091 | 40038L,40039L,40040L,40041L,40042L,40043L,40044L,40045L,40046L,40047L, |
| 96092 | 40048L,40049L,40050L,40051L,40052L,40053L,40054L,40055L,40056L,40057L, |
| 96093 | 40058L,40059L,40060L,40061L,40062L,40063L,40064L,40065L,40066L,40067L, |
| 96094 | 40068L,40069L,40070L,40071L,40072L,40073L,40074L,40075L,40076L,40077L, |
| 96095 | 40078L,40079L,40080L,40081L,40082L,40083L,40084L,40085L,40086L,40087L, |
| 96096 | 40088L,40089L,40090L,40091L,40092L,40093L,40094L,40095L,40096L,40097L, |
| 96097 | 40098L,40099L,40100L,40101L,40102L,40103L,40104L,40105L,40106L,40107L, |
| 96098 | 40108L,40109L,40110L,40111L,40112L,40113L,40114L,40115L,40116L,40117L, |
| 96099 | 40118L,40119L,40120L,40121L,40122L,40123L,40124L,40125L,40126L,40127L, |
| 96100 | 40128L,40129L,40130L,40131L,40132L,40133L,40134L,40135L,40136L,40137L, |
| 96101 | 40138L,40139L,40140L,40141L,40142L,40143L,40144L,40145L,40146L,40147L, |
| 96102 | 40148L,40149L,40150L,40151L,40152L,40153L,40154L,40155L,40156L,40157L, |
| 96103 | 40158L,40159L,40160L,40161L,40162L,40163L,40164L,40165L,40166L,40167L, |
| 96104 | 40168L,40169L,40170L,40171L,40172L,40173L,40174L,40175L,40176L,40177L, |
| 96105 | 40178L,40179L,40180L,40181L,40182L,40183L,40184L,40185L,40186L,40187L, |
| 96106 | 40188L,40189L,40190L,40191L,40192L,40193L,40194L,40195L,40196L,40197L, |
| 96107 | 40198L,40199L,40200L,40201L,40202L,40203L,40204L,40205L,40206L,40207L, |
| 96108 | 40208L,40209L,40210L,40211L,40212L,40213L,40214L,40215L,40216L,40217L, |
| 96109 | 40218L,40219L,40220L,40221L,40222L,40223L,40224L,40225L,40226L,40227L, |
| 96110 | 40228L,40229L,40230L,40231L,40232L,40233L,40234L,40235L,40236L,40237L, |
| 96111 | 40238L,40239L,40240L,40241L,40242L,40243L,40244L,40245L,40246L,40247L, |
| 96112 | 40248L,40249L,40250L,40251L,40252L,40253L,40254L,40255L,40256L,40257L, |
| 96113 | 40258L,40259L,40260L,40261L,40262L,40263L,40264L,40265L,40266L,40267L, |
| 96114 | 40268L,40269L,40270L,40271L,40272L,40273L,40274L,40275L,40276L,40277L, |
| 96115 | 40278L,40279L,40280L,40281L,40282L,40283L,40284L,40285L,40286L,40287L, |
| 96116 | 40288L,40289L,40290L,40291L,40292L,40293L,40294L,40295L,40296L,40297L, |
| 96117 | 40298L,40299L,40300L,40301L,40302L,40303L,40304L,40305L,40306L,40307L, |
| 96118 | 40308L,40309L,40310L,40311L,40312L,40313L,40314L,40315L,40316L,40317L, |
| 96119 | 40318L,40319L,40320L,40321L,40322L,40323L,40324L,40325L,40326L,40327L, |
| 96120 | 40328L,40329L,40330L,40331L,40332L,40333L,40334L,40335L,40336L,40337L, |
| 96121 | 40338L,40339L,40340L,40341L,40342L,40343L,40344L,40345L,40346L,40347L, |
| 96122 | 40348L,40349L,40350L,40351L,40352L,40353L,40354L,40355L,40356L,40357L, |
| 96123 | 40358L,40359L,40360L,40361L,40362L,40363L,40364L,40365L,40366L,40367L, |
| 96124 | 40368L,40369L,40370L,40371L,40372L,40373L,40374L,40375L,40376L,40377L, |
| 96125 | 40378L,40379L,40380L,40381L,40382L,40383L,40384L,40385L,40386L,40387L, |
| 96126 | 40388L,40389L,40390L,40391L,40392L,40393L,40394L,40395L,40396L,40397L, |
| 96127 | 40398L,40399L,40400L,40401L,40402L,40403L,40404L,40405L,40406L,40407L, |
| 96128 | 40408L,40409L,40410L,40411L,40412L,40413L,40414L,40415L,40416L,40417L, |
| 96129 | 40418L,40419L,40420L,40421L,40422L,40423L,40424L,40425L,40426L,40427L, |
| 96130 | 40428L,40429L,40430L,40431L,40432L,40433L,40434L,40435L,40436L,40437L, |
| 96131 | 40438L,40439L,40440L,40441L,40442L,40443L,40444L,40445L,40446L,40447L, |
| 96132 | 40448L,40449L,40450L,40451L,40452L,40453L,40454L,40455L,40456L,40457L, |
| 96133 | 40458L,40459L,40460L,40461L,40462L,40463L,40464L,40465L,40466L,40467L, |
| 96134 | 40468L,40469L,40470L,40471L,40472L,40473L,40474L,40475L,40476L,40477L, |
| 96135 | 40478L,40479L,40480L,40481L,40482L,40483L,40484L,40485L,40486L,40487L, |
| 96136 | 40488L,40489L,40490L,40491L,40492L,40493L,40494L,40495L,40496L,40497L, |
| 96137 | 40498L,40499L,40500L,40501L,40502L,40503L,40504L,40505L,40506L,40507L, |
| 96138 | 40508L,40509L,40510L,40511L,40512L,40513L,40514L,40515L,40516L,40517L, |
| 96139 | 40518L,40519L,40520L,40521L,40522L,40523L,40524L,40525L,40526L,40527L, |
| 96140 | 40528L,40529L,40530L,40531L,40532L,40533L,40534L,40535L,40536L,40537L, |
| 96141 | 40538L,40539L,40540L,40541L,40542L,40543L,40544L,40545L,40546L,40547L, |
| 96142 | 40548L,40549L,40550L,40551L,40552L,40553L,40554L,40555L,40556L,40557L, |
| 96143 | 40558L,40559L,40560L,40561L,40562L,40563L,40564L,40565L,40566L,40567L, |
| 96144 | 40568L,40569L,40570L,40571L,40572L,40573L,40574L,40575L,40576L,40577L, |
| 96145 | 40578L,40579L,40580L,40581L,40582L,40583L,40584L,40585L,40586L,40587L, |
| 96146 | 40588L,40589L,40590L,40591L,40592L,40593L,40594L,40595L,40596L,40597L, |
| 96147 | 40598L,40599L,40600L,40601L,40602L,40603L,40604L,40605L,40606L,40607L, |
| 96148 | 40608L,40609L,40610L,40611L,40612L,40613L,40614L,40615L,40616L,40617L, |
| 96149 | 40618L,40619L,40620L,40621L,40622L,40623L,40624L,40625L,40626L,40627L, |
| 96150 | 40628L,40629L,40630L,40631L,40632L,40633L,40634L,40635L,40636L,40637L, |
| 96151 | 40638L,40639L,40640L,40641L,40642L,40643L,40644L,40645L,40646L,40647L, |
| 96152 | 40648L,40649L,40650L,40651L,40652L,40653L,40654L,40655L,40656L,40657L, |
| 96153 | 40658L,40659L,40660L,40661L,40662L,40663L,40664L,40665L,40666L,40667L, |
| 96154 | 40668L,40669L,40670L,40671L,40672L,40673L,40674L,40675L,40676L,40677L, |
| 96155 | 40678L,40679L,40680L,40681L,40682L,40683L,40684L,40685L,40686L,40687L, |
| 96156 | 40688L,40689L,40690L,40691L,40692L,40693L,40694L,40695L,40696L,40697L, |
| 96157 | 40698L,40699L,40700L,40701L,40702L,40703L,40704L,40705L,40706L,40707L, |
| 96158 | 40708L,40709L,40710L,40711L,40712L,40713L,40714L,40715L,40716L,40717L, |
| 96159 | 40718L,40719L,40720L,40721L,40722L,40723L,40724L,40725L,40726L,40727L, |
| 96160 | 40728L,40729L,40730L,40731L,40732L,40733L,40734L,40735L,40736L,40737L, |
| 96161 | 40738L,40739L,40740L,40741L,40742L,40743L,40744L,40745L,40746L,40747L, |
| 96162 | 40748L,40749L,40750L,40751L,40752L,40753L,40754L,40755L,40756L,40757L, |
| 96163 | 40758L,40759L,40760L,40761L,40762L,40763L,40764L,40765L,40766L,40767L, |
| 96164 | 40768L,40769L,40770L,40771L,40772L,40773L,40774L,40775L,40776L,40777L, |
| 96165 | 40778L,40779L,40780L,40781L,40782L,40783L,40784L,40785L,40786L,40787L, |
| 96166 | 40788L,40789L,40790L,40791L,40792L,40793L,40794L,40795L,40796L,40797L, |
| 96167 | 40798L,40799L,40800L,40801L,40802L,40803L,40804L,40805L,40806L,40807L, |
| 96168 | 40808L,40809L,40810L,40811L,40812L,40813L,40814L,40815L,40816L,40817L, |
| 96169 | 40818L,40819L,40820L,40821L,40822L,40823L,40824L,40825L,40826L,40827L, |
| 96170 | 40828L,40829L,40830L,40831L,40832L,40833L,40834L,40835L,40836L,40837L, |
| 96171 | 40838L,40839L,40840L,40841L,40842L,40843L,40844L,40845L,40846L,40847L, |
| 96172 | 40848L,40849L,40850L,40851L,40852L,40853L,40854L,40855L,40856L,40857L, |
| 96173 | 40858L,40859L,40860L,40861L,40862L,40863L,40864L,40865L,40866L,40867L, |
| 96174 | 40868L,40869L,40870L,40871L,40872L,40873L,40874L,40875L,40876L,40877L, |
| 96175 | 40878L,40879L,40880L,40881L,40882L,40883L,40884L,40885L,40886L,40887L, |
| 96176 | 40888L,40889L,40890L,40891L,40892L,40893L,40894L,40895L,40896L,40897L, |
| 96177 | 40898L,40899L,40900L,40901L,40902L,40903L,40904L,40905L,40906L,40907L, |
| 96178 | 40908L,40909L,40910L,40911L,40912L,40913L,40914L,40915L,40916L,40917L, |
| 96179 | 40918L,40919L,40920L,40921L,40922L,40923L,40924L,40925L,40926L,40927L, |
| 96180 | 40928L,40929L,40930L,40931L,40932L,40933L,40934L,40935L,40936L,40937L, |
| 96181 | 40938L,40939L,40940L,40941L,40942L,40943L,40944L,40945L,40946L,40947L, |
| 96182 | 40948L,40949L,40950L,40951L,40952L,40953L,40954L,40955L,40956L,40957L, |
| 96183 | 40958L,40959L,40960L,40961L,40962L,40963L,40964L,40965L,40966L,40967L, |
| 96184 | 40968L,40969L,40970L,40971L,40972L,40973L,40974L,40975L,40976L,40977L, |
| 96185 | 40978L,40979L,40980L,40981L,40982L,40983L,40984L,40985L,40986L,40987L, |
| 96186 | 40988L,40989L,40990L,40991L,40992L,40993L,40994L,40995L,40996L,40997L, |
| 96187 | 40998L,40999L,41000L,41001L,41002L,41003L,41004L,41005L,41006L,41007L, |
| 96188 | 41008L,41009L,41010L,41011L,41012L,41013L,41014L,41015L,41016L,41017L, |
| 96189 | 41018L,41019L,41020L,41021L,41022L,41023L,41024L,41025L,41026L,41027L, |
| 96190 | 41028L,41029L,41030L,41031L,41032L,41033L,41034L,41035L,41036L,41037L, |
| 96191 | 41038L,41039L,41040L,41041L,41042L,41043L,41044L,41045L,41046L,41047L, |
| 96192 | 41048L,41049L,41050L,41051L,41052L,41053L,41054L,41055L,41056L,41057L, |
| 96193 | 41058L,41059L,41060L,41061L,41062L,41063L,41064L,41065L,41066L,41067L, |
| 96194 | 41068L,41069L,41070L,41071L,41072L,41073L,41074L,41075L,41076L,41077L, |
| 96195 | 41078L,41079L,41080L,41081L,41082L,41083L,41084L,41085L,41086L,41087L, |
| 96196 | 41088L,41089L,41090L,41091L,41092L,41093L,41094L,41095L,41096L,41097L, |
| 96197 | 41098L,41099L,41100L,41101L,41102L,41103L,41104L,41105L,41106L,41107L, |
| 96198 | 41108L,41109L,41110L,41111L,41112L,41113L,41114L,41115L,41116L,41117L, |
| 96199 | 41118L,41119L,41120L,41121L,41122L,41123L,41124L,41125L,41126L,41127L, |
| 96200 | 41128L,41129L,41130L,41131L,41132L,41133L,41134L,41135L,41136L,41137L, |
| 96201 | 41138L,41139L,41140L,41141L,41142L,41143L,41144L,41145L,41146L,41147L, |
| 96202 | 41148L,41149L,41150L,41151L,41152L,41153L,41154L,41155L,41156L,41157L, |
| 96203 | 41158L,41159L,41160L,41161L,41162L,41163L,41164L,41165L,41166L,41167L, |
| 96204 | 41168L,41169L,41170L,41171L,41172L,41173L,41174L,41175L,41176L,41177L, |
| 96205 | 41178L,41179L,41180L,41181L,41182L,41183L,41184L,41185L,41186L,41187L, |
| 96206 | 41188L,41189L,41190L,41191L,41192L,41193L,41194L,41195L,41196L,41197L, |
| 96207 | 41198L,41199L,41200L,41201L,41202L,41203L,41204L,41205L,41206L,41207L, |
| 96208 | 41208L,41209L,41210L,41211L,41212L,41213L,41214L,41215L,41216L,41217L, |
| 96209 | 41218L,41219L,41220L,41221L,41222L,41223L,41224L,41225L,41226L,41227L, |
| 96210 | 41228L,41229L,41230L,41231L,41232L,41233L,41234L,41235L,41236L,41237L, |
| 96211 | 41238L,41239L,41240L,41241L,41242L,41243L,41244L,41245L,41246L,41247L, |
| 96212 | 41248L,41249L,41250L,41251L,41252L,41253L,41254L,41255L,41256L,41257L, |
| 96213 | 41258L,41259L,41260L,41261L,41262L,41263L,41264L,41265L,41266L,41267L, |
| 96214 | 41268L,41269L,41270L,41271L,41272L,41273L,41274L,41275L,41276L,41277L, |
| 96215 | 41278L,41279L,41280L,41281L,41282L,41283L,41284L,41285L,41286L,41287L, |
| 96216 | 41288L,41289L,41290L,41291L,41292L,41293L,41294L,41295L,41296L,41297L, |
| 96217 | 41298L,41299L,41300L,41301L,41302L,41303L,41304L,41305L,41306L,41307L, |
| 96218 | 41308L,41309L,41310L,41311L,41312L,41313L,41314L,41315L,41316L,41317L, |
| 96219 | 41318L,41319L,41320L,41321L,41322L,41323L,41324L,41325L,41326L,41327L, |
| 96220 | 41328L,41329L,41330L,41331L,41332L,41333L,41334L,41335L,41336L,41337L, |
| 96221 | 41338L,41339L,41340L,41341L,41342L,41343L,41344L,41345L,41346L,41347L, |
| 96222 | 41348L,41349L,41350L,41351L,41352L,41353L,41354L,41355L,41356L,41357L, |
| 96223 | 41358L,41359L,41360L,41361L,41362L,41363L,41364L,41365L,41366L,41367L, |
| 96224 | 41368L,41369L,41370L,41371L,41372L,41373L,41374L,41375L,41376L,41377L, |
| 96225 | 41378L,41379L,41380L,41381L,41382L,41383L,41384L,41385L,41386L,41387L, |
| 96226 | 41388L,41389L,41390L,41391L,41392L,41393L,41394L,41395L,41396L,41397L, |
| 96227 | 41398L,41399L,41400L,41401L,41402L,41403L,41404L,41405L,41406L,41407L, |
| 96228 | 41408L,41409L,41410L,41411L,41412L,41413L,41414L,41415L,41416L,41417L, |
| 96229 | 41418L,41419L,41420L,41421L,41422L,41423L,41424L,41425L,41426L,41427L, |
| 96230 | 41428L,41429L,41430L,41431L,41432L,41433L,41434L,41435L,41436L,41437L, |
| 96231 | 41438L,41439L,41440L,41441L,41442L,41443L,41444L,41445L,41446L,41447L, |
| 96232 | 41448L,41449L,41450L,41451L,41452L,41453L,41454L,41455L,41456L,41457L, |
| 96233 | 41458L,41459L,41460L,41461L,41462L,41463L,41464L,41465L,41466L,41467L, |
| 96234 | 41468L,41469L,41470L,41471L,41472L,41473L,41474L,41475L,41476L,41477L, |
| 96235 | 41478L,41479L,41480L,41481L,41482L,41483L,41484L,41485L,41486L,41487L, |
| 96236 | 41488L,41489L,41490L,41491L,41492L,41493L,41494L,41495L,41496L,41497L, |
| 96237 | 41498L,41499L,41500L,41501L,41502L,41503L,41504L,41505L,41506L,41507L, |
| 96238 | 41508L,41509L,41510L,41511L,41512L,41513L,41514L,41515L,41516L,41517L, |
| 96239 | 41518L,41519L,41520L,41521L,41522L,41523L,41524L,41525L,41526L,41527L, |
| 96240 | 41528L,41529L,41530L,41531L,41532L,41533L,41534L,41535L,41536L,41537L, |
| 96241 | 41538L,41539L,41540L,41541L,41542L,41543L,41544L,41545L,41546L,41547L, |
| 96242 | 41548L,41549L,41550L,41551L,41552L,41553L,41554L,41555L,41556L,41557L, |
| 96243 | 41558L,41559L,41560L,41561L,41562L,41563L,41564L,41565L,41566L,41567L, |
| 96244 | 41568L,41569L,41570L,41571L,41572L,41573L,41574L,41575L,41576L,41577L, |
| 96245 | 41578L,41579L,41580L,41581L,41582L,41583L,41584L,41585L,41586L,41587L, |
| 96246 | 41588L,41589L,41590L,41591L,41592L,41593L,41594L,41595L,41596L,41597L, |
| 96247 | 41598L,41599L,41600L,41601L,41602L,41603L,41604L,41605L,41606L,41607L, |
| 96248 | 41608L,41609L,41610L,41611L,41612L,41613L,41614L,41615L,41616L,41617L, |
| 96249 | 41618L,41619L,41620L,41621L,41622L,41623L,41624L,41625L,41626L,41627L, |
| 96250 | 41628L,41629L,41630L,41631L,41632L,41633L,41634L,41635L,41636L,41637L, |
| 96251 | 41638L,41639L,41640L,41641L,41642L,41643L,41644L,41645L,41646L,41647L, |
| 96252 | 41648L,41649L,41650L,41651L,41652L,41653L,41654L,41655L,41656L,41657L, |
| 96253 | 41658L,41659L,41660L,41661L,41662L,41663L,41664L,41665L,41666L,41667L, |
| 96254 | 41668L,41669L,41670L,41671L,41672L,41673L,41674L,41675L,41676L,41677L, |
| 96255 | 41678L,41679L,41680L,41681L,41682L,41683L,41684L,41685L,41686L,41687L, |
| 96256 | 41688L,41689L,41690L,41691L,41692L,41693L,41694L,41695L,41696L,41697L, |
| 96257 | 41698L,41699L,41700L,41701L,41702L,41703L,41704L,41705L,41706L,41707L, |
| 96258 | 41708L,41709L,41710L,41711L,41712L,41713L,41714L,41715L,41716L,41717L, |
| 96259 | 41718L,41719L,41720L,41721L,41722L,41723L,41724L,41725L,41726L,41727L, |
| 96260 | 41728L,41729L,41730L,41731L,41732L,41733L,41734L,41735L,41736L,41737L, |
| 96261 | 41738L,41739L,41740L,41741L,41742L,41743L,41744L,41745L,41746L,41747L, |
| 96262 | 41748L,41749L,41750L,41751L,41752L,41753L,41754L,41755L,41756L,41757L, |
| 96263 | 41758L,41759L,41760L,41761L,41762L,41763L,41764L,41765L,41766L,41767L, |
| 96264 | 41768L,41769L,41770L,41771L,41772L,41773L,41774L,41775L,41776L,41777L, |
| 96265 | 41778L,41779L,41780L,41781L,41782L,41783L,41784L,41785L,41786L,41787L, |
| 96266 | 41788L,41789L,41790L,41791L,41792L,41793L,41794L,41795L,41796L,41797L, |
| 96267 | 41798L,41799L,41800L,41801L,41802L,41803L,41804L,41805L,41806L,41807L, |
| 96268 | 41808L,41809L,41810L,41811L,41812L,41813L,41814L,41815L,41816L,41817L, |
| 96269 | 41818L,41819L,41820L,41821L,41822L,41823L,41824L,41825L,41826L,41827L, |
| 96270 | 41828L,41829L,41830L,41831L,41832L,41833L,41834L,41835L,41836L,41837L, |
| 96271 | 41838L,41839L,41840L,41841L,41842L,41843L,41844L,41845L,41846L,41847L, |
| 96272 | 41848L,41849L,41850L,41851L,41852L,41853L,41854L,41855L,41856L,41857L, |
| 96273 | 41858L,41859L,41860L,41861L,41862L,41863L,41864L,41865L,41866L,41867L, |
| 96274 | 41868L,41869L,41870L,41871L,41872L,41873L,41874L,41875L,41876L,41877L, |
| 96275 | 41878L,41879L,41880L,41881L,41882L,41883L,41884L,41885L,41886L,41887L, |
| 96276 | 41888L,41889L,41890L,41891L,41892L,41893L,41894L,41895L,41896L,41897L, |
| 96277 | 41898L,41899L,41900L,41901L,41902L,41903L,41904L,41905L,41906L,41907L, |
| 96278 | 41908L,41909L,41910L,41911L,41912L,41913L,41914L,41915L,41916L,41917L, |
| 96279 | 41918L,41919L,41920L,41921L,41922L,41923L,41924L,41925L,41926L,41927L, |
| 96280 | 41928L,41929L,41930L,41931L,41932L,41933L,41934L,41935L,41936L,41937L, |
| 96281 | 41938L,41939L,41940L,41941L,41942L,41943L,41944L,41945L,41946L,41947L, |
| 96282 | 41948L,41949L,41950L,41951L,41952L,41953L,41954L,41955L,41956L,41957L, |
| 96283 | 41958L,41959L,41960L,41961L,41962L,41963L,41964L,41965L,41966L,41967L, |
| 96284 | 41968L,41969L,41970L,41971L,41972L,41973L,41974L,41975L,41976L,41977L, |
| 96285 | 41978L,41979L,41980L,41981L,41982L,41983L,41984L,41985L,41986L,41987L, |
| 96286 | 41988L,41989L,41990L,41991L,41992L,41993L,41994L,41995L,41996L,41997L, |
| 96287 | 41998L,41999L,42000L,42001L,42002L,42003L,42004L,42005L,42006L,42007L, |
| 96288 | 42008L,42009L,42010L,42011L,42012L,42013L,42014L,42015L,42016L,42017L, |
| 96289 | 42018L,42019L,42020L,42021L,42022L,42023L,42024L,42025L,42026L,42027L, |
| 96290 | 42028L,42029L,42030L,42031L,42032L,42033L,42034L,42035L,42036L,42037L, |
| 96291 | 42038L,42039L,42040L,42041L,42042L,42043L,42044L,42045L,42046L,42047L, |
| 96292 | 42048L,42049L,42050L,42051L,42052L,42053L,42054L,42055L,42056L,42057L, |
| 96293 | 42058L,42059L,42060L,42061L,42062L,42063L,42064L,42065L,42066L,42067L, |
| 96294 | 42068L,42069L,42070L,42071L,42072L,42073L,42074L,42075L,42076L,42077L, |
| 96295 | 42078L,42079L,42080L,42081L,42082L,42083L,42084L,42085L,42086L,42087L, |
| 96296 | 42088L,42089L,42090L,42091L,42092L,42093L,42094L,42095L,42096L,42097L, |
| 96297 | 42098L,42099L,42100L,42101L,42102L,42103L,42104L,42105L,42106L,42107L, |
| 96298 | 42108L,42109L,42110L,42111L,42112L,42113L,42114L,42115L,42116L,42117L, |
| 96299 | 42118L,42119L,42120L,42121L,42122L,42123L,42124L,42125L,42126L,42127L, |
| 96300 | 42128L,42129L,42130L,42131L,42132L,42133L,42134L,42135L,42136L,42137L, |
| 96301 | 42138L,42139L,42140L,42141L,42142L,42143L,42144L,42145L,42146L,42147L, |
| 96302 | 42148L,42149L,42150L,42151L,42152L,42153L,42154L,42155L,42156L,42157L, |
| 96303 | 42158L,42159L,42160L,42161L,42162L,42163L,42164L,42165L,42166L,42167L, |
| 96304 | 42168L,42169L,42170L,42171L,42172L,42173L,42174L,42175L,42176L,42177L, |
| 96305 | 42178L,42179L,42180L,42181L,42182L,42183L,42184L,42185L,42186L,42187L, |
| 96306 | 42188L,42189L,42190L,42191L,42192L,42193L,42194L,42195L,42196L,42197L, |
| 96307 | 42198L,42199L,42200L,42201L,42202L,42203L,42204L,42205L,42206L,42207L, |
| 96308 | 42208L,42209L,42210L,42211L,42212L,42213L,42214L,42215L,42216L,42217L, |
| 96309 | 42218L,42219L,42220L,42221L,42222L,42223L,42224L,42225L,42226L,42227L, |
| 96310 | 42228L,42229L,42230L,42231L,42232L,42233L,42234L,42235L,42236L,42237L, |
| 96311 | 42238L,42239L,42240L,42241L,42242L,42243L,42244L,42245L,42246L,42247L, |
| 96312 | 42248L,42249L,42250L,42251L,42252L,42253L,42254L,42255L,42256L,42257L, |
| 96313 | 42258L,42259L,42260L,42261L,42262L,42263L,42264L,42265L,42266L,42267L, |
| 96314 | 42268L,42269L,42270L,42271L,42272L,42273L,42274L,42275L,42276L,42277L, |
| 96315 | 42278L,42279L,42280L,42281L,42282L,42283L,42284L,42285L,42286L,42287L, |
| 96316 | 42288L,42289L,42290L,42291L,42292L,42293L,42294L,42295L,42296L,42297L, |
| 96317 | 42298L,42299L,42300L,42301L,42302L,42303L,42304L,42305L,42306L,42307L, |
| 96318 | 42308L,42309L,42310L,42311L,42312L,42313L,42314L,42315L,42316L,42317L, |
| 96319 | 42318L,42319L,42320L,42321L,42322L,42323L,42324L,42325L,42326L,42327L, |
| 96320 | 42328L,42329L,42330L,42331L,42332L,42333L,42334L,42335L,42336L,42337L, |
| 96321 | 42338L,42339L,42340L,42341L,42342L,42343L,42344L,42345L,42346L,42347L, |
| 96322 | 42348L,42349L,42350L,42351L,42352L,42353L,42354L,42355L,42356L,42357L, |
| 96323 | 42358L,42359L,42360L,42361L,42362L,42363L,42364L,42365L,42366L,42367L, |
| 96324 | 42368L,42369L,42370L,42371L,42372L,42373L,42374L,42375L,42376L,42377L, |
| 96325 | 42378L,42379L,42380L,42381L,42382L,42383L,42384L,42385L,42386L,42387L, |
| 96326 | 42388L,42389L,42390L,42391L,42392L,42393L,42394L,42395L,42396L,42397L, |
| 96327 | 42398L,42399L,42400L,42401L,42402L,42403L,42404L,42405L,42406L,42407L, |
| 96328 | 42408L,42409L,42410L,42411L,42412L,42413L,42414L,42415L,42416L,42417L, |
| 96329 | 42418L,42419L,42420L,42421L,42422L,42423L,42424L,42425L,42426L,42427L, |
| 96330 | 42428L,42429L,42430L,42431L,42432L,42433L,42434L,42435L,42436L,42437L, |
| 96331 | 42438L,42439L,42440L,42441L,42442L,42443L,42444L,42445L,42446L,42447L, |
| 96332 | 42448L,42449L,42450L,42451L,42452L,42453L,42454L,42455L,42456L,42457L, |
| 96333 | 42458L,42459L,42460L,42461L,42462L,42463L,42464L,42465L,42466L,42467L, |
| 96334 | 42468L,42469L,42470L,42471L,42472L,42473L,42474L,42475L,42476L,42477L, |
| 96335 | 42478L,42479L,42480L,42481L,42482L,42483L,42484L,42485L,42486L,42487L, |
| 96336 | 42488L,42489L,42490L,42491L,42492L,42493L,42494L,42495L,42496L,42497L, |
| 96337 | 42498L,42499L,42500L,42501L,42502L,42503L,42504L,42505L,42506L,42507L, |
| 96338 | 42508L,42509L,42510L,42511L,42512L,42513L,42514L,42515L,42516L,42517L, |
| 96339 | 42518L,42519L,42520L,42521L,42522L,42523L,42524L,42525L,42526L,42527L, |
| 96340 | 42528L,42529L,42530L,42531L,42532L,42533L,42534L,42535L,42536L,42537L, |
| 96341 | 42538L,42539L,42540L,42541L,42542L,42543L,42544L,42545L,42546L,42547L, |
| 96342 | 42548L,42549L,42550L,42551L,42552L,42553L,42554L,42555L,42556L,42557L, |
| 96343 | 42558L,42559L,42560L,42560L,42562L,42562L,42564L,42564L,42566L,42566L, |
| 96344 | 42568L,42568L,42570L,42570L,42572L,42572L,42574L,42574L,42576L,42576L, |
| 96345 | 42578L,42578L,42580L,42580L,42582L,42582L,42584L,42584L,42586L,42586L, |
| 96346 | 42588L,42588L,42590L,42590L,42592L,42592L,42594L,42594L,42596L,42596L, |
| 96347 | 42598L,42598L,42600L,42600L,42602L,42602L,42604L,42604L,42606L,42607L, |
| 96348 | 42608L,42609L,42610L,42611L,42612L,42613L,42614L,42615L,42616L,42617L, |
| 96349 | 42618L,42619L,42620L,42621L,42622L,42623L,42624L,42624L,42626L,42626L, |
| 96350 | 42628L,42628L,42630L,42630L,42632L,42632L,42634L,42634L,42636L,42636L, |
| 96351 | 42638L,42638L,42640L,42640L,42642L,42642L,42644L,42644L,42646L,42646L, |
| 96352 | 42648L,42648L,42650L,42650L,42652L,42653L,42654L,42655L,42656L,42657L, |
| 96353 | 42658L,42659L,42660L,42661L,42662L,42663L,42664L,42665L,42666L,42667L, |
| 96354 | 42668L,42669L,42670L,42671L,42672L,42673L,42674L,42675L,42676L,42677L, |
| 96355 | 42678L,42679L,42680L,42681L,42682L,42683L,42684L,42685L,42686L,42687L, |
| 96356 | 42688L,42689L,42690L,42691L,42692L,42693L,42694L,42695L,42696L,42697L, |
| 96357 | 42698L,42699L,42700L,42701L,42702L,42703L,42704L,42705L,42706L,42707L, |
| 96358 | 42708L,42709L,42710L,42711L,42712L,42713L,42714L,42715L,42716L,42717L, |
| 96359 | 42718L,42719L,42720L,42721L,42722L,42723L,42724L,42725L,42726L,42727L, |
| 96360 | 42728L,42729L,42730L,42731L,42732L,42733L,42734L,42735L,42736L,42737L, |
| 96361 | 42738L,42739L,42740L,42741L,42742L,42743L,42744L,42745L,42746L,42747L, |
| 96362 | 42748L,42749L,42750L,42751L,42752L,42753L,42754L,42755L,42756L,42757L, |
| 96363 | 42758L,42759L,42760L,42761L,42762L,42763L,42764L,42765L,42766L,42767L, |
| 96364 | 42768L,42769L,42770L,42771L,42772L,42773L,42774L,42775L,42776L,42777L, |
| 96365 | 42778L,42779L,42780L,42781L,42782L,42783L,42784L,42785L,42786L,42786L, |
| 96366 | 42788L,42788L,42790L,42790L,42792L,42792L,42794L,42794L,42796L,42796L, |
| 96367 | 42798L,42798L,42800L,42801L,42802L,42802L,42804L,42804L,42806L,42806L, |
| 96368 | 42808L,42808L,42810L,42810L,42812L,42812L,42814L,42814L,42816L,42816L, |
| 96369 | 42818L,42818L,42820L,42820L,42822L,42822L,42824L,42824L,42826L,42826L, |
| 96370 | 42828L,42828L,42830L,42830L,42832L,42832L,42834L,42834L,42836L,42836L, |
| 96371 | 42838L,42838L,42840L,42840L,42842L,42842L,42844L,42844L,42846L,42846L, |
| 96372 | 42848L,42848L,42850L,42850L,42852L,42852L,42854L,42854L,42856L,42856L, |
| 96373 | 42858L,42858L,42860L,42860L,42862L,42862L,42864L,42865L,42866L,42867L, |
| 96374 | 42868L,42869L,42870L,42871L,42872L,42873L,42873L,42875L,42875L,42877L, |
| 96375 | 42878L,42878L,42880L,42880L,42882L,42882L,42884L,42884L,42886L,42886L, |
| 96376 | 42888L,42889L,42890L,42891L,42891L,42893L,42894L,42895L,42896L,42896L, |
| 96377 | 42898L,42898L,42948L,42901L,42902L,42902L,42904L,42904L,42906L,42906L, |
| 96378 | 42908L,42908L,42910L,42910L,42912L,42912L,42914L,42914L,42916L,42916L, |
| 96379 | 42918L,42918L,42920L,42920L,42922L,42923L,42924L,42925L,42926L,42927L, |
| 96380 | 42928L,42929L,42930L,42931L,42932L,42932L,42934L,42934L,42936L,42936L, |
| 96381 | 42938L,42938L,42940L,42940L,42942L,42942L,42944L,42945L,42946L,42946L, |
| 96382 | 42948L,42949L,42950L,42951L,42952L,42953L,42954L,42955L,42956L,42957L, |
| 96383 | 42958L,42959L,42960L,42961L,42962L,42963L,42964L,42965L,42966L,42967L, |
| 96384 | 42968L,42969L,42970L,42971L,42972L,42973L,42974L,42975L,42976L,42977L, |
| 96385 | 42978L,42979L,42980L,42981L,42982L,42983L,42984L,42985L,42986L,42987L, |
| 96386 | 42988L,42989L,42990L,42991L,42992L,42993L,42994L,42995L,42996L,42997L, |
| 96387 | 42998L,42999L,43000L,43001L,43002L,43003L,43004L,43005L,43006L,43007L, |
| 96388 | 43008L,43009L,43010L,43011L,43012L,43013L,43014L,43015L,43016L,43017L, |
| 96389 | 43018L,43019L,43020L,43021L,43022L,43023L,43024L,43025L,43026L,43027L, |
| 96390 | 43028L,43029L,43030L,43031L,43032L,43033L,43034L,43035L,43036L,43037L, |
| 96391 | 43038L,43039L,43040L,43041L,43042L,43043L,43044L,43045L,43046L,43047L, |
| 96392 | 43048L,43049L,43050L,43051L,43052L,43053L,43054L,43055L,43056L,43057L, |
| 96393 | 43058L,43059L,43060L,43061L,43062L,43063L,43064L,43065L,43066L,43067L, |
| 96394 | 43068L,43069L,43070L,43071L,43072L,43073L,43074L,43075L,43076L,43077L, |
| 96395 | 43078L,43079L,43080L,43081L,43082L,43083L,43084L,43085L,43086L,43087L, |
| 96396 | 43088L,43089L,43090L,43091L,43092L,43093L,43094L,43095L,43096L,43097L, |
| 96397 | 43098L,43099L,43100L,43101L,43102L,43103L,43104L,43105L,43106L,43107L, |
| 96398 | 43108L,43109L,43110L,43111L,43112L,43113L,43114L,43115L,43116L,43117L, |
| 96399 | 43118L,43119L,43120L,43121L,43122L,43123L,43124L,43125L,43126L,43127L, |
| 96400 | 43128L,43129L,43130L,43131L,43132L,43133L,43134L,43135L,43136L,43137L, |
| 96401 | 43138L,43139L,43140L,43141L,43142L,43143L,43144L,43145L,43146L,43147L, |
| 96402 | 43148L,43149L,43150L,43151L,43152L,43153L,43154L,43155L,43156L,43157L, |
| 96403 | 43158L,43159L,43160L,43161L,43162L,43163L,43164L,43165L,43166L,43167L, |
| 96404 | 43168L,43169L,43170L,43171L,43172L,43173L,43174L,43175L,43176L,43177L, |
| 96405 | 43178L,43179L,43180L,43181L,43182L,43183L,43184L,43185L,43186L,43187L, |
| 96406 | 43188L,43189L,43190L,43191L,43192L,43193L,43194L,43195L,43196L,43197L, |
| 96407 | 43198L,43199L,43200L,43201L,43202L,43203L,43204L,43205L,43206L,43207L, |
| 96408 | 43208L,43209L,43210L,43211L,43212L,43213L,43214L,43215L,43216L,43217L, |
| 96409 | 43218L,43219L,43220L,43221L,43222L,43223L,43224L,43225L,43226L,43227L, |
| 96410 | 43228L,43229L,43230L,43231L,43232L,43233L,43234L,43235L,43236L,43237L, |
| 96411 | 43238L,43239L,43240L,43241L,43242L,43243L,43244L,43245L,43246L,43247L, |
| 96412 | 43248L,43249L,43250L,43251L,43252L,43253L,43254L,43255L,43256L,43257L, |
| 96413 | 43258L,43259L,43260L,43261L,43262L,43263L,43264L,43265L,43266L,43267L, |
| 96414 | 43268L,43269L,43270L,43271L,43272L,43273L,43274L,43275L,43276L,43277L, |
| 96415 | 43278L,43279L,43280L,43281L,43282L,43283L,43284L,43285L,43286L,43287L, |
| 96416 | 43288L,43289L,43290L,43291L,43292L,43293L,43294L,43295L,43296L,43297L, |
| 96417 | 43298L,43299L,43300L,43301L,43302L,43303L,43304L,43305L,43306L,43307L, |
| 96418 | 43308L,43309L,43310L,43311L,43312L,43313L,43314L,43315L,43316L,43317L, |
| 96419 | 43318L,43319L,43320L,43321L,43322L,43323L,43324L,43325L,43326L,43327L, |
| 96420 | 43328L,43329L,43330L,43331L,43332L,43333L,43334L,43335L,43336L,43337L, |
| 96421 | 43338L,43339L,43340L,43341L,43342L,43343L,43344L,43345L,43346L,43347L, |
| 96422 | 43348L,43349L,43350L,43351L,43352L,43353L,43354L,43355L,43356L,43357L, |
| 96423 | 43358L,43359L,43360L,43361L,43362L,43363L,43364L,43365L,43366L,43367L, |
| 96424 | 43368L,43369L,43370L,43371L,43372L,43373L,43374L,43375L,43376L,43377L, |
| 96425 | 43378L,43379L,43380L,43381L,43382L,43383L,43384L,43385L,43386L,43387L, |
| 96426 | 43388L,43389L,43390L,43391L,43392L,43393L,43394L,43395L,43396L,43397L, |
| 96427 | 43398L,43399L,43400L,43401L,43402L,43403L,43404L,43405L,43406L,43407L, |
| 96428 | 43408L,43409L,43410L,43411L,43412L,43413L,43414L,43415L,43416L,43417L, |
| 96429 | 43418L,43419L,43420L,43421L,43422L,43423L,43424L,43425L,43426L,43427L, |
| 96430 | 43428L,43429L,43430L,43431L,43432L,43433L,43434L,43435L,43436L,43437L, |
| 96431 | 43438L,43439L,43440L,43441L,43442L,43443L,43444L,43445L,43446L,43447L, |
| 96432 | 43448L,43449L,43450L,43451L,43452L,43453L,43454L,43455L,43456L,43457L, |
| 96433 | 43458L,43459L,43460L,43461L,43462L,43463L,43464L,43465L,43466L,43467L, |
| 96434 | 43468L,43469L,43470L,43471L,43472L,43473L,43474L,43475L,43476L,43477L, |
| 96435 | 43478L,43479L,43480L,43481L,43482L,43483L,43484L,43485L,43486L,43487L, |
| 96436 | 43488L,43489L,43490L,43491L,43492L,43493L,43494L,43495L,43496L,43497L, |
| 96437 | 43498L,43499L,43500L,43501L,43502L,43503L,43504L,43505L,43506L,43507L, |
| 96438 | 43508L,43509L,43510L,43511L,43512L,43513L,43514L,43515L,43516L,43517L, |
| 96439 | 43518L,43519L,43520L,43521L,43522L,43523L,43524L,43525L,43526L,43527L, |
| 96440 | 43528L,43529L,43530L,43531L,43532L,43533L,43534L,43535L,43536L,43537L, |
| 96441 | 43538L,43539L,43540L,43541L,43542L,43543L,43544L,43545L,43546L,43547L, |
| 96442 | 43548L,43549L,43550L,43551L,43552L,43553L,43554L,43555L,43556L,43557L, |
| 96443 | 43558L,43559L,43560L,43561L,43562L,43563L,43564L,43565L,43566L,43567L, |
| 96444 | 43568L,43569L,43570L,43571L,43572L,43573L,43574L,43575L,43576L,43577L, |
| 96445 | 43578L,43579L,43580L,43581L,43582L,43583L,43584L,43585L,43586L,43587L, |
| 96446 | 43588L,43589L,43590L,43591L,43592L,43593L,43594L,43595L,43596L,43597L, |
| 96447 | 43598L,43599L,43600L,43601L,43602L,43603L,43604L,43605L,43606L,43607L, |
| 96448 | 43608L,43609L,43610L,43611L,43612L,43613L,43614L,43615L,43616L,43617L, |
| 96449 | 43618L,43619L,43620L,43621L,43622L,43623L,43624L,43625L,43626L,43627L, |
| 96450 | 43628L,43629L,43630L,43631L,43632L,43633L,43634L,43635L,43636L,43637L, |
| 96451 | 43638L,43639L,43640L,43641L,43642L,43643L,43644L,43645L,43646L,43647L, |
| 96452 | 43648L,43649L,43650L,43651L,43652L,43653L,43654L,43655L,43656L,43657L, |
| 96453 | 43658L,43659L,43660L,43661L,43662L,43663L,43664L,43665L,43666L,43667L, |
| 96454 | 43668L,43669L,43670L,43671L,43672L,43673L,43674L,43675L,43676L,43677L, |
| 96455 | 43678L,43679L,43680L,43681L,43682L,43683L,43684L,43685L,43686L,43687L, |
| 96456 | 43688L,43689L,43690L,43691L,43692L,43693L,43694L,43695L,43696L,43697L, |
| 96457 | 43698L,43699L,43700L,43701L,43702L,43703L,43704L,43705L,43706L,43707L, |
| 96458 | 43708L,43709L,43710L,43711L,43712L,43713L,43714L,43715L,43716L,43717L, |
| 96459 | 43718L,43719L,43720L,43721L,43722L,43723L,43724L,43725L,43726L,43727L, |
| 96460 | 43728L,43729L,43730L,43731L,43732L,43733L,43734L,43735L,43736L,43737L, |
| 96461 | 43738L,43739L,43740L,43741L,43742L,43743L,43744L,43745L,43746L,43747L, |
| 96462 | 43748L,43749L,43750L,43751L,43752L,43753L,43754L,43755L,43756L,43757L, |
| 96463 | 43758L,43759L,43760L,43761L,43762L,43763L,43764L,43765L,43766L,43767L, |
| 96464 | 43768L,43769L,43770L,43771L,43772L,43773L,43774L,43775L,43776L,43777L, |
| 96465 | 43778L,43779L,43780L,43781L,43782L,43783L,43784L,43785L,43786L,43787L, |
| 96466 | 43788L,43789L,43790L,43791L,43792L,43793L,43794L,43795L,43796L,43797L, |
| 96467 | 43798L,43799L,43800L,43801L,43802L,43803L,43804L,43805L,43806L,43807L, |
| 96468 | 43808L,43809L,43810L,43811L,43812L,43813L,43814L,43815L,43816L,43817L, |
| 96469 | 43818L,43819L,43820L,43821L,43822L,43823L,43824L,43825L,43826L,43827L, |
| 96470 | 43828L,43829L,43830L,43831L,43832L,43833L,43834L,43835L,43836L,43837L, |
| 96471 | 43838L,43839L,43840L,43841L,43842L,43843L,43844L,43845L,43846L,43847L, |
| 96472 | 43848L,43849L,43850L,43851L,43852L,43853L,43854L,43855L,43856L,43857L, |
| 96473 | 43858L,42931L,43860L,43861L,43862L,43863L,43864L,43865L,43866L,43867L, |
| 96474 | 43868L,43869L,43870L,43871L,43872L,43873L,43874L,43875L,43876L,43877L, |
| 96475 | 43878L,43879L,43880L,43881L,43882L,43883L,43884L,43885L,43886L,43887L,5024, |
| 96476 | 5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039, |
| 96477 | 5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054, |
| 96478 | 5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069, |
| 96479 | 5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084, |
| 96480 | 5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099, |
| 96481 | 5100,5101,5102,5103,43968L,43969L,43970L,43971L,43972L,43973L,43974L, |
| 96482 | 43975L,43976L,43977L,43978L,43979L,43980L,43981L,43982L,43983L,43984L, |
| 96483 | 43985L,43986L,43987L,43988L,43989L,43990L,43991L,43992L,43993L,43994L, |
| 96484 | 43995L,43996L,43997L,43998L,43999L,44000L,44001L,44002L,44003L,44004L, |
| 96485 | 44005L,44006L,44007L,44008L,44009L,44010L,44011L,44012L,44013L,44014L, |
| 96486 | 44015L,44016L,44017L,44018L,44019L,44020L,44021L,44022L,44023L,44024L, |
| 96487 | 44025L,44026L,44027L,44028L,44029L,44030L,44031L,44032L,44033L,44034L, |
| 96488 | 44035L,44036L,44037L,44038L,44039L,44040L,44041L,44042L,44043L,44044L, |
| 96489 | 44045L,44046L,44047L,44048L,44049L,44050L,44051L,44052L,44053L,44054L, |
| 96490 | 44055L,44056L,44057L,44058L,44059L,44060L,44061L,44062L,44063L,44064L, |
| 96491 | 44065L,44066L,44067L,44068L,44069L,44070L,44071L,44072L,44073L,44074L, |
| 96492 | 44075L,44076L,44077L,44078L,44079L,44080L,44081L,44082L,44083L,44084L, |
| 96493 | 44085L,44086L,44087L,44088L,44089L,44090L,44091L,44092L,44093L,44094L, |
| 96494 | 44095L,44096L,44097L,44098L,44099L,44100L,44101L,44102L,44103L,44104L, |
| 96495 | 44105L,44106L,44107L,44108L,44109L,44110L,44111L,44112L,44113L,44114L, |
| 96496 | 44115L,44116L,44117L,44118L,44119L,44120L,44121L,44122L,44123L,44124L, |
| 96497 | 44125L,44126L,44127L,44128L,44129L,44130L,44131L,44132L,44133L,44134L, |
| 96498 | 44135L,44136L,44137L,44138L,44139L,44140L,44141L,44142L,44143L,44144L, |
| 96499 | 44145L,44146L,44147L,44148L,44149L,44150L,44151L,44152L,44153L,44154L, |
| 96500 | 44155L,44156L,44157L,44158L,44159L,44160L,44161L,44162L,44163L,44164L, |
| 96501 | 44165L,44166L,44167L,44168L,44169L,44170L,44171L,44172L,44173L,44174L, |
| 96502 | 44175L,44176L,44177L,44178L,44179L,44180L,44181L,44182L,44183L,44184L, |
| 96503 | 44185L,44186L,44187L,44188L,44189L,44190L,44191L,44192L,44193L,44194L, |
| 96504 | 44195L,44196L,44197L,44198L,44199L,44200L,44201L,44202L,44203L,44204L, |
| 96505 | 44205L,44206L,44207L,44208L,44209L,44210L,44211L,44212L,44213L,44214L, |
| 96506 | 44215L,44216L,44217L,44218L,44219L,44220L,44221L,44222L,44223L,44224L, |
| 96507 | 44225L,44226L,44227L,44228L,44229L,44230L,44231L,44232L,44233L,44234L, |
| 96508 | 44235L,44236L,44237L,44238L,44239L,44240L,44241L,44242L,44243L,44244L, |
| 96509 | 44245L,44246L,44247L,44248L,44249L,44250L,44251L,44252L,44253L,44254L, |
| 96510 | 44255L,44256L,44257L,44258L,44259L,44260L,44261L,44262L,44263L,44264L, |
| 96511 | 44265L,44266L,44267L,44268L,44269L,44270L,44271L,44272L,44273L,44274L, |
| 96512 | 44275L,44276L,44277L,44278L,44279L,44280L,44281L,44282L,44283L,44284L, |
| 96513 | 44285L,44286L,44287L,44288L,44289L,44290L,44291L,44292L,44293L,44294L, |
| 96514 | 44295L,44296L,44297L,44298L,44299L,44300L,44301L,44302L,44303L,44304L, |
| 96515 | 44305L,44306L,44307L,44308L,44309L,44310L,44311L,44312L,44313L,44314L, |
| 96516 | 44315L,44316L,44317L,44318L,44319L,44320L,44321L,44322L,44323L,44324L, |
| 96517 | 44325L,44326L,44327L,44328L,44329L,44330L,44331L,44332L,44333L,44334L, |
| 96518 | 44335L,44336L,44337L,44338L,44339L,44340L,44341L,44342L,44343L,44344L, |
| 96519 | 44345L,44346L,44347L,44348L,44349L,44350L,44351L,44352L,44353L,44354L, |
| 96520 | 44355L,44356L,44357L,44358L,44359L,44360L,44361L,44362L,44363L,44364L, |
| 96521 | 44365L,44366L,44367L,44368L,44369L,44370L,44371L,44372L,44373L,44374L, |
| 96522 | 44375L,44376L,44377L,44378L,44379L,44380L,44381L,44382L,44383L,44384L, |
| 96523 | 44385L,44386L,44387L,44388L,44389L,44390L,44391L,44392L,44393L,44394L, |
| 96524 | 44395L,44396L,44397L,44398L,44399L,44400L,44401L,44402L,44403L,44404L, |
| 96525 | 44405L,44406L,44407L,44408L,44409L,44410L,44411L,44412L,44413L,44414L, |
| 96526 | 44415L,44416L,44417L,44418L,44419L,44420L,44421L,44422L,44423L,44424L, |
| 96527 | 44425L,44426L,44427L,44428L,44429L,44430L,44431L,44432L,44433L,44434L, |
| 96528 | 44435L,44436L,44437L,44438L,44439L,44440L,44441L,44442L,44443L,44444L, |
| 96529 | 44445L,44446L,44447L,44448L,44449L,44450L,44451L,44452L,44453L,44454L, |
| 96530 | 44455L,44456L,44457L,44458L,44459L,44460L,44461L,44462L,44463L,44464L, |
| 96531 | 44465L,44466L,44467L,44468L,44469L,44470L,44471L,44472L,44473L,44474L, |
| 96532 | 44475L,44476L,44477L,44478L,44479L,44480L,44481L,44482L,44483L,44484L, |
| 96533 | 44485L,44486L,44487L,44488L,44489L,44490L,44491L,44492L,44493L,44494L, |
| 96534 | 44495L,44496L,44497L,44498L,44499L,44500L,44501L,44502L,44503L,44504L, |
| 96535 | 44505L,44506L,44507L,44508L,44509L,44510L,44511L,44512L,44513L,44514L, |
| 96536 | 44515L,44516L,44517L,44518L,44519L,44520L,44521L,44522L,44523L,44524L, |
| 96537 | 44525L,44526L,44527L,44528L,44529L,44530L,44531L,44532L,44533L,44534L, |
| 96538 | 44535L,44536L,44537L,44538L,44539L,44540L,44541L,44542L,44543L,44544L, |
| 96539 | 44545L,44546L,44547L,44548L,44549L,44550L,44551L,44552L,44553L,44554L, |
| 96540 | 44555L,44556L,44557L,44558L,44559L,44560L,44561L,44562L,44563L,44564L, |
| 96541 | 44565L,44566L,44567L,44568L,44569L,44570L,44571L,44572L,44573L,44574L, |
| 96542 | 44575L,44576L,44577L,44578L,44579L,44580L,44581L,44582L,44583L,44584L, |
| 96543 | 44585L,44586L,44587L,44588L,44589L,44590L,44591L,44592L,44593L,44594L, |
| 96544 | 44595L,44596L,44597L,44598L,44599L,44600L,44601L,44602L,44603L,44604L, |
| 96545 | 44605L,44606L,44607L,44608L,44609L,44610L,44611L,44612L,44613L,44614L, |
| 96546 | 44615L,44616L,44617L,44618L,44619L,44620L,44621L,44622L,44623L,44624L, |
| 96547 | 44625L,44626L,44627L,44628L,44629L,44630L,44631L,44632L,44633L,44634L, |
| 96548 | 44635L,44636L,44637L,44638L,44639L,44640L,44641L,44642L,44643L,44644L, |
| 96549 | 44645L,44646L,44647L,44648L,44649L,44650L,44651L,44652L,44653L,44654L, |
| 96550 | 44655L,44656L,44657L,44658L,44659L,44660L,44661L,44662L,44663L,44664L, |
| 96551 | 44665L,44666L,44667L,44668L,44669L,44670L,44671L,44672L,44673L,44674L, |
| 96552 | 44675L,44676L,44677L,44678L,44679L,44680L,44681L,44682L,44683L,44684L, |
| 96553 | 44685L,44686L,44687L,44688L,44689L,44690L,44691L,44692L,44693L,44694L, |
| 96554 | 44695L,44696L,44697L,44698L,44699L,44700L,44701L,44702L,44703L,44704L, |
| 96555 | 44705L,44706L,44707L,44708L,44709L,44710L,44711L,44712L,44713L,44714L, |
| 96556 | 44715L,44716L,44717L,44718L,44719L,44720L,44721L,44722L,44723L,44724L, |
| 96557 | 44725L,44726L,44727L,44728L,44729L,44730L,44731L,44732L,44733L,44734L, |
| 96558 | 44735L,44736L,44737L,44738L,44739L,44740L,44741L,44742L,44743L,44744L, |
| 96559 | 44745L,44746L,44747L,44748L,44749L,44750L,44751L,44752L,44753L,44754L, |
| 96560 | 44755L,44756L,44757L,44758L,44759L,44760L,44761L,44762L,44763L,44764L, |
| 96561 | 44765L,44766L,44767L,44768L,44769L,44770L,44771L,44772L,44773L,44774L, |
| 96562 | 44775L,44776L,44777L,44778L,44779L,44780L,44781L,44782L,44783L,44784L, |
| 96563 | 44785L,44786L,44787L,44788L,44789L,44790L,44791L,44792L,44793L,44794L, |
| 96564 | 44795L,44796L,44797L,44798L,44799L,44800L,44801L,44802L,44803L,44804L, |
| 96565 | 44805L,44806L,44807L,44808L,44809L,44810L,44811L,44812L,44813L,44814L, |
| 96566 | 44815L,44816L,44817L,44818L,44819L,44820L,44821L,44822L,44823L,44824L, |
| 96567 | 44825L,44826L,44827L,44828L,44829L,44830L,44831L,44832L,44833L,44834L, |
| 96568 | 44835L,44836L,44837L,44838L,44839L,44840L,44841L,44842L,44843L,44844L, |
| 96569 | 44845L,44846L,44847L,44848L,44849L,44850L,44851L,44852L,44853L,44854L, |
| 96570 | 44855L,44856L,44857L,44858L,44859L,44860L,44861L,44862L,44863L,44864L, |
| 96571 | 44865L,44866L,44867L,44868L,44869L,44870L,44871L,44872L,44873L,44874L, |
| 96572 | 44875L,44876L,44877L,44878L,44879L,44880L,44881L,44882L,44883L,44884L, |
| 96573 | 44885L,44886L,44887L,44888L,44889L,44890L,44891L,44892L,44893L,44894L, |
| 96574 | 44895L,44896L,44897L,44898L,44899L,44900L,44901L,44902L,44903L,44904L, |
| 96575 | 44905L,44906L,44907L,44908L,44909L,44910L,44911L,44912L,44913L,44914L, |
| 96576 | 44915L,44916L,44917L,44918L,44919L,44920L,44921L,44922L,44923L,44924L, |
| 96577 | 44925L,44926L,44927L,44928L,44929L,44930L,44931L,44932L,44933L,44934L, |
| 96578 | 44935L,44936L,44937L,44938L,44939L,44940L,44941L,44942L,44943L,44944L, |
| 96579 | 44945L,44946L,44947L,44948L,44949L,44950L,44951L,44952L,44953L,44954L, |
| 96580 | 44955L,44956L,44957L,44958L,44959L,44960L,44961L,44962L,44963L,44964L, |
| 96581 | 44965L,44966L,44967L,44968L,44969L,44970L,44971L,44972L,44973L,44974L, |
| 96582 | 44975L,44976L,44977L,44978L,44979L,44980L,44981L,44982L,44983L,44984L, |
| 96583 | 44985L,44986L,44987L,44988L,44989L,44990L,44991L,44992L,44993L,44994L, |
| 96584 | 44995L,44996L,44997L,44998L,44999L,45000L,45001L,45002L,45003L,45004L, |
| 96585 | 45005L,45006L,45007L,45008L,45009L,45010L,45011L,45012L,45013L,45014L, |
| 96586 | 45015L,45016L,45017L,45018L,45019L,45020L,45021L,45022L,45023L,45024L, |
| 96587 | 45025L,45026L,45027L,45028L,45029L,45030L,45031L,45032L,45033L,45034L, |
| 96588 | 45035L,45036L,45037L,45038L,45039L,45040L,45041L,45042L,45043L,45044L, |
| 96589 | 45045L,45046L,45047L,45048L,45049L,45050L,45051L,45052L,45053L,45054L, |
| 96590 | 45055L,45056L,45057L,45058L,45059L,45060L,45061L,45062L,45063L,45064L, |
| 96591 | 45065L,45066L,45067L,45068L,45069L,45070L,45071L,45072L,45073L,45074L, |
| 96592 | 45075L,45076L,45077L,45078L,45079L,45080L,45081L,45082L,45083L,45084L, |
| 96593 | 45085L,45086L,45087L,45088L,45089L,45090L,45091L,45092L,45093L,45094L, |
| 96594 | 45095L,45096L,45097L,45098L,45099L,45100L,45101L,45102L,45103L,45104L, |
| 96595 | 45105L,45106L,45107L,45108L,45109L,45110L,45111L,45112L,45113L,45114L, |
| 96596 | 45115L,45116L,45117L,45118L,45119L,45120L,45121L,45122L,45123L,45124L, |
| 96597 | 45125L,45126L,45127L,45128L,45129L,45130L,45131L,45132L,45133L,45134L, |
| 96598 | 45135L,45136L,45137L,45138L,45139L,45140L,45141L,45142L,45143L,45144L, |
| 96599 | 45145L,45146L,45147L,45148L,45149L,45150L,45151L,45152L,45153L,45154L, |
| 96600 | 45155L,45156L,45157L,45158L,45159L,45160L,45161L,45162L,45163L,45164L, |
| 96601 | 45165L,45166L,45167L,45168L,45169L,45170L,45171L,45172L,45173L,45174L, |
| 96602 | 45175L,45176L,45177L,45178L,45179L,45180L,45181L,45182L,45183L,45184L, |
| 96603 | 45185L,45186L,45187L,45188L,45189L,45190L,45191L,45192L,45193L,45194L, |
| 96604 | 45195L,45196L,45197L,45198L,45199L,45200L,45201L,45202L,45203L,45204L, |
| 96605 | 45205L,45206L,45207L,45208L,45209L,45210L,45211L,45212L,45213L,45214L, |
| 96606 | 45215L,45216L,45217L,45218L,45219L,45220L,45221L,45222L,45223L,45224L, |
| 96607 | 45225L,45226L,45227L,45228L,45229L,45230L,45231L,45232L,45233L,45234L, |
| 96608 | 45235L,45236L,45237L,45238L,45239L,45240L,45241L,45242L,45243L,45244L, |
| 96609 | 45245L,45246L,45247L,45248L,45249L,45250L,45251L,45252L,45253L,45254L, |
| 96610 | 45255L,45256L,45257L,45258L,45259L,45260L,45261L,45262L,45263L,45264L, |
| 96611 | 45265L,45266L,45267L,45268L,45269L,45270L,45271L,45272L,45273L,45274L, |
| 96612 | 45275L,45276L,45277L,45278L,45279L,45280L,45281L,45282L,45283L,45284L, |
| 96613 | 45285L,45286L,45287L,45288L,45289L,45290L,45291L,45292L,45293L,45294L, |
| 96614 | 45295L,45296L,45297L,45298L,45299L,45300L,45301L,45302L,45303L,45304L, |
| 96615 | 45305L,45306L,45307L,45308L,45309L,45310L,45311L,45312L,45313L,45314L, |
| 96616 | 45315L,45316L,45317L,45318L,45319L,45320L,45321L,45322L,45323L,45324L, |
| 96617 | 45325L,45326L,45327L,45328L,45329L,45330L,45331L,45332L,45333L,45334L, |
| 96618 | 45335L,45336L,45337L,45338L,45339L,45340L,45341L,45342L,45343L,45344L, |
| 96619 | 45345L,45346L,45347L,45348L,45349L,45350L,45351L,45352L,45353L,45354L, |
| 96620 | 45355L,45356L,45357L,45358L,45359L,45360L,45361L,45362L,45363L,45364L, |
| 96621 | 45365L,45366L,45367L,45368L,45369L,45370L,45371L,45372L,45373L,45374L, |
| 96622 | 45375L,45376L,45377L,45378L,45379L,45380L,45381L,45382L,45383L,45384L, |
| 96623 | 45385L,45386L,45387L,45388L,45389L,45390L,45391L,45392L,45393L,45394L, |
| 96624 | 45395L,45396L,45397L,45398L,45399L,45400L,45401L,45402L,45403L,45404L, |
| 96625 | 45405L,45406L,45407L,45408L,45409L,45410L,45411L,45412L,45413L,45414L, |
| 96626 | 45415L,45416L,45417L,45418L,45419L,45420L,45421L,45422L,45423L,45424L, |
| 96627 | 45425L,45426L,45427L,45428L,45429L,45430L,45431L,45432L,45433L,45434L, |
| 96628 | 45435L,45436L,45437L,45438L,45439L,45440L,45441L,45442L,45443L,45444L, |
| 96629 | 45445L,45446L,45447L,45448L,45449L,45450L,45451L,45452L,45453L,45454L, |
| 96630 | 45455L,45456L,45457L,45458L,45459L,45460L,45461L,45462L,45463L,45464L, |
| 96631 | 45465L,45466L,45467L,45468L,45469L,45470L,45471L,45472L,45473L,45474L, |
| 96632 | 45475L,45476L,45477L,45478L,45479L,45480L,45481L,45482L,45483L,45484L, |
| 96633 | 45485L,45486L,45487L,45488L,45489L,45490L,45491L,45492L,45493L,45494L, |
| 96634 | 45495L,45496L,45497L,45498L,45499L,45500L,45501L,45502L,45503L,45504L, |
| 96635 | 45505L,45506L,45507L,45508L,45509L,45510L,45511L,45512L,45513L,45514L, |
| 96636 | 45515L,45516L,45517L,45518L,45519L,45520L,45521L,45522L,45523L,45524L, |
| 96637 | 45525L,45526L,45527L,45528L,45529L,45530L,45531L,45532L,45533L,45534L, |
| 96638 | 45535L,45536L,45537L,45538L,45539L,45540L,45541L,45542L,45543L,45544L, |
| 96639 | 45545L,45546L,45547L,45548L,45549L,45550L,45551L,45552L,45553L,45554L, |
| 96640 | 45555L,45556L,45557L,45558L,45559L,45560L,45561L,45562L,45563L,45564L, |
| 96641 | 45565L,45566L,45567L,45568L,45569L,45570L,45571L,45572L,45573L,45574L, |
| 96642 | 45575L,45576L,45577L,45578L,45579L,45580L,45581L,45582L,45583L,45584L, |
| 96643 | 45585L,45586L,45587L,45588L,45589L,45590L,45591L,45592L,45593L,45594L, |
| 96644 | 45595L,45596L,45597L,45598L,45599L,45600L,45601L,45602L,45603L,45604L, |
| 96645 | 45605L,45606L,45607L,45608L,45609L,45610L,45611L,45612L,45613L,45614L, |
| 96646 | 45615L,45616L,45617L,45618L,45619L,45620L,45621L,45622L,45623L,45624L, |
| 96647 | 45625L,45626L,45627L,45628L,45629L,45630L,45631L,45632L,45633L,45634L, |
| 96648 | 45635L,45636L,45637L,45638L,45639L,45640L,45641L,45642L,45643L,45644L, |
| 96649 | 45645L,45646L,45647L,45648L,45649L,45650L,45651L,45652L,45653L,45654L, |
| 96650 | 45655L,45656L,45657L,45658L,45659L,45660L,45661L,45662L,45663L,45664L, |
| 96651 | 45665L,45666L,45667L,45668L,45669L,45670L,45671L,45672L,45673L,45674L, |
| 96652 | 45675L,45676L,45677L,45678L,45679L,45680L,45681L,45682L,45683L,45684L, |
| 96653 | 45685L,45686L,45687L,45688L,45689L,45690L,45691L,45692L,45693L,45694L, |
| 96654 | 45695L,45696L,45697L,45698L,45699L,45700L,45701L,45702L,45703L,45704L, |
| 96655 | 45705L,45706L,45707L,45708L,45709L,45710L,45711L,45712L,45713L,45714L, |
| 96656 | 45715L,45716L,45717L,45718L,45719L,45720L,45721L,45722L,45723L,45724L, |
| 96657 | 45725L,45726L,45727L,45728L,45729L,45730L,45731L,45732L,45733L,45734L, |
| 96658 | 45735L,45736L,45737L,45738L,45739L,45740L,45741L,45742L,45743L,45744L, |
| 96659 | 45745L,45746L,45747L,45748L,45749L,45750L,45751L,45752L,45753L,45754L, |
| 96660 | 45755L,45756L,45757L,45758L,45759L,45760L,45761L,45762L,45763L,45764L, |
| 96661 | 45765L,45766L,45767L,45768L,45769L,45770L,45771L,45772L,45773L,45774L, |
| 96662 | 45775L,45776L,45777L,45778L,45779L,45780L,45781L,45782L,45783L,45784L, |
| 96663 | 45785L,45786L,45787L,45788L,45789L,45790L,45791L,45792L,45793L,45794L, |
| 96664 | 45795L,45796L,45797L,45798L,45799L,45800L,45801L,45802L,45803L,45804L, |
| 96665 | 45805L,45806L,45807L,45808L,45809L,45810L,45811L,45812L,45813L,45814L, |
| 96666 | 45815L,45816L,45817L,45818L,45819L,45820L,45821L,45822L,45823L,45824L, |
| 96667 | 45825L,45826L,45827L,45828L,45829L,45830L,45831L,45832L,45833L,45834L, |
| 96668 | 45835L,45836L,45837L,45838L,45839L,45840L,45841L,45842L,45843L,45844L, |
| 96669 | 45845L,45846L,45847L,45848L,45849L,45850L,45851L,45852L,45853L,45854L, |
| 96670 | 45855L,45856L,45857L,45858L,45859L,45860L,45861L,45862L,45863L,45864L, |
| 96671 | 45865L,45866L,45867L,45868L,45869L,45870L,45871L,45872L,45873L,45874L, |
| 96672 | 45875L,45876L,45877L,45878L,45879L,45880L,45881L,45882L,45883L,45884L, |
| 96673 | 45885L,45886L,45887L,45888L,45889L,45890L,45891L,45892L,45893L,45894L, |
| 96674 | 45895L,45896L,45897L,45898L,45899L,45900L,45901L,45902L,45903L,45904L, |
| 96675 | 45905L,45906L,45907L,45908L,45909L,45910L,45911L,45912L,45913L,45914L, |
| 96676 | 45915L,45916L,45917L,45918L,45919L,45920L,45921L,45922L,45923L,45924L, |
| 96677 | 45925L,45926L,45927L,45928L,45929L,45930L,45931L,45932L,45933L,45934L, |
| 96678 | 45935L,45936L,45937L,45938L,45939L,45940L,45941L,45942L,45943L,45944L, |
| 96679 | 45945L,45946L,45947L,45948L,45949L,45950L,45951L,45952L,45953L,45954L, |
| 96680 | 45955L,45956L,45957L,45958L,45959L,45960L,45961L,45962L,45963L,45964L, |
| 96681 | 45965L,45966L,45967L,45968L,45969L,45970L,45971L,45972L,45973L,45974L, |
| 96682 | 45975L,45976L,45977L,45978L,45979L,45980L,45981L,45982L,45983L,45984L, |
| 96683 | 45985L,45986L,45987L,45988L,45989L,45990L,45991L,45992L,45993L,45994L, |
| 96684 | 45995L,45996L,45997L,45998L,45999L,46000L,46001L,46002L,46003L,46004L, |
| 96685 | 46005L,46006L,46007L,46008L,46009L,46010L,46011L,46012L,46013L,46014L, |
| 96686 | 46015L,46016L,46017L,46018L,46019L,46020L,46021L,46022L,46023L,46024L, |
| 96687 | 46025L,46026L,46027L,46028L,46029L,46030L,46031L,46032L,46033L,46034L, |
| 96688 | 46035L,46036L,46037L,46038L,46039L,46040L,46041L,46042L,46043L,46044L, |
| 96689 | 46045L,46046L,46047L,46048L,46049L,46050L,46051L,46052L,46053L,46054L, |
| 96690 | 46055L,46056L,46057L,46058L,46059L,46060L,46061L,46062L,46063L,46064L, |
| 96691 | 46065L,46066L,46067L,46068L,46069L,46070L,46071L,46072L,46073L,46074L, |
| 96692 | 46075L,46076L,46077L,46078L,46079L,46080L,46081L,46082L,46083L,46084L, |
| 96693 | 46085L,46086L,46087L,46088L,46089L,46090L,46091L,46092L,46093L,46094L, |
| 96694 | 46095L,46096L,46097L,46098L,46099L,46100L,46101L,46102L,46103L,46104L, |
| 96695 | 46105L,46106L,46107L,46108L,46109L,46110L,46111L,46112L,46113L,46114L, |
| 96696 | 46115L,46116L,46117L,46118L,46119L,46120L,46121L,46122L,46123L,46124L, |
| 96697 | 46125L,46126L,46127L,46128L,46129L,46130L,46131L,46132L,46133L,46134L, |
| 96698 | 46135L,46136L,46137L,46138L,46139L,46140L,46141L,46142L,46143L,46144L, |
| 96699 | 46145L,46146L,46147L,46148L,46149L,46150L,46151L,46152L,46153L,46154L, |
| 96700 | 46155L,46156L,46157L,46158L,46159L,46160L,46161L,46162L,46163L,46164L, |
| 96701 | 46165L,46166L,46167L,46168L,46169L,46170L,46171L,46172L,46173L,46174L, |
| 96702 | 46175L,46176L,46177L,46178L,46179L,46180L,46181L,46182L,46183L,46184L, |
| 96703 | 46185L,46186L,46187L,46188L,46189L,46190L,46191L,46192L,46193L,46194L, |
| 96704 | 46195L,46196L,46197L,46198L,46199L,46200L,46201L,46202L,46203L,46204L, |
| 96705 | 46205L,46206L,46207L,46208L,46209L,46210L,46211L,46212L,46213L,46214L, |
| 96706 | 46215L,46216L,46217L,46218L,46219L,46220L,46221L,46222L,46223L,46224L, |
| 96707 | 46225L,46226L,46227L,46228L,46229L,46230L,46231L,46232L,46233L,46234L, |
| 96708 | 46235L,46236L,46237L,46238L,46239L,46240L,46241L,46242L,46243L,46244L, |
| 96709 | 46245L,46246L,46247L,46248L,46249L,46250L,46251L,46252L,46253L,46254L, |
| 96710 | 46255L,46256L,46257L,46258L,46259L,46260L,46261L,46262L,46263L,46264L, |
| 96711 | 46265L,46266L,46267L,46268L,46269L,46270L,46271L,46272L,46273L,46274L, |
| 96712 | 46275L,46276L,46277L,46278L,46279L,46280L,46281L,46282L,46283L,46284L, |
| 96713 | 46285L,46286L,46287L,46288L,46289L,46290L,46291L,46292L,46293L,46294L, |
| 96714 | 46295L,46296L,46297L,46298L,46299L,46300L,46301L,46302L,46303L,46304L, |
| 96715 | 46305L,46306L,46307L,46308L,46309L,46310L,46311L,46312L,46313L,46314L, |
| 96716 | 46315L,46316L,46317L,46318L,46319L,46320L,46321L,46322L,46323L,46324L, |
| 96717 | 46325L,46326L,46327L,46328L,46329L,46330L,46331L,46332L,46333L,46334L, |
| 96718 | 46335L,46336L,46337L,46338L,46339L,46340L,46341L,46342L,46343L,46344L, |
| 96719 | 46345L,46346L,46347L,46348L,46349L,46350L,46351L,46352L,46353L,46354L, |
| 96720 | 46355L,46356L,46357L,46358L,46359L,46360L,46361L,46362L,46363L,46364L, |
| 96721 | 46365L,46366L,46367L,46368L,46369L,46370L,46371L,46372L,46373L,46374L, |
| 96722 | 46375L,46376L,46377L,46378L,46379L,46380L,46381L,46382L,46383L,46384L, |
| 96723 | 46385L,46386L,46387L,46388L,46389L,46390L,46391L,46392L,46393L,46394L, |
| 96724 | 46395L,46396L,46397L,46398L,46399L,46400L,46401L,46402L,46403L,46404L, |
| 96725 | 46405L,46406L,46407L,46408L,46409L,46410L,46411L,46412L,46413L,46414L, |
| 96726 | 46415L,46416L,46417L,46418L,46419L,46420L,46421L,46422L,46423L,46424L, |
| 96727 | 46425L,46426L,46427L,46428L,46429L,46430L,46431L,46432L,46433L,46434L, |
| 96728 | 46435L,46436L,46437L,46438L,46439L,46440L,46441L,46442L,46443L,46444L, |
| 96729 | 46445L,46446L,46447L,46448L,46449L,46450L,46451L,46452L,46453L,46454L, |
| 96730 | 46455L,46456L,46457L,46458L,46459L,46460L,46461L,46462L,46463L,46464L, |
| 96731 | 46465L,46466L,46467L,46468L,46469L,46470L,46471L,46472L,46473L,46474L, |
| 96732 | 46475L,46476L,46477L,46478L,46479L,46480L,46481L,46482L,46483L,46484L, |
| 96733 | 46485L,46486L,46487L,46488L,46489L,46490L,46491L,46492L,46493L,46494L, |
| 96734 | 46495L,46496L,46497L,46498L,46499L,46500L,46501L,46502L,46503L,46504L, |
| 96735 | 46505L,46506L,46507L,46508L,46509L,46510L,46511L,46512L,46513L,46514L, |
| 96736 | 46515L,46516L,46517L,46518L,46519L,46520L,46521L,46522L,46523L,46524L, |
| 96737 | 46525L,46526L,46527L,46528L,46529L,46530L,46531L,46532L,46533L,46534L, |
| 96738 | 46535L,46536L,46537L,46538L,46539L,46540L,46541L,46542L,46543L,46544L, |
| 96739 | 46545L,46546L,46547L,46548L,46549L,46550L,46551L,46552L,46553L,46554L, |
| 96740 | 46555L,46556L,46557L,46558L,46559L,46560L,46561L,46562L,46563L,46564L, |
| 96741 | 46565L,46566L,46567L,46568L,46569L,46570L,46571L,46572L,46573L,46574L, |
| 96742 | 46575L,46576L,46577L,46578L,46579L,46580L,46581L,46582L,46583L,46584L, |
| 96743 | 46585L,46586L,46587L,46588L,46589L,46590L,46591L,46592L,46593L,46594L, |
| 96744 | 46595L,46596L,46597L,46598L,46599L,46600L,46601L,46602L,46603L,46604L, |
| 96745 | 46605L,46606L,46607L,46608L,46609L,46610L,46611L,46612L,46613L,46614L, |
| 96746 | 46615L,46616L,46617L,46618L,46619L,46620L,46621L,46622L,46623L,46624L, |
| 96747 | 46625L,46626L,46627L,46628L,46629L,46630L,46631L,46632L,46633L,46634L, |
| 96748 | 46635L,46636L,46637L,46638L,46639L,46640L,46641L,46642L,46643L,46644L, |
| 96749 | 46645L,46646L,46647L,46648L,46649L,46650L,46651L,46652L,46653L,46654L, |
| 96750 | 46655L,46656L,46657L,46658L,46659L,46660L,46661L,46662L,46663L,46664L, |
| 96751 | 46665L,46666L,46667L,46668L,46669L,46670L,46671L,46672L,46673L,46674L, |
| 96752 | 46675L,46676L,46677L,46678L,46679L,46680L,46681L,46682L,46683L,46684L, |
| 96753 | 46685L,46686L,46687L,46688L,46689L,46690L,46691L,46692L,46693L,46694L, |
| 96754 | 46695L,46696L,46697L,46698L,46699L,46700L,46701L,46702L,46703L,46704L, |
| 96755 | 46705L,46706L,46707L,46708L,46709L,46710L,46711L,46712L,46713L,46714L, |
| 96756 | 46715L,46716L,46717L,46718L,46719L,46720L,46721L,46722L,46723L,46724L, |
| 96757 | 46725L,46726L,46727L,46728L,46729L,46730L,46731L,46732L,46733L,46734L, |
| 96758 | 46735L,46736L,46737L,46738L,46739L,46740L,46741L,46742L,46743L,46744L, |
| 96759 | 46745L,46746L,46747L,46748L,46749L,46750L,46751L,46752L,46753L,46754L, |
| 96760 | 46755L,46756L,46757L,46758L,46759L,46760L,46761L,46762L,46763L,46764L, |
| 96761 | 46765L,46766L,46767L,46768L,46769L,46770L,46771L,46772L,46773L,46774L, |
| 96762 | 46775L,46776L,46777L,46778L,46779L,46780L,46781L,46782L,46783L,46784L, |
| 96763 | 46785L,46786L,46787L,46788L,46789L,46790L,46791L,46792L,46793L,46794L, |
| 96764 | 46795L,46796L,46797L,46798L,46799L,46800L,46801L,46802L,46803L,46804L, |
| 96765 | 46805L,46806L,46807L,46808L,46809L,46810L,46811L,46812L,46813L,46814L, |
| 96766 | 46815L,46816L,46817L,46818L,46819L,46820L,46821L,46822L,46823L,46824L, |
| 96767 | 46825L,46826L,46827L,46828L,46829L,46830L,46831L,46832L,46833L,46834L, |
| 96768 | 46835L,46836L,46837L,46838L,46839L,46840L,46841L,46842L,46843L,46844L, |
| 96769 | 46845L,46846L,46847L,46848L,46849L,46850L,46851L,46852L,46853L,46854L, |
| 96770 | 46855L,46856L,46857L,46858L,46859L,46860L,46861L,46862L,46863L,46864L, |
| 96771 | 46865L,46866L,46867L,46868L,46869L,46870L,46871L,46872L,46873L,46874L, |
| 96772 | 46875L,46876L,46877L,46878L,46879L,46880L,46881L,46882L,46883L,46884L, |
| 96773 | 46885L,46886L,46887L,46888L,46889L,46890L,46891L,46892L,46893L,46894L, |
| 96774 | 46895L,46896L,46897L,46898L,46899L,46900L,46901L,46902L,46903L,46904L, |
| 96775 | 46905L,46906L,46907L,46908L,46909L,46910L,46911L,46912L,46913L,46914L, |
| 96776 | 46915L,46916L,46917L,46918L,46919L,46920L,46921L,46922L,46923L,46924L, |
| 96777 | 46925L,46926L,46927L,46928L,46929L,46930L,46931L,46932L,46933L,46934L, |
| 96778 | 46935L,46936L,46937L,46938L,46939L,46940L,46941L,46942L,46943L,46944L, |
| 96779 | 46945L,46946L,46947L,46948L,46949L,46950L,46951L,46952L,46953L,46954L, |
| 96780 | 46955L,46956L,46957L,46958L,46959L,46960L,46961L,46962L,46963L,46964L, |
| 96781 | 46965L,46966L,46967L,46968L,46969L,46970L,46971L,46972L,46973L,46974L, |
| 96782 | 46975L,46976L,46977L,46978L,46979L,46980L,46981L,46982L,46983L,46984L, |
| 96783 | 46985L,46986L,46987L,46988L,46989L,46990L,46991L,46992L,46993L,46994L, |
| 96784 | 46995L,46996L,46997L,46998L,46999L,47000L,47001L,47002L,47003L,47004L, |
| 96785 | 47005L,47006L,47007L,47008L,47009L,47010L,47011L,47012L,47013L,47014L, |
| 96786 | 47015L,47016L,47017L,47018L,47019L,47020L,47021L,47022L,47023L,47024L, |
| 96787 | 47025L,47026L,47027L,47028L,47029L,47030L,47031L,47032L,47033L,47034L, |
| 96788 | 47035L,47036L,47037L,47038L,47039L,47040L,47041L,47042L,47043L,47044L, |
| 96789 | 47045L,47046L,47047L,47048L,47049L,47050L,47051L,47052L,47053L,47054L, |
| 96790 | 47055L,47056L,47057L,47058L,47059L,47060L,47061L,47062L,47063L,47064L, |
| 96791 | 47065L,47066L,47067L,47068L,47069L,47070L,47071L,47072L,47073L,47074L, |
| 96792 | 47075L,47076L,47077L,47078L,47079L,47080L,47081L,47082L,47083L,47084L, |
| 96793 | 47085L,47086L,47087L,47088L,47089L,47090L,47091L,47092L,47093L,47094L, |
| 96794 | 47095L,47096L,47097L,47098L,47099L,47100L,47101L,47102L,47103L,47104L, |
| 96795 | 47105L,47106L,47107L,47108L,47109L,47110L,47111L,47112L,47113L,47114L, |
| 96796 | 47115L,47116L,47117L,47118L,47119L,47120L,47121L,47122L,47123L,47124L, |
| 96797 | 47125L,47126L,47127L,47128L,47129L,47130L,47131L,47132L,47133L,47134L, |
| 96798 | 47135L,47136L,47137L,47138L,47139L,47140L,47141L,47142L,47143L,47144L, |
| 96799 | 47145L,47146L,47147L,47148L,47149L,47150L,47151L,47152L,47153L,47154L, |
| 96800 | 47155L,47156L,47157L,47158L,47159L,47160L,47161L,47162L,47163L,47164L, |
| 96801 | 47165L,47166L,47167L,47168L,47169L,47170L,47171L,47172L,47173L,47174L, |
| 96802 | 47175L,47176L,47177L,47178L,47179L,47180L,47181L,47182L,47183L,47184L, |
| 96803 | 47185L,47186L,47187L,47188L,47189L,47190L,47191L,47192L,47193L,47194L, |
| 96804 | 47195L,47196L,47197L,47198L,47199L,47200L,47201L,47202L,47203L,47204L, |
| 96805 | 47205L,47206L,47207L,47208L,47209L,47210L,47211L,47212L,47213L,47214L, |
| 96806 | 47215L,47216L,47217L,47218L,47219L,47220L,47221L,47222L,47223L,47224L, |
| 96807 | 47225L,47226L,47227L,47228L,47229L,47230L,47231L,47232L,47233L,47234L, |
| 96808 | 47235L,47236L,47237L,47238L,47239L,47240L,47241L,47242L,47243L,47244L, |
| 96809 | 47245L,47246L,47247L,47248L,47249L,47250L,47251L,47252L,47253L,47254L, |
| 96810 | 47255L,47256L,47257L,47258L,47259L,47260L,47261L,47262L,47263L,47264L, |
| 96811 | 47265L,47266L,47267L,47268L,47269L,47270L,47271L,47272L,47273L,47274L, |
| 96812 | 47275L,47276L,47277L,47278L,47279L,47280L,47281L,47282L,47283L,47284L, |
| 96813 | 47285L,47286L,47287L,47288L,47289L,47290L,47291L,47292L,47293L,47294L, |
| 96814 | 47295L,47296L,47297L,47298L,47299L,47300L,47301L,47302L,47303L,47304L, |
| 96815 | 47305L,47306L,47307L,47308L,47309L,47310L,47311L,47312L,47313L,47314L, |
| 96816 | 47315L,47316L,47317L,47318L,47319L,47320L,47321L,47322L,47323L,47324L, |
| 96817 | 47325L,47326L,47327L,47328L,47329L,47330L,47331L,47332L,47333L,47334L, |
| 96818 | 47335L,47336L,47337L,47338L,47339L,47340L,47341L,47342L,47343L,47344L, |
| 96819 | 47345L,47346L,47347L,47348L,47349L,47350L,47351L,47352L,47353L,47354L, |
| 96820 | 47355L,47356L,47357L,47358L,47359L,47360L,47361L,47362L,47363L,47364L, |
| 96821 | 47365L,47366L,47367L,47368L,47369L,47370L,47371L,47372L,47373L,47374L, |
| 96822 | 47375L,47376L,47377L,47378L,47379L,47380L,47381L,47382L,47383L,47384L, |
| 96823 | 47385L,47386L,47387L,47388L,47389L,47390L,47391L,47392L,47393L,47394L, |
| 96824 | 47395L,47396L,47397L,47398L,47399L,47400L,47401L,47402L,47403L,47404L, |
| 96825 | 47405L,47406L,47407L,47408L,47409L,47410L,47411L,47412L,47413L,47414L, |
| 96826 | 47415L,47416L,47417L,47418L,47419L,47420L,47421L,47422L,47423L,47424L, |
| 96827 | 47425L,47426L,47427L,47428L,47429L,47430L,47431L,47432L,47433L,47434L, |
| 96828 | 47435L,47436L,47437L,47438L,47439L,47440L,47441L,47442L,47443L,47444L, |
| 96829 | 47445L,47446L,47447L,47448L,47449L,47450L,47451L,47452L,47453L,47454L, |
| 96830 | 47455L,47456L,47457L,47458L,47459L,47460L,47461L,47462L,47463L,47464L, |
| 96831 | 47465L,47466L,47467L,47468L,47469L,47470L,47471L,47472L,47473L,47474L, |
| 96832 | 47475L,47476L,47477L,47478L,47479L,47480L,47481L,47482L,47483L,47484L, |
| 96833 | 47485L,47486L,47487L,47488L,47489L,47490L,47491L,47492L,47493L,47494L, |
| 96834 | 47495L,47496L,47497L,47498L,47499L,47500L,47501L,47502L,47503L,47504L, |
| 96835 | 47505L,47506L,47507L,47508L,47509L,47510L,47511L,47512L,47513L,47514L, |
| 96836 | 47515L,47516L,47517L,47518L,47519L,47520L,47521L,47522L,47523L,47524L, |
| 96837 | 47525L,47526L,47527L,47528L,47529L,47530L,47531L,47532L,47533L,47534L, |
| 96838 | 47535L,47536L,47537L,47538L,47539L,47540L,47541L,47542L,47543L,47544L, |
| 96839 | 47545L,47546L,47547L,47548L,47549L,47550L,47551L,47552L,47553L,47554L, |
| 96840 | 47555L,47556L,47557L,47558L,47559L,47560L,47561L,47562L,47563L,47564L, |
| 96841 | 47565L,47566L,47567L,47568L,47569L,47570L,47571L,47572L,47573L,47574L, |
| 96842 | 47575L,47576L,47577L,47578L,47579L,47580L,47581L,47582L,47583L,47584L, |
| 96843 | 47585L,47586L,47587L,47588L,47589L,47590L,47591L,47592L,47593L,47594L, |
| 96844 | 47595L,47596L,47597L,47598L,47599L,47600L,47601L,47602L,47603L,47604L, |
| 96845 | 47605L,47606L,47607L,47608L,47609L,47610L,47611L,47612L,47613L,47614L, |
| 96846 | 47615L,47616L,47617L,47618L,47619L,47620L,47621L,47622L,47623L,47624L, |
| 96847 | 47625L,47626L,47627L,47628L,47629L,47630L,47631L,47632L,47633L,47634L, |
| 96848 | 47635L,47636L,47637L,47638L,47639L,47640L,47641L,47642L,47643L,47644L, |
| 96849 | 47645L,47646L,47647L,47648L,47649L,47650L,47651L,47652L,47653L,47654L, |
| 96850 | 47655L,47656L,47657L,47658L,47659L,47660L,47661L,47662L,47663L,47664L, |
| 96851 | 47665L,47666L,47667L,47668L,47669L,47670L,47671L,47672L,47673L,47674L, |
| 96852 | 47675L,47676L,47677L,47678L,47679L,47680L,47681L,47682L,47683L,47684L, |
| 96853 | 47685L,47686L,47687L,47688L,47689L,47690L,47691L,47692L,47693L,47694L, |
| 96854 | 47695L,47696L,47697L,47698L,47699L,47700L,47701L,47702L,47703L,47704L, |
| 96855 | 47705L,47706L,47707L,47708L,47709L,47710L,47711L,47712L,47713L,47714L, |
| 96856 | 47715L,47716L,47717L,47718L,47719L,47720L,47721L,47722L,47723L,47724L, |
| 96857 | 47725L,47726L,47727L,47728L,47729L,47730L,47731L,47732L,47733L,47734L, |
| 96858 | 47735L,47736L,47737L,47738L,47739L,47740L,47741L,47742L,47743L,47744L, |
| 96859 | 47745L,47746L,47747L,47748L,47749L,47750L,47751L,47752L,47753L,47754L, |
| 96860 | 47755L,47756L,47757L,47758L,47759L,47760L,47761L,47762L,47763L,47764L, |
| 96861 | 47765L,47766L,47767L,47768L,47769L,47770L,47771L,47772L,47773L,47774L, |
| 96862 | 47775L,47776L,47777L,47778L,47779L,47780L,47781L,47782L,47783L,47784L, |
| 96863 | 47785L,47786L,47787L,47788L,47789L,47790L,47791L,47792L,47793L,47794L, |
| 96864 | 47795L,47796L,47797L,47798L,47799L,47800L,47801L,47802L,47803L,47804L, |
| 96865 | 47805L,47806L,47807L,47808L,47809L,47810L,47811L,47812L,47813L,47814L, |
| 96866 | 47815L,47816L,47817L,47818L,47819L,47820L,47821L,47822L,47823L,47824L, |
| 96867 | 47825L,47826L,47827L,47828L,47829L,47830L,47831L,47832L,47833L,47834L, |
| 96868 | 47835L,47836L,47837L,47838L,47839L,47840L,47841L,47842L,47843L,47844L, |
| 96869 | 47845L,47846L,47847L,47848L,47849L,47850L,47851L,47852L,47853L,47854L, |
| 96870 | 47855L,47856L,47857L,47858L,47859L,47860L,47861L,47862L,47863L,47864L, |
| 96871 | 47865L,47866L,47867L,47868L,47869L,47870L,47871L,47872L,47873L,47874L, |
| 96872 | 47875L,47876L,47877L,47878L,47879L,47880L,47881L,47882L,47883L,47884L, |
| 96873 | 47885L,47886L,47887L,47888L,47889L,47890L,47891L,47892L,47893L,47894L, |
| 96874 | 47895L,47896L,47897L,47898L,47899L,47900L,47901L,47902L,47903L,47904L, |
| 96875 | 47905L,47906L,47907L,47908L,47909L,47910L,47911L,47912L,47913L,47914L, |
| 96876 | 47915L,47916L,47917L,47918L,47919L,47920L,47921L,47922L,47923L,47924L, |
| 96877 | 47925L,47926L,47927L,47928L,47929L,47930L,47931L,47932L,47933L,47934L, |
| 96878 | 47935L,47936L,47937L,47938L,47939L,47940L,47941L,47942L,47943L,47944L, |
| 96879 | 47945L,47946L,47947L,47948L,47949L,47950L,47951L,47952L,47953L,47954L, |
| 96880 | 47955L,47956L,47957L,47958L,47959L,47960L,47961L,47962L,47963L,47964L, |
| 96881 | 47965L,47966L,47967L,47968L,47969L,47970L,47971L,47972L,47973L,47974L, |
| 96882 | 47975L,47976L,47977L,47978L,47979L,47980L,47981L,47982L,47983L,47984L, |
| 96883 | 47985L,47986L,47987L,47988L,47989L,47990L,47991L,47992L,47993L,47994L, |
| 96884 | 47995L,47996L,47997L,47998L,47999L,48000L,48001L,48002L,48003L,48004L, |
| 96885 | 48005L,48006L,48007L,48008L,48009L,48010L,48011L,48012L,48013L,48014L, |
| 96886 | 48015L,48016L,48017L,48018L,48019L,48020L,48021L,48022L,48023L,48024L, |
| 96887 | 48025L,48026L,48027L,48028L,48029L,48030L,48031L,48032L,48033L,48034L, |
| 96888 | 48035L,48036L,48037L,48038L,48039L,48040L,48041L,48042L,48043L,48044L, |
| 96889 | 48045L,48046L,48047L,48048L,48049L,48050L,48051L,48052L,48053L,48054L, |
| 96890 | 48055L,48056L,48057L,48058L,48059L,48060L,48061L,48062L,48063L,48064L, |
| 96891 | 48065L,48066L,48067L,48068L,48069L,48070L,48071L,48072L,48073L,48074L, |
| 96892 | 48075L,48076L,48077L,48078L,48079L,48080L,48081L,48082L,48083L,48084L, |
| 96893 | 48085L,48086L,48087L,48088L,48089L,48090L,48091L,48092L,48093L,48094L, |
| 96894 | 48095L,48096L,48097L,48098L,48099L,48100L,48101L,48102L,48103L,48104L, |
| 96895 | 48105L,48106L,48107L,48108L,48109L,48110L,48111L,48112L,48113L,48114L, |
| 96896 | 48115L,48116L,48117L,48118L,48119L,48120L,48121L,48122L,48123L,48124L, |
| 96897 | 48125L,48126L,48127L,48128L,48129L,48130L,48131L,48132L,48133L,48134L, |
| 96898 | 48135L,48136L,48137L,48138L,48139L,48140L,48141L,48142L,48143L,48144L, |
| 96899 | 48145L,48146L,48147L,48148L,48149L,48150L,48151L,48152L,48153L,48154L, |
| 96900 | 48155L,48156L,48157L,48158L,48159L,48160L,48161L,48162L,48163L,48164L, |
| 96901 | 48165L,48166L,48167L,48168L,48169L,48170L,48171L,48172L,48173L,48174L, |
| 96902 | 48175L,48176L,48177L,48178L,48179L,48180L,48181L,48182L,48183L,48184L, |
| 96903 | 48185L,48186L,48187L,48188L,48189L,48190L,48191L,48192L,48193L,48194L, |
| 96904 | 48195L,48196L,48197L,48198L,48199L,48200L,48201L,48202L,48203L,48204L, |
| 96905 | 48205L,48206L,48207L,48208L,48209L,48210L,48211L,48212L,48213L,48214L, |
| 96906 | 48215L,48216L,48217L,48218L,48219L,48220L,48221L,48222L,48223L,48224L, |
| 96907 | 48225L,48226L,48227L,48228L,48229L,48230L,48231L,48232L,48233L,48234L, |
| 96908 | 48235L,48236L,48237L,48238L,48239L,48240L,48241L,48242L,48243L,48244L, |
| 96909 | 48245L,48246L,48247L,48248L,48249L,48250L,48251L,48252L,48253L,48254L, |
| 96910 | 48255L,48256L,48257L,48258L,48259L,48260L,48261L,48262L,48263L,48264L, |
| 96911 | 48265L,48266L,48267L,48268L,48269L,48270L,48271L,48272L,48273L,48274L, |
| 96912 | 48275L,48276L,48277L,48278L,48279L,48280L,48281L,48282L,48283L,48284L, |
| 96913 | 48285L,48286L,48287L,48288L,48289L,48290L,48291L,48292L,48293L,48294L, |
| 96914 | 48295L,48296L,48297L,48298L,48299L,48300L,48301L,48302L,48303L,48304L, |
| 96915 | 48305L,48306L,48307L,48308L,48309L,48310L,48311L,48312L,48313L,48314L, |
| 96916 | 48315L,48316L,48317L,48318L,48319L,48320L,48321L,48322L,48323L,48324L, |
| 96917 | 48325L,48326L,48327L,48328L,48329L,48330L,48331L,48332L,48333L,48334L, |
| 96918 | 48335L,48336L,48337L,48338L,48339L,48340L,48341L,48342L,48343L,48344L, |
| 96919 | 48345L,48346L,48347L,48348L,48349L,48350L,48351L,48352L,48353L,48354L, |
| 96920 | 48355L,48356L,48357L,48358L,48359L,48360L,48361L,48362L,48363L,48364L, |
| 96921 | 48365L,48366L,48367L,48368L,48369L,48370L,48371L,48372L,48373L,48374L, |
| 96922 | 48375L,48376L,48377L,48378L,48379L,48380L,48381L,48382L,48383L,48384L, |
| 96923 | 48385L,48386L,48387L,48388L,48389L,48390L,48391L,48392L,48393L,48394L, |
| 96924 | 48395L,48396L,48397L,48398L,48399L,48400L,48401L,48402L,48403L,48404L, |
| 96925 | 48405L,48406L,48407L,48408L,48409L,48410L,48411L,48412L,48413L,48414L, |
| 96926 | 48415L,48416L,48417L,48418L,48419L,48420L,48421L,48422L,48423L,48424L, |
| 96927 | 48425L,48426L,48427L,48428L,48429L,48430L,48431L,48432L,48433L,48434L, |
| 96928 | 48435L,48436L,48437L,48438L,48439L,48440L,48441L,48442L,48443L,48444L, |
| 96929 | 48445L,48446L,48447L,48448L,48449L,48450L,48451L,48452L,48453L,48454L, |
| 96930 | 48455L,48456L,48457L,48458L,48459L,48460L,48461L,48462L,48463L,48464L, |
| 96931 | 48465L,48466L,48467L,48468L,48469L,48470L,48471L,48472L,48473L,48474L, |
| 96932 | 48475L,48476L,48477L,48478L,48479L,48480L,48481L,48482L,48483L,48484L, |
| 96933 | 48485L,48486L,48487L,48488L,48489L,48490L,48491L,48492L,48493L,48494L, |
| 96934 | 48495L,48496L,48497L,48498L,48499L,48500L,48501L,48502L,48503L,48504L, |
| 96935 | 48505L,48506L,48507L,48508L,48509L,48510L,48511L,48512L,48513L,48514L, |
| 96936 | 48515L,48516L,48517L,48518L,48519L,48520L,48521L,48522L,48523L,48524L, |
| 96937 | 48525L,48526L,48527L,48528L,48529L,48530L,48531L,48532L,48533L,48534L, |
| 96938 | 48535L,48536L,48537L,48538L,48539L,48540L,48541L,48542L,48543L,48544L, |
| 96939 | 48545L,48546L,48547L,48548L,48549L,48550L,48551L,48552L,48553L,48554L, |
| 96940 | 48555L,48556L,48557L,48558L,48559L,48560L,48561L,48562L,48563L,48564L, |
| 96941 | 48565L,48566L,48567L,48568L,48569L,48570L,48571L,48572L,48573L,48574L, |
| 96942 | 48575L,48576L,48577L,48578L,48579L,48580L,48581L,48582L,48583L,48584L, |
| 96943 | 48585L,48586L,48587L,48588L,48589L,48590L,48591L,48592L,48593L,48594L, |
| 96944 | 48595L,48596L,48597L,48598L,48599L,48600L,48601L,48602L,48603L,48604L, |
| 96945 | 48605L,48606L,48607L,48608L,48609L,48610L,48611L,48612L,48613L,48614L, |
| 96946 | 48615L,48616L,48617L,48618L,48619L,48620L,48621L,48622L,48623L,48624L, |
| 96947 | 48625L,48626L,48627L,48628L,48629L,48630L,48631L,48632L,48633L,48634L, |
| 96948 | 48635L,48636L,48637L,48638L,48639L,48640L,48641L,48642L,48643L,48644L, |
| 96949 | 48645L,48646L,48647L,48648L,48649L,48650L,48651L,48652L,48653L,48654L, |
| 96950 | 48655L,48656L,48657L,48658L,48659L,48660L,48661L,48662L,48663L,48664L, |
| 96951 | 48665L,48666L,48667L,48668L,48669L,48670L,48671L,48672L,48673L,48674L, |
| 96952 | 48675L,48676L,48677L,48678L,48679L,48680L,48681L,48682L,48683L,48684L, |
| 96953 | 48685L,48686L,48687L,48688L,48689L,48690L,48691L,48692L,48693L,48694L, |
| 96954 | 48695L,48696L,48697L,48698L,48699L,48700L,48701L,48702L,48703L,48704L, |
| 96955 | 48705L,48706L,48707L,48708L,48709L,48710L,48711L,48712L,48713L,48714L, |
| 96956 | 48715L,48716L,48717L,48718L,48719L,48720L,48721L,48722L,48723L,48724L, |
| 96957 | 48725L,48726L,48727L,48728L,48729L,48730L,48731L,48732L,48733L,48734L, |
| 96958 | 48735L,48736L,48737L,48738L,48739L,48740L,48741L,48742L,48743L,48744L, |
| 96959 | 48745L,48746L,48747L,48748L,48749L,48750L,48751L,48752L,48753L,48754L, |
| 96960 | 48755L,48756L,48757L,48758L,48759L,48760L,48761L,48762L,48763L,48764L, |
| 96961 | 48765L,48766L,48767L,48768L,48769L,48770L,48771L,48772L,48773L,48774L, |
| 96962 | 48775L,48776L,48777L,48778L,48779L,48780L,48781L,48782L,48783L,48784L, |
| 96963 | 48785L,48786L,48787L,48788L,48789L,48790L,48791L,48792L,48793L,48794L, |
| 96964 | 48795L,48796L,48797L,48798L,48799L,48800L,48801L,48802L,48803L,48804L, |
| 96965 | 48805L,48806L,48807L,48808L,48809L,48810L,48811L,48812L,48813L,48814L, |
| 96966 | 48815L,48816L,48817L,48818L,48819L,48820L,48821L,48822L,48823L,48824L, |
| 96967 | 48825L,48826L,48827L,48828L,48829L,48830L,48831L,48832L,48833L,48834L, |
| 96968 | 48835L,48836L,48837L,48838L,48839L,48840L,48841L,48842L,48843L,48844L, |
| 96969 | 48845L,48846L,48847L,48848L,48849L,48850L,48851L,48852L,48853L,48854L, |
| 96970 | 48855L,48856L,48857L,48858L,48859L,48860L,48861L,48862L,48863L,48864L, |
| 96971 | 48865L,48866L,48867L,48868L,48869L,48870L,48871L,48872L,48873L,48874L, |
| 96972 | 48875L,48876L,48877L,48878L,48879L,48880L,48881L,48882L,48883L,48884L, |
| 96973 | 48885L,48886L,48887L,48888L,48889L,48890L,48891L,48892L,48893L,48894L, |
| 96974 | 48895L,48896L,48897L,48898L,48899L,48900L,48901L,48902L,48903L,48904L, |
| 96975 | 48905L,48906L,48907L,48908L,48909L,48910L,48911L,48912L,48913L,48914L, |
| 96976 | 48915L,48916L,48917L,48918L,48919L,48920L,48921L,48922L,48923L,48924L, |
| 96977 | 48925L,48926L,48927L,48928L,48929L,48930L,48931L,48932L,48933L,48934L, |
| 96978 | 48935L,48936L,48937L,48938L,48939L,48940L,48941L,48942L,48943L,48944L, |
| 96979 | 48945L,48946L,48947L,48948L,48949L,48950L,48951L,48952L,48953L,48954L, |
| 96980 | 48955L,48956L,48957L,48958L,48959L,48960L,48961L,48962L,48963L,48964L, |
| 96981 | 48965L,48966L,48967L,48968L,48969L,48970L,48971L,48972L,48973L,48974L, |
| 96982 | 48975L,48976L,48977L,48978L,48979L,48980L,48981L,48982L,48983L,48984L, |
| 96983 | 48985L,48986L,48987L,48988L,48989L,48990L,48991L,48992L,48993L,48994L, |
| 96984 | 48995L,48996L,48997L,48998L,48999L,49000L,49001L,49002L,49003L,49004L, |
| 96985 | 49005L,49006L,49007L,49008L,49009L,49010L,49011L,49012L,49013L,49014L, |
| 96986 | 49015L,49016L,49017L,49018L,49019L,49020L,49021L,49022L,49023L,49024L, |
| 96987 | 49025L,49026L,49027L,49028L,49029L,49030L,49031L,49032L,49033L,49034L, |
| 96988 | 49035L,49036L,49037L,49038L,49039L,49040L,49041L,49042L,49043L,49044L, |
| 96989 | 49045L,49046L,49047L,49048L,49049L,49050L,49051L,49052L,49053L,49054L, |
| 96990 | 49055L,49056L,49057L,49058L,49059L,49060L,49061L,49062L,49063L,49064L, |
| 96991 | 49065L,49066L,49067L,49068L,49069L,49070L,49071L,49072L,49073L,49074L, |
| 96992 | 49075L,49076L,49077L,49078L,49079L,49080L,49081L,49082L,49083L,49084L, |
| 96993 | 49085L,49086L,49087L,49088L,49089L,49090L,49091L,49092L,49093L,49094L, |
| 96994 | 49095L,49096L,49097L,49098L,49099L,49100L,49101L,49102L,49103L,49104L, |
| 96995 | 49105L,49106L,49107L,49108L,49109L,49110L,49111L,49112L,49113L,49114L, |
| 96996 | 49115L,49116L,49117L,49118L,49119L,49120L,49121L,49122L,49123L,49124L, |
| 96997 | 49125L,49126L,49127L,49128L,49129L,49130L,49131L,49132L,49133L,49134L, |
| 96998 | 49135L,49136L,49137L,49138L,49139L,49140L,49141L,49142L,49143L,49144L, |
| 96999 | 49145L,49146L,49147L,49148L,49149L,49150L,49151L,49152L,49153L,49154L, |
| 97000 | 49155L,49156L,49157L,49158L,49159L,49160L,49161L,49162L,49163L,49164L, |
| 97001 | 49165L,49166L,49167L,49168L,49169L,49170L,49171L,49172L,49173L,49174L, |
| 97002 | 49175L,49176L,49177L,49178L,49179L,49180L,49181L,49182L,49183L,49184L, |
| 97003 | 49185L,49186L,49187L,49188L,49189L,49190L,49191L,49192L,49193L,49194L, |
| 97004 | 49195L,49196L,49197L,49198L,49199L,49200L,49201L,49202L,49203L,49204L, |
| 97005 | 49205L,49206L,49207L,49208L,49209L,49210L,49211L,49212L,49213L,49214L, |
| 97006 | 49215L,49216L,49217L,49218L,49219L,49220L,49221L,49222L,49223L,49224L, |
| 97007 | 49225L,49226L,49227L,49228L,49229L,49230L,49231L,49232L,49233L,49234L, |
| 97008 | 49235L,49236L,49237L,49238L,49239L,49240L,49241L,49242L,49243L,49244L, |
| 97009 | 49245L,49246L,49247L,49248L,49249L,49250L,49251L,49252L,49253L,49254L, |
| 97010 | 49255L,49256L,49257L,49258L,49259L,49260L,49261L,49262L,49263L,49264L, |
| 97011 | 49265L,49266L,49267L,49268L,49269L,49270L,49271L,49272L,49273L,49274L, |
| 97012 | 49275L,49276L,49277L,49278L,49279L,49280L,49281L,49282L,49283L,49284L, |
| 97013 | 49285L,49286L,49287L,49288L,49289L,49290L,49291L,49292L,49293L,49294L, |
| 97014 | 49295L,49296L,49297L,49298L,49299L,49300L,49301L,49302L,49303L,49304L, |
| 97015 | 49305L,49306L,49307L,49308L,49309L,49310L,49311L,49312L,49313L,49314L, |
| 97016 | 49315L,49316L,49317L,49318L,49319L,49320L,49321L,49322L,49323L,49324L, |
| 97017 | 49325L,49326L,49327L,49328L,49329L,49330L,49331L,49332L,49333L,49334L, |
| 97018 | 49335L,49336L,49337L,49338L,49339L,49340L,49341L,49342L,49343L,49344L, |
| 97019 | 49345L,49346L,49347L,49348L,49349L,49350L,49351L,49352L,49353L,49354L, |
| 97020 | 49355L,49356L,49357L,49358L,49359L,49360L,49361L,49362L,49363L,49364L, |
| 97021 | 49365L,49366L,49367L,49368L,49369L,49370L,49371L,49372L,49373L,49374L, |
| 97022 | 49375L,49376L,49377L,49378L,49379L,49380L,49381L,49382L,49383L,49384L, |
| 97023 | 49385L,49386L,49387L,49388L,49389L,49390L,49391L,49392L,49393L,49394L, |
| 97024 | 49395L,49396L,49397L,49398L,49399L,49400L,49401L,49402L,49403L,49404L, |
| 97025 | 49405L,49406L,49407L,49408L,49409L,49410L,49411L,49412L,49413L,49414L, |
| 97026 | 49415L,49416L,49417L,49418L,49419L,49420L,49421L,49422L,49423L,49424L, |
| 97027 | 49425L,49426L,49427L,49428L,49429L,49430L,49431L,49432L,49433L,49434L, |
| 97028 | 49435L,49436L,49437L,49438L,49439L,49440L,49441L,49442L,49443L,49444L, |
| 97029 | 49445L,49446L,49447L,49448L,49449L,49450L,49451L,49452L,49453L,49454L, |
| 97030 | 49455L,49456L,49457L,49458L,49459L,49460L,49461L,49462L,49463L,49464L, |
| 97031 | 49465L,49466L,49467L,49468L,49469L,49470L,49471L,49472L,49473L,49474L, |
| 97032 | 49475L,49476L,49477L,49478L,49479L,49480L,49481L,49482L,49483L,49484L, |
| 97033 | 49485L,49486L,49487L,49488L,49489L,49490L,49491L,49492L,49493L,49494L, |
| 97034 | 49495L,49496L,49497L,49498L,49499L,49500L,49501L,49502L,49503L,49504L, |
| 97035 | 49505L,49506L,49507L,49508L,49509L,49510L,49511L,49512L,49513L,49514L, |
| 97036 | 49515L,49516L,49517L,49518L,49519L,49520L,49521L,49522L,49523L,49524L, |
| 97037 | 49525L,49526L,49527L,49528L,49529L,49530L,49531L,49532L,49533L,49534L, |
| 97038 | 49535L,49536L,49537L,49538L,49539L,49540L,49541L,49542L,49543L,49544L, |
| 97039 | 49545L,49546L,49547L,49548L,49549L,49550L,49551L,49552L,49553L,49554L, |
| 97040 | 49555L,49556L,49557L,49558L,49559L,49560L,49561L,49562L,49563L,49564L, |
| 97041 | 49565L,49566L,49567L,49568L,49569L,49570L,49571L,49572L,49573L,49574L, |
| 97042 | 49575L,49576L,49577L,49578L,49579L,49580L,49581L,49582L,49583L,49584L, |
| 97043 | 49585L,49586L,49587L,49588L,49589L,49590L,49591L,49592L,49593L,49594L, |
| 97044 | 49595L,49596L,49597L,49598L,49599L,49600L,49601L,49602L,49603L,49604L, |
| 97045 | 49605L,49606L,49607L,49608L,49609L,49610L,49611L,49612L,49613L,49614L, |
| 97046 | 49615L,49616L,49617L,49618L,49619L,49620L,49621L,49622L,49623L,49624L, |
| 97047 | 49625L,49626L,49627L,49628L,49629L,49630L,49631L,49632L,49633L,49634L, |
| 97048 | 49635L,49636L,49637L,49638L,49639L,49640L,49641L,49642L,49643L,49644L, |
| 97049 | 49645L,49646L,49647L,49648L,49649L,49650L,49651L,49652L,49653L,49654L, |
| 97050 | 49655L,49656L,49657L,49658L,49659L,49660L,49661L,49662L,49663L,49664L, |
| 97051 | 49665L,49666L,49667L,49668L,49669L,49670L,49671L,49672L,49673L,49674L, |
| 97052 | 49675L,49676L,49677L,49678L,49679L,49680L,49681L,49682L,49683L,49684L, |
| 97053 | 49685L,49686L,49687L,49688L,49689L,49690L,49691L,49692L,49693L,49694L, |
| 97054 | 49695L,49696L,49697L,49698L,49699L,49700L,49701L,49702L,49703L,49704L, |
| 97055 | 49705L,49706L,49707L,49708L,49709L,49710L,49711L,49712L,49713L,49714L, |
| 97056 | 49715L,49716L,49717L,49718L,49719L,49720L,49721L,49722L,49723L,49724L, |
| 97057 | 49725L,49726L,49727L,49728L,49729L,49730L,49731L,49732L,49733L,49734L, |
| 97058 | 49735L,49736L,49737L,49738L,49739L,49740L,49741L,49742L,49743L,49744L, |
| 97059 | 49745L,49746L,49747L,49748L,49749L,49750L,49751L,49752L,49753L,49754L, |
| 97060 | 49755L,49756L,49757L,49758L,49759L,49760L,49761L,49762L,49763L,49764L, |
| 97061 | 49765L,49766L,49767L,49768L,49769L,49770L,49771L,49772L,49773L,49774L, |
| 97062 | 49775L,49776L,49777L,49778L,49779L,49780L,49781L,49782L,49783L,49784L, |
| 97063 | 49785L,49786L,49787L,49788L,49789L,49790L,49791L,49792L,49793L,49794L, |
| 97064 | 49795L,49796L,49797L,49798L,49799L,49800L,49801L,49802L,49803L,49804L, |
| 97065 | 49805L,49806L,49807L,49808L,49809L,49810L,49811L,49812L,49813L,49814L, |
| 97066 | 49815L,49816L,49817L,49818L,49819L,49820L,49821L,49822L,49823L,49824L, |
| 97067 | 49825L,49826L,49827L,49828L,49829L,49830L,49831L,49832L,49833L,49834L, |
| 97068 | 49835L,49836L,49837L,49838L,49839L,49840L,49841L,49842L,49843L,49844L, |
| 97069 | 49845L,49846L,49847L,49848L,49849L,49850L,49851L,49852L,49853L,49854L, |
| 97070 | 49855L,49856L,49857L,49858L,49859L,49860L,49861L,49862L,49863L,49864L, |
| 97071 | 49865L,49866L,49867L,49868L,49869L,49870L,49871L,49872L,49873L,49874L, |
| 97072 | 49875L,49876L,49877L,49878L,49879L,49880L,49881L,49882L,49883L,49884L, |
| 97073 | 49885L,49886L,49887L,49888L,49889L,49890L,49891L,49892L,49893L,49894L, |
| 97074 | 49895L,49896L,49897L,49898L,49899L,49900L,49901L,49902L,49903L,49904L, |
| 97075 | 49905L,49906L,49907L,49908L,49909L,49910L,49911L,49912L,49913L,49914L, |
| 97076 | 49915L,49916L,49917L,49918L,49919L,49920L,49921L,49922L,49923L,49924L, |
| 97077 | 49925L,49926L,49927L,49928L,49929L,49930L,49931L,49932L,49933L,49934L, |
| 97078 | 49935L,49936L,49937L,49938L,49939L,49940L,49941L,49942L,49943L,49944L, |
| 97079 | 49945L,49946L,49947L,49948L,49949L,49950L,49951L,49952L,49953L,49954L, |
| 97080 | 49955L,49956L,49957L,49958L,49959L,49960L,49961L,49962L,49963L,49964L, |
| 97081 | 49965L,49966L,49967L,49968L,49969L,49970L,49971L,49972L,49973L,49974L, |
| 97082 | 49975L,49976L,49977L,49978L,49979L,49980L,49981L,49982L,49983L,49984L, |
| 97083 | 49985L,49986L,49987L,49988L,49989L,49990L,49991L,49992L,49993L,49994L, |
| 97084 | 49995L,49996L,49997L,49998L,49999L,50000L,50001L,50002L,50003L,50004L, |
| 97085 | 50005L,50006L,50007L,50008L,50009L,50010L,50011L,50012L,50013L,50014L, |
| 97086 | 50015L,50016L,50017L,50018L,50019L,50020L,50021L,50022L,50023L,50024L, |
| 97087 | 50025L,50026L,50027L,50028L,50029L,50030L,50031L,50032L,50033L,50034L, |
| 97088 | 50035L,50036L,50037L,50038L,50039L,50040L,50041L,50042L,50043L,50044L, |
| 97089 | 50045L,50046L,50047L,50048L,50049L,50050L,50051L,50052L,50053L,50054L, |
| 97090 | 50055L,50056L,50057L,50058L,50059L,50060L,50061L,50062L,50063L,50064L, |
| 97091 | 50065L,50066L,50067L,50068L,50069L,50070L,50071L,50072L,50073L,50074L, |
| 97092 | 50075L,50076L,50077L,50078L,50079L,50080L,50081L,50082L,50083L,50084L, |
| 97093 | 50085L,50086L,50087L,50088L,50089L,50090L,50091L,50092L,50093L,50094L, |
| 97094 | 50095L,50096L,50097L,50098L,50099L,50100L,50101L,50102L,50103L,50104L, |
| 97095 | 50105L,50106L,50107L,50108L,50109L,50110L,50111L,50112L,50113L,50114L, |
| 97096 | 50115L,50116L,50117L,50118L,50119L,50120L,50121L,50122L,50123L,50124L, |
| 97097 | 50125L,50126L,50127L,50128L,50129L,50130L,50131L,50132L,50133L,50134L, |
| 97098 | 50135L,50136L,50137L,50138L,50139L,50140L,50141L,50142L,50143L,50144L, |
| 97099 | 50145L,50146L,50147L,50148L,50149L,50150L,50151L,50152L,50153L,50154L, |
| 97100 | 50155L,50156L,50157L,50158L,50159L,50160L,50161L,50162L,50163L,50164L, |
| 97101 | 50165L,50166L,50167L,50168L,50169L,50170L,50171L,50172L,50173L,50174L, |
| 97102 | 50175L,50176L,50177L,50178L,50179L,50180L,50181L,50182L,50183L,50184L, |
| 97103 | 50185L,50186L,50187L,50188L,50189L,50190L,50191L,50192L,50193L,50194L, |
| 97104 | 50195L,50196L,50197L,50198L,50199L,50200L,50201L,50202L,50203L,50204L, |
| 97105 | 50205L,50206L,50207L,50208L,50209L,50210L,50211L,50212L,50213L,50214L, |
| 97106 | 50215L,50216L,50217L,50218L,50219L,50220L,50221L,50222L,50223L,50224L, |
| 97107 | 50225L,50226L,50227L,50228L,50229L,50230L,50231L,50232L,50233L,50234L, |
| 97108 | 50235L,50236L,50237L,50238L,50239L,50240L,50241L,50242L,50243L,50244L, |
| 97109 | 50245L,50246L,50247L,50248L,50249L,50250L,50251L,50252L,50253L,50254L, |
| 97110 | 50255L,50256L,50257L,50258L,50259L,50260L,50261L,50262L,50263L,50264L, |
| 97111 | 50265L,50266L,50267L,50268L,50269L,50270L,50271L,50272L,50273L,50274L, |
| 97112 | 50275L,50276L,50277L,50278L,50279L,50280L,50281L,50282L,50283L,50284L, |
| 97113 | 50285L,50286L,50287L,50288L,50289L,50290L,50291L,50292L,50293L,50294L, |
| 97114 | 50295L,50296L,50297L,50298L,50299L,50300L,50301L,50302L,50303L,50304L, |
| 97115 | 50305L,50306L,50307L,50308L,50309L,50310L,50311L,50312L,50313L,50314L, |
| 97116 | 50315L,50316L,50317L,50318L,50319L,50320L,50321L,50322L,50323L,50324L, |
| 97117 | 50325L,50326L,50327L,50328L,50329L,50330L,50331L,50332L,50333L,50334L, |
| 97118 | 50335L,50336L,50337L,50338L,50339L,50340L,50341L,50342L,50343L,50344L, |
| 97119 | 50345L,50346L,50347L,50348L,50349L,50350L,50351L,50352L,50353L,50354L, |
| 97120 | 50355L,50356L,50357L,50358L,50359L,50360L,50361L,50362L,50363L,50364L, |
| 97121 | 50365L,50366L,50367L,50368L,50369L,50370L,50371L,50372L,50373L,50374L, |
| 97122 | 50375L,50376L,50377L,50378L,50379L,50380L,50381L,50382L,50383L,50384L, |
| 97123 | 50385L,50386L,50387L,50388L,50389L,50390L,50391L,50392L,50393L,50394L, |
| 97124 | 50395L,50396L,50397L,50398L,50399L,50400L,50401L,50402L,50403L,50404L, |
| 97125 | 50405L,50406L,50407L,50408L,50409L,50410L,50411L,50412L,50413L,50414L, |
| 97126 | 50415L,50416L,50417L,50418L,50419L,50420L,50421L,50422L,50423L,50424L, |
| 97127 | 50425L,50426L,50427L,50428L,50429L,50430L,50431L,50432L,50433L,50434L, |
| 97128 | 50435L,50436L,50437L,50438L,50439L,50440L,50441L,50442L,50443L,50444L, |
| 97129 | 50445L,50446L,50447L,50448L,50449L,50450L,50451L,50452L,50453L,50454L, |
| 97130 | 50455L,50456L,50457L,50458L,50459L,50460L,50461L,50462L,50463L,50464L, |
| 97131 | 50465L,50466L,50467L,50468L,50469L,50470L,50471L,50472L,50473L,50474L, |
| 97132 | 50475L,50476L,50477L,50478L,50479L,50480L,50481L,50482L,50483L,50484L, |
| 97133 | 50485L,50486L,50487L,50488L,50489L,50490L,50491L,50492L,50493L,50494L, |
| 97134 | 50495L,50496L,50497L,50498L,50499L,50500L,50501L,50502L,50503L,50504L, |
| 97135 | 50505L,50506L,50507L,50508L,50509L,50510L,50511L,50512L,50513L,50514L, |
| 97136 | 50515L,50516L,50517L,50518L,50519L,50520L,50521L,50522L,50523L,50524L, |
| 97137 | 50525L,50526L,50527L,50528L,50529L,50530L,50531L,50532L,50533L,50534L, |
| 97138 | 50535L,50536L,50537L,50538L,50539L,50540L,50541L,50542L,50543L,50544L, |
| 97139 | 50545L,50546L,50547L,50548L,50549L,50550L,50551L,50552L,50553L,50554L, |
| 97140 | 50555L,50556L,50557L,50558L,50559L,50560L,50561L,50562L,50563L,50564L, |
| 97141 | 50565L,50566L,50567L,50568L,50569L,50570L,50571L,50572L,50573L,50574L, |
| 97142 | 50575L,50576L,50577L,50578L,50579L,50580L,50581L,50582L,50583L,50584L, |
| 97143 | 50585L,50586L,50587L,50588L,50589L,50590L,50591L,50592L,50593L,50594L, |
| 97144 | 50595L,50596L,50597L,50598L,50599L,50600L,50601L,50602L,50603L,50604L, |
| 97145 | 50605L,50606L,50607L,50608L,50609L,50610L,50611L,50612L,50613L,50614L, |
| 97146 | 50615L,50616L,50617L,50618L,50619L,50620L,50621L,50622L,50623L,50624L, |
| 97147 | 50625L,50626L,50627L,50628L,50629L,50630L,50631L,50632L,50633L,50634L, |
| 97148 | 50635L,50636L,50637L,50638L,50639L,50640L,50641L,50642L,50643L,50644L, |
| 97149 | 50645L,50646L,50647L,50648L,50649L,50650L,50651L,50652L,50653L,50654L, |
| 97150 | 50655L,50656L,50657L,50658L,50659L,50660L,50661L,50662L,50663L,50664L, |
| 97151 | 50665L,50666L,50667L,50668L,50669L,50670L,50671L,50672L,50673L,50674L, |
| 97152 | 50675L,50676L,50677L,50678L,50679L,50680L,50681L,50682L,50683L,50684L, |
| 97153 | 50685L,50686L,50687L,50688L,50689L,50690L,50691L,50692L,50693L,50694L, |
| 97154 | 50695L,50696L,50697L,50698L,50699L,50700L,50701L,50702L,50703L,50704L, |
| 97155 | 50705L,50706L,50707L,50708L,50709L,50710L,50711L,50712L,50713L,50714L, |
| 97156 | 50715L,50716L,50717L,50718L,50719L,50720L,50721L,50722L,50723L,50724L, |
| 97157 | 50725L,50726L,50727L,50728L,50729L,50730L,50731L,50732L,50733L,50734L, |
| 97158 | 50735L,50736L,50737L,50738L,50739L,50740L,50741L,50742L,50743L,50744L, |
| 97159 | 50745L,50746L,50747L,50748L,50749L,50750L,50751L,50752L,50753L,50754L, |
| 97160 | 50755L,50756L,50757L,50758L,50759L,50760L,50761L,50762L,50763L,50764L, |
| 97161 | 50765L,50766L,50767L,50768L,50769L,50770L,50771L,50772L,50773L,50774L, |
| 97162 | 50775L,50776L,50777L,50778L,50779L,50780L,50781L,50782L,50783L,50784L, |
| 97163 | 50785L,50786L,50787L,50788L,50789L,50790L,50791L,50792L,50793L,50794L, |
| 97164 | 50795L,50796L,50797L,50798L,50799L,50800L,50801L,50802L,50803L,50804L, |
| 97165 | 50805L,50806L,50807L,50808L,50809L,50810L,50811L,50812L,50813L,50814L, |
| 97166 | 50815L,50816L,50817L,50818L,50819L,50820L,50821L,50822L,50823L,50824L, |
| 97167 | 50825L,50826L,50827L,50828L,50829L,50830L,50831L,50832L,50833L,50834L, |
| 97168 | 50835L,50836L,50837L,50838L,50839L,50840L,50841L,50842L,50843L,50844L, |
| 97169 | 50845L,50846L,50847L,50848L,50849L,50850L,50851L,50852L,50853L,50854L, |
| 97170 | 50855L,50856L,50857L,50858L,50859L,50860L,50861L,50862L,50863L,50864L, |
| 97171 | 50865L,50866L,50867L,50868L,50869L,50870L,50871L,50872L,50873L,50874L, |
| 97172 | 50875L,50876L,50877L,50878L,50879L,50880L,50881L,50882L,50883L,50884L, |
| 97173 | 50885L,50886L,50887L,50888L,50889L,50890L,50891L,50892L,50893L,50894L, |
| 97174 | 50895L,50896L,50897L,50898L,50899L,50900L,50901L,50902L,50903L,50904L, |
| 97175 | 50905L,50906L,50907L,50908L,50909L,50910L,50911L,50912L,50913L,50914L, |
| 97176 | 50915L,50916L,50917L,50918L,50919L,50920L,50921L,50922L,50923L,50924L, |
| 97177 | 50925L,50926L,50927L,50928L,50929L,50930L,50931L,50932L,50933L,50934L, |
| 97178 | 50935L,50936L,50937L,50938L,50939L,50940L,50941L,50942L,50943L,50944L, |
| 97179 | 50945L,50946L,50947L,50948L,50949L,50950L,50951L,50952L,50953L,50954L, |
| 97180 | 50955L,50956L,50957L,50958L,50959L,50960L,50961L,50962L,50963L,50964L, |
| 97181 | 50965L,50966L,50967L,50968L,50969L,50970L,50971L,50972L,50973L,50974L, |
| 97182 | 50975L,50976L,50977L,50978L,50979L,50980L,50981L,50982L,50983L,50984L, |
| 97183 | 50985L,50986L,50987L,50988L,50989L,50990L,50991L,50992L,50993L,50994L, |
| 97184 | 50995L,50996L,50997L,50998L,50999L,51000L,51001L,51002L,51003L,51004L, |
| 97185 | 51005L,51006L,51007L,51008L,51009L,51010L,51011L,51012L,51013L,51014L, |
| 97186 | 51015L,51016L,51017L,51018L,51019L,51020L,51021L,51022L,51023L,51024L, |
| 97187 | 51025L,51026L,51027L,51028L,51029L,51030L,51031L,51032L,51033L,51034L, |
| 97188 | 51035L,51036L,51037L,51038L,51039L,51040L,51041L,51042L,51043L,51044L, |
| 97189 | 51045L,51046L,51047L,51048L,51049L,51050L,51051L,51052L,51053L,51054L, |
| 97190 | 51055L,51056L,51057L,51058L,51059L,51060L,51061L,51062L,51063L,51064L, |
| 97191 | 51065L,51066L,51067L,51068L,51069L,51070L,51071L,51072L,51073L,51074L, |
| 97192 | 51075L,51076L,51077L,51078L,51079L,51080L,51081L,51082L,51083L,51084L, |
| 97193 | 51085L,51086L,51087L,51088L,51089L,51090L,51091L,51092L,51093L,51094L, |
| 97194 | 51095L,51096L,51097L,51098L,51099L,51100L,51101L,51102L,51103L,51104L, |
| 97195 | 51105L,51106L,51107L,51108L,51109L,51110L,51111L,51112L,51113L,51114L, |
| 97196 | 51115L,51116L,51117L,51118L,51119L,51120L,51121L,51122L,51123L,51124L, |
| 97197 | 51125L,51126L,51127L,51128L,51129L,51130L,51131L,51132L,51133L,51134L, |
| 97198 | 51135L,51136L,51137L,51138L,51139L,51140L,51141L,51142L,51143L,51144L, |
| 97199 | 51145L,51146L,51147L,51148L,51149L,51150L,51151L,51152L,51153L,51154L, |
| 97200 | 51155L,51156L,51157L,51158L,51159L,51160L,51161L,51162L,51163L,51164L, |
| 97201 | 51165L,51166L,51167L,51168L,51169L,51170L,51171L,51172L,51173L,51174L, |
| 97202 | 51175L,51176L,51177L,51178L,51179L,51180L,51181L,51182L,51183L,51184L, |
| 97203 | 51185L,51186L,51187L,51188L,51189L,51190L,51191L,51192L,51193L,51194L, |
| 97204 | 51195L,51196L,51197L,51198L,51199L,51200L,51201L,51202L,51203L,51204L, |
| 97205 | 51205L,51206L,51207L,51208L,51209L,51210L,51211L,51212L,51213L,51214L, |
| 97206 | 51215L,51216L,51217L,51218L,51219L,51220L,51221L,51222L,51223L,51224L, |
| 97207 | 51225L,51226L,51227L,51228L,51229L,51230L,51231L,51232L,51233L,51234L, |
| 97208 | 51235L,51236L,51237L,51238L,51239L,51240L,51241L,51242L,51243L,51244L, |
| 97209 | 51245L,51246L,51247L,51248L,51249L,51250L,51251L,51252L,51253L,51254L, |
| 97210 | 51255L,51256L,51257L,51258L,51259L,51260L,51261L,51262L,51263L,51264L, |
| 97211 | 51265L,51266L,51267L,51268L,51269L,51270L,51271L,51272L,51273L,51274L, |
| 97212 | 51275L,51276L,51277L,51278L,51279L,51280L,51281L,51282L,51283L,51284L, |
| 97213 | 51285L,51286L,51287L,51288L,51289L,51290L,51291L,51292L,51293L,51294L, |
| 97214 | 51295L,51296L,51297L,51298L,51299L,51300L,51301L,51302L,51303L,51304L, |
| 97215 | 51305L,51306L,51307L,51308L,51309L,51310L,51311L,51312L,51313L,51314L, |
| 97216 | 51315L,51316L,51317L,51318L,51319L,51320L,51321L,51322L,51323L,51324L, |
| 97217 | 51325L,51326L,51327L,51328L,51329L,51330L,51331L,51332L,51333L,51334L, |
| 97218 | 51335L,51336L,51337L,51338L,51339L,51340L,51341L,51342L,51343L,51344L, |
| 97219 | 51345L,51346L,51347L,51348L,51349L,51350L,51351L,51352L,51353L,51354L, |
| 97220 | 51355L,51356L,51357L,51358L,51359L,51360L,51361L,51362L,51363L,51364L, |
| 97221 | 51365L,51366L,51367L,51368L,51369L,51370L,51371L,51372L,51373L,51374L, |
| 97222 | 51375L,51376L,51377L,51378L,51379L,51380L,51381L,51382L,51383L,51384L, |
| 97223 | 51385L,51386L,51387L,51388L,51389L,51390L,51391L,51392L,51393L,51394L, |
| 97224 | 51395L,51396L,51397L,51398L,51399L,51400L,51401L,51402L,51403L,51404L, |
| 97225 | 51405L,51406L,51407L,51408L,51409L,51410L,51411L,51412L,51413L,51414L, |
| 97226 | 51415L,51416L,51417L,51418L,51419L,51420L,51421L,51422L,51423L,51424L, |
| 97227 | 51425L,51426L,51427L,51428L,51429L,51430L,51431L,51432L,51433L,51434L, |
| 97228 | 51435L,51436L,51437L,51438L,51439L,51440L,51441L,51442L,51443L,51444L, |
| 97229 | 51445L,51446L,51447L,51448L,51449L,51450L,51451L,51452L,51453L,51454L, |
| 97230 | 51455L,51456L,51457L,51458L,51459L,51460L,51461L,51462L,51463L,51464L, |
| 97231 | 51465L,51466L,51467L,51468L,51469L,51470L,51471L,51472L,51473L,51474L, |
| 97232 | 51475L,51476L,51477L,51478L,51479L,51480L,51481L,51482L,51483L,51484L, |
| 97233 | 51485L,51486L,51487L,51488L,51489L,51490L,51491L,51492L,51493L,51494L, |
| 97234 | 51495L,51496L,51497L,51498L,51499L,51500L,51501L,51502L,51503L,51504L, |
| 97235 | 51505L,51506L,51507L,51508L,51509L,51510L,51511L,51512L,51513L,51514L, |
| 97236 | 51515L,51516L,51517L,51518L,51519L,51520L,51521L,51522L,51523L,51524L, |
| 97237 | 51525L,51526L,51527L,51528L,51529L,51530L,51531L,51532L,51533L,51534L, |
| 97238 | 51535L,51536L,51537L,51538L,51539L,51540L,51541L,51542L,51543L,51544L, |
| 97239 | 51545L,51546L,51547L,51548L,51549L,51550L,51551L,51552L,51553L,51554L, |
| 97240 | 51555L,51556L,51557L,51558L,51559L,51560L,51561L,51562L,51563L,51564L, |
| 97241 | 51565L,51566L,51567L,51568L,51569L,51570L,51571L,51572L,51573L,51574L, |
| 97242 | 51575L,51576L,51577L,51578L,51579L,51580L,51581L,51582L,51583L,51584L, |
| 97243 | 51585L,51586L,51587L,51588L,51589L,51590L,51591L,51592L,51593L,51594L, |
| 97244 | 51595L,51596L,51597L,51598L,51599L,51600L,51601L,51602L,51603L,51604L, |
| 97245 | 51605L,51606L,51607L,51608L,51609L,51610L,51611L,51612L,51613L,51614L, |
| 97246 | 51615L,51616L,51617L,51618L,51619L,51620L,51621L,51622L,51623L,51624L, |
| 97247 | 51625L,51626L,51627L,51628L,51629L,51630L,51631L,51632L,51633L,51634L, |
| 97248 | 51635L,51636L,51637L,51638L,51639L,51640L,51641L,51642L,51643L,51644L, |
| 97249 | 51645L,51646L,51647L,51648L,51649L,51650L,51651L,51652L,51653L,51654L, |
| 97250 | 51655L,51656L,51657L,51658L,51659L,51660L,51661L,51662L,51663L,51664L, |
| 97251 | 51665L,51666L,51667L,51668L,51669L,51670L,51671L,51672L,51673L,51674L, |
| 97252 | 51675L,51676L,51677L,51678L,51679L,51680L,51681L,51682L,51683L,51684L, |
| 97253 | 51685L,51686L,51687L,51688L,51689L,51690L,51691L,51692L,51693L,51694L, |
| 97254 | 51695L,51696L,51697L,51698L,51699L,51700L,51701L,51702L,51703L,51704L, |
| 97255 | 51705L,51706L,51707L,51708L,51709L,51710L,51711L,51712L,51713L,51714L, |
| 97256 | 51715L,51716L,51717L,51718L,51719L,51720L,51721L,51722L,51723L,51724L, |
| 97257 | 51725L,51726L,51727L,51728L,51729L,51730L,51731L,51732L,51733L,51734L, |
| 97258 | 51735L,51736L,51737L,51738L,51739L,51740L,51741L,51742L,51743L,51744L, |
| 97259 | 51745L,51746L,51747L,51748L,51749L,51750L,51751L,51752L,51753L,51754L, |
| 97260 | 51755L,51756L,51757L,51758L,51759L,51760L,51761L,51762L,51763L,51764L, |
| 97261 | 51765L,51766L,51767L,51768L,51769L,51770L,51771L,51772L,51773L,51774L, |
| 97262 | 51775L,51776L,51777L,51778L,51779L,51780L,51781L,51782L,51783L,51784L, |
| 97263 | 51785L,51786L,51787L,51788L,51789L,51790L,51791L,51792L,51793L,51794L, |
| 97264 | 51795L,51796L,51797L,51798L,51799L,51800L,51801L,51802L,51803L,51804L, |
| 97265 | 51805L,51806L,51807L,51808L,51809L,51810L,51811L,51812L,51813L,51814L, |
| 97266 | 51815L,51816L,51817L,51818L,51819L,51820L,51821L,51822L,51823L,51824L, |
| 97267 | 51825L,51826L,51827L,51828L,51829L,51830L,51831L,51832L,51833L,51834L, |
| 97268 | 51835L,51836L,51837L,51838L,51839L,51840L,51841L,51842L,51843L,51844L, |
| 97269 | 51845L,51846L,51847L,51848L,51849L,51850L,51851L,51852L,51853L,51854L, |
| 97270 | 51855L,51856L,51857L,51858L,51859L,51860L,51861L,51862L,51863L,51864L, |
| 97271 | 51865L,51866L,51867L,51868L,51869L,51870L,51871L,51872L,51873L,51874L, |
| 97272 | 51875L,51876L,51877L,51878L,51879L,51880L,51881L,51882L,51883L,51884L, |
| 97273 | 51885L,51886L,51887L,51888L,51889L,51890L,51891L,51892L,51893L,51894L, |
| 97274 | 51895L,51896L,51897L,51898L,51899L,51900L,51901L,51902L,51903L,51904L, |
| 97275 | 51905L,51906L,51907L,51908L,51909L,51910L,51911L,51912L,51913L,51914L, |
| 97276 | 51915L,51916L,51917L,51918L,51919L,51920L,51921L,51922L,51923L,51924L, |
| 97277 | 51925L,51926L,51927L,51928L,51929L,51930L,51931L,51932L,51933L,51934L, |
| 97278 | 51935L,51936L,51937L,51938L,51939L,51940L,51941L,51942L,51943L,51944L, |
| 97279 | 51945L,51946L,51947L,51948L,51949L,51950L,51951L,51952L,51953L,51954L, |
| 97280 | 51955L,51956L,51957L,51958L,51959L,51960L,51961L,51962L,51963L,51964L, |
| 97281 | 51965L,51966L,51967L,51968L,51969L,51970L,51971L,51972L,51973L,51974L, |
| 97282 | 51975L,51976L,51977L,51978L,51979L,51980L,51981L,51982L,51983L,51984L, |
| 97283 | 51985L,51986L,51987L,51988L,51989L,51990L,51991L,51992L,51993L,51994L, |
| 97284 | 51995L,51996L,51997L,51998L,51999L,52000L,52001L,52002L,52003L,52004L, |
| 97285 | 52005L,52006L,52007L,52008L,52009L,52010L,52011L,52012L,52013L,52014L, |
| 97286 | 52015L,52016L,52017L,52018L,52019L,52020L,52021L,52022L,52023L,52024L, |
| 97287 | 52025L,52026L,52027L,52028L,52029L,52030L,52031L,52032L,52033L,52034L, |
| 97288 | 52035L,52036L,52037L,52038L,52039L,52040L,52041L,52042L,52043L,52044L, |
| 97289 | 52045L,52046L,52047L,52048L,52049L,52050L,52051L,52052L,52053L,52054L, |
| 97290 | 52055L,52056L,52057L,52058L,52059L,52060L,52061L,52062L,52063L,52064L, |
| 97291 | 52065L,52066L,52067L,52068L,52069L,52070L,52071L,52072L,52073L,52074L, |
| 97292 | 52075L,52076L,52077L,52078L,52079L,52080L,52081L,52082L,52083L,52084L, |
| 97293 | 52085L,52086L,52087L,52088L,52089L,52090L,52091L,52092L,52093L,52094L, |
| 97294 | 52095L,52096L,52097L,52098L,52099L,52100L,52101L,52102L,52103L,52104L, |
| 97295 | 52105L,52106L,52107L,52108L,52109L,52110L,52111L,52112L,52113L,52114L, |
| 97296 | 52115L,52116L,52117L,52118L,52119L,52120L,52121L,52122L,52123L,52124L, |
| 97297 | 52125L,52126L,52127L,52128L,52129L,52130L,52131L,52132L,52133L,52134L, |
| 97298 | 52135L,52136L,52137L,52138L,52139L,52140L,52141L,52142L,52143L,52144L, |
| 97299 | 52145L,52146L,52147L,52148L,52149L,52150L,52151L,52152L,52153L,52154L, |
| 97300 | 52155L,52156L,52157L,52158L,52159L,52160L,52161L,52162L,52163L,52164L, |
| 97301 | 52165L,52166L,52167L,52168L,52169L,52170L,52171L,52172L,52173L,52174L, |
| 97302 | 52175L,52176L,52177L,52178L,52179L,52180L,52181L,52182L,52183L,52184L, |
| 97303 | 52185L,52186L,52187L,52188L,52189L,52190L,52191L,52192L,52193L,52194L, |
| 97304 | 52195L,52196L,52197L,52198L,52199L,52200L,52201L,52202L,52203L,52204L, |
| 97305 | 52205L,52206L,52207L,52208L,52209L,52210L,52211L,52212L,52213L,52214L, |
| 97306 | 52215L,52216L,52217L,52218L,52219L,52220L,52221L,52222L,52223L,52224L, |
| 97307 | 52225L,52226L,52227L,52228L,52229L,52230L,52231L,52232L,52233L,52234L, |
| 97308 | 52235L,52236L,52237L,52238L,52239L,52240L,52241L,52242L,52243L,52244L, |
| 97309 | 52245L,52246L,52247L,52248L,52249L,52250L,52251L,52252L,52253L,52254L, |
| 97310 | 52255L,52256L,52257L,52258L,52259L,52260L,52261L,52262L,52263L,52264L, |
| 97311 | 52265L,52266L,52267L,52268L,52269L,52270L,52271L,52272L,52273L,52274L, |
| 97312 | 52275L,52276L,52277L,52278L,52279L,52280L,52281L,52282L,52283L,52284L, |
| 97313 | 52285L,52286L,52287L,52288L,52289L,52290L,52291L,52292L,52293L,52294L, |
| 97314 | 52295L,52296L,52297L,52298L,52299L,52300L,52301L,52302L,52303L,52304L, |
| 97315 | 52305L,52306L,52307L,52308L,52309L,52310L,52311L,52312L,52313L,52314L, |
| 97316 | 52315L,52316L,52317L,52318L,52319L,52320L,52321L,52322L,52323L,52324L, |
| 97317 | 52325L,52326L,52327L,52328L,52329L,52330L,52331L,52332L,52333L,52334L, |
| 97318 | 52335L,52336L,52337L,52338L,52339L,52340L,52341L,52342L,52343L,52344L, |
| 97319 | 52345L,52346L,52347L,52348L,52349L,52350L,52351L,52352L,52353L,52354L, |
| 97320 | 52355L,52356L,52357L,52358L,52359L,52360L,52361L,52362L,52363L,52364L, |
| 97321 | 52365L,52366L,52367L,52368L,52369L,52370L,52371L,52372L,52373L,52374L, |
| 97322 | 52375L,52376L,52377L,52378L,52379L,52380L,52381L,52382L,52383L,52384L, |
| 97323 | 52385L,52386L,52387L,52388L,52389L,52390L,52391L,52392L,52393L,52394L, |
| 97324 | 52395L,52396L,52397L,52398L,52399L,52400L,52401L,52402L,52403L,52404L, |
| 97325 | 52405L,52406L,52407L,52408L,52409L,52410L,52411L,52412L,52413L,52414L, |
| 97326 | 52415L,52416L,52417L,52418L,52419L,52420L,52421L,52422L,52423L,52424L, |
| 97327 | 52425L,52426L,52427L,52428L,52429L,52430L,52431L,52432L,52433L,52434L, |
| 97328 | 52435L,52436L,52437L,52438L,52439L,52440L,52441L,52442L,52443L,52444L, |
| 97329 | 52445L,52446L,52447L,52448L,52449L,52450L,52451L,52452L,52453L,52454L, |
| 97330 | 52455L,52456L,52457L,52458L,52459L,52460L,52461L,52462L,52463L,52464L, |
| 97331 | 52465L,52466L,52467L,52468L,52469L,52470L,52471L,52472L,52473L,52474L, |
| 97332 | 52475L,52476L,52477L,52478L,52479L,52480L,52481L,52482L,52483L,52484L, |
| 97333 | 52485L,52486L,52487L,52488L,52489L,52490L,52491L,52492L,52493L,52494L, |
| 97334 | 52495L,52496L,52497L,52498L,52499L,52500L,52501L,52502L,52503L,52504L, |
| 97335 | 52505L,52506L,52507L,52508L,52509L,52510L,52511L,52512L,52513L,52514L, |
| 97336 | 52515L,52516L,52517L,52518L,52519L,52520L,52521L,52522L,52523L,52524L, |
| 97337 | 52525L,52526L,52527L,52528L,52529L,52530L,52531L,52532L,52533L,52534L, |
| 97338 | 52535L,52536L,52537L,52538L,52539L,52540L,52541L,52542L,52543L,52544L, |
| 97339 | 52545L,52546L,52547L,52548L,52549L,52550L,52551L,52552L,52553L,52554L, |
| 97340 | 52555L,52556L,52557L,52558L,52559L,52560L,52561L,52562L,52563L,52564L, |
| 97341 | 52565L,52566L,52567L,52568L,52569L,52570L,52571L,52572L,52573L,52574L, |
| 97342 | 52575L,52576L,52577L,52578L,52579L,52580L,52581L,52582L,52583L,52584L, |
| 97343 | 52585L,52586L,52587L,52588L,52589L,52590L,52591L,52592L,52593L,52594L, |
| 97344 | 52595L,52596L,52597L,52598L,52599L,52600L,52601L,52602L,52603L,52604L, |
| 97345 | 52605L,52606L,52607L,52608L,52609L,52610L,52611L,52612L,52613L,52614L, |
| 97346 | 52615L,52616L,52617L,52618L,52619L,52620L,52621L,52622L,52623L,52624L, |
| 97347 | 52625L,52626L,52627L,52628L,52629L,52630L,52631L,52632L,52633L,52634L, |
| 97348 | 52635L,52636L,52637L,52638L,52639L,52640L,52641L,52642L,52643L,52644L, |
| 97349 | 52645L,52646L,52647L,52648L,52649L,52650L,52651L,52652L,52653L,52654L, |
| 97350 | 52655L,52656L,52657L,52658L,52659L,52660L,52661L,52662L,52663L,52664L, |
| 97351 | 52665L,52666L,52667L,52668L,52669L,52670L,52671L,52672L,52673L,52674L, |
| 97352 | 52675L,52676L,52677L,52678L,52679L,52680L,52681L,52682L,52683L,52684L, |
| 97353 | 52685L,52686L,52687L,52688L,52689L,52690L,52691L,52692L,52693L,52694L, |
| 97354 | 52695L,52696L,52697L,52698L,52699L,52700L,52701L,52702L,52703L,52704L, |
| 97355 | 52705L,52706L,52707L,52708L,52709L,52710L,52711L,52712L,52713L,52714L, |
| 97356 | 52715L,52716L,52717L,52718L,52719L,52720L,52721L,52722L,52723L,52724L, |
| 97357 | 52725L,52726L,52727L,52728L,52729L,52730L,52731L,52732L,52733L,52734L, |
| 97358 | 52735L,52736L,52737L,52738L,52739L,52740L,52741L,52742L,52743L,52744L, |
| 97359 | 52745L,52746L,52747L,52748L,52749L,52750L,52751L,52752L,52753L,52754L, |
| 97360 | 52755L,52756L,52757L,52758L,52759L,52760L,52761L,52762L,52763L,52764L, |
| 97361 | 52765L,52766L,52767L,52768L,52769L,52770L,52771L,52772L,52773L,52774L, |
| 97362 | 52775L,52776L,52777L,52778L,52779L,52780L,52781L,52782L,52783L,52784L, |
| 97363 | 52785L,52786L,52787L,52788L,52789L,52790L,52791L,52792L,52793L,52794L, |
| 97364 | 52795L,52796L,52797L,52798L,52799L,52800L,52801L,52802L,52803L,52804L, |
| 97365 | 52805L,52806L,52807L,52808L,52809L,52810L,52811L,52812L,52813L,52814L, |
| 97366 | 52815L,52816L,52817L,52818L,52819L,52820L,52821L,52822L,52823L,52824L, |
| 97367 | 52825L,52826L,52827L,52828L,52829L,52830L,52831L,52832L,52833L,52834L, |
| 97368 | 52835L,52836L,52837L,52838L,52839L,52840L,52841L,52842L,52843L,52844L, |
| 97369 | 52845L,52846L,52847L,52848L,52849L,52850L,52851L,52852L,52853L,52854L, |
| 97370 | 52855L,52856L,52857L,52858L,52859L,52860L,52861L,52862L,52863L,52864L, |
| 97371 | 52865L,52866L,52867L,52868L,52869L,52870L,52871L,52872L,52873L,52874L, |
| 97372 | 52875L,52876L,52877L,52878L,52879L,52880L,52881L,52882L,52883L,52884L, |
| 97373 | 52885L,52886L,52887L,52888L,52889L,52890L,52891L,52892L,52893L,52894L, |
| 97374 | 52895L,52896L,52897L,52898L,52899L,52900L,52901L,52902L,52903L,52904L, |
| 97375 | 52905L,52906L,52907L,52908L,52909L,52910L,52911L,52912L,52913L,52914L, |
| 97376 | 52915L,52916L,52917L,52918L,52919L,52920L,52921L,52922L,52923L,52924L, |
| 97377 | 52925L,52926L,52927L,52928L,52929L,52930L,52931L,52932L,52933L,52934L, |
| 97378 | 52935L,52936L,52937L,52938L,52939L,52940L,52941L,52942L,52943L,52944L, |
| 97379 | 52945L,52946L,52947L,52948L,52949L,52950L,52951L,52952L,52953L,52954L, |
| 97380 | 52955L,52956L,52957L,52958L,52959L,52960L,52961L,52962L,52963L,52964L, |
| 97381 | 52965L,52966L,52967L,52968L,52969L,52970L,52971L,52972L,52973L,52974L, |
| 97382 | 52975L,52976L,52977L,52978L,52979L,52980L,52981L,52982L,52983L,52984L, |
| 97383 | 52985L,52986L,52987L,52988L,52989L,52990L,52991L,52992L,52993L,52994L, |
| 97384 | 52995L,52996L,52997L,52998L,52999L,53000L,53001L,53002L,53003L,53004L, |
| 97385 | 53005L,53006L,53007L,53008L,53009L,53010L,53011L,53012L,53013L,53014L, |
| 97386 | 53015L,53016L,53017L,53018L,53019L,53020L,53021L,53022L,53023L,53024L, |
| 97387 | 53025L,53026L,53027L,53028L,53029L,53030L,53031L,53032L,53033L,53034L, |
| 97388 | 53035L,53036L,53037L,53038L,53039L,53040L,53041L,53042L,53043L,53044L, |
| 97389 | 53045L,53046L,53047L,53048L,53049L,53050L,53051L,53052L,53053L,53054L, |
| 97390 | 53055L,53056L,53057L,53058L,53059L,53060L,53061L,53062L,53063L,53064L, |
| 97391 | 53065L,53066L,53067L,53068L,53069L,53070L,53071L,53072L,53073L,53074L, |
| 97392 | 53075L,53076L,53077L,53078L,53079L,53080L,53081L,53082L,53083L,53084L, |
| 97393 | 53085L,53086L,53087L,53088L,53089L,53090L,53091L,53092L,53093L,53094L, |
| 97394 | 53095L,53096L,53097L,53098L,53099L,53100L,53101L,53102L,53103L,53104L, |
| 97395 | 53105L,53106L,53107L,53108L,53109L,53110L,53111L,53112L,53113L,53114L, |
| 97396 | 53115L,53116L,53117L,53118L,53119L,53120L,53121L,53122L,53123L,53124L, |
| 97397 | 53125L,53126L,53127L,53128L,53129L,53130L,53131L,53132L,53133L,53134L, |
| 97398 | 53135L,53136L,53137L,53138L,53139L,53140L,53141L,53142L,53143L,53144L, |
| 97399 | 53145L,53146L,53147L,53148L,53149L,53150L,53151L,53152L,53153L,53154L, |
| 97400 | 53155L,53156L,53157L,53158L,53159L,53160L,53161L,53162L,53163L,53164L, |
| 97401 | 53165L,53166L,53167L,53168L,53169L,53170L,53171L,53172L,53173L,53174L, |
| 97402 | 53175L,53176L,53177L,53178L,53179L,53180L,53181L,53182L,53183L,53184L, |
| 97403 | 53185L,53186L,53187L,53188L,53189L,53190L,53191L,53192L,53193L,53194L, |
| 97404 | 53195L,53196L,53197L,53198L,53199L,53200L,53201L,53202L,53203L,53204L, |
| 97405 | 53205L,53206L,53207L,53208L,53209L,53210L,53211L,53212L,53213L,53214L, |
| 97406 | 53215L,53216L,53217L,53218L,53219L,53220L,53221L,53222L,53223L,53224L, |
| 97407 | 53225L,53226L,53227L,53228L,53229L,53230L,53231L,53232L,53233L,53234L, |
| 97408 | 53235L,53236L,53237L,53238L,53239L,53240L,53241L,53242L,53243L,53244L, |
| 97409 | 53245L,53246L,53247L,53248L,53249L,53250L,53251L,53252L,53253L,53254L, |
| 97410 | 53255L,53256L,53257L,53258L,53259L,53260L,53261L,53262L,53263L,53264L, |
| 97411 | 53265L,53266L,53267L,53268L,53269L,53270L,53271L,53272L,53273L,53274L, |
| 97412 | 53275L,53276L,53277L,53278L,53279L,53280L,53281L,53282L,53283L,53284L, |
| 97413 | 53285L,53286L,53287L,53288L,53289L,53290L,53291L,53292L,53293L,53294L, |
| 97414 | 53295L,53296L,53297L,53298L,53299L,53300L,53301L,53302L,53303L,53304L, |
| 97415 | 53305L,53306L,53307L,53308L,53309L,53310L,53311L,53312L,53313L,53314L, |
| 97416 | 53315L,53316L,53317L,53318L,53319L,53320L,53321L,53322L,53323L,53324L, |
| 97417 | 53325L,53326L,53327L,53328L,53329L,53330L,53331L,53332L,53333L,53334L, |
| 97418 | 53335L,53336L,53337L,53338L,53339L,53340L,53341L,53342L,53343L,53344L, |
| 97419 | 53345L,53346L,53347L,53348L,53349L,53350L,53351L,53352L,53353L,53354L, |
| 97420 | 53355L,53356L,53357L,53358L,53359L,53360L,53361L,53362L,53363L,53364L, |
| 97421 | 53365L,53366L,53367L,53368L,53369L,53370L,53371L,53372L,53373L,53374L, |
| 97422 | 53375L,53376L,53377L,53378L,53379L,53380L,53381L,53382L,53383L,53384L, |
| 97423 | 53385L,53386L,53387L,53388L,53389L,53390L,53391L,53392L,53393L,53394L, |
| 97424 | 53395L,53396L,53397L,53398L,53399L,53400L,53401L,53402L,53403L,53404L, |
| 97425 | 53405L,53406L,53407L,53408L,53409L,53410L,53411L,53412L,53413L,53414L, |
| 97426 | 53415L,53416L,53417L,53418L,53419L,53420L,53421L,53422L,53423L,53424L, |
| 97427 | 53425L,53426L,53427L,53428L,53429L,53430L,53431L,53432L,53433L,53434L, |
| 97428 | 53435L,53436L,53437L,53438L,53439L,53440L,53441L,53442L,53443L,53444L, |
| 97429 | 53445L,53446L,53447L,53448L,53449L,53450L,53451L,53452L,53453L,53454L, |
| 97430 | 53455L,53456L,53457L,53458L,53459L,53460L,53461L,53462L,53463L,53464L, |
| 97431 | 53465L,53466L,53467L,53468L,53469L,53470L,53471L,53472L,53473L,53474L, |
| 97432 | 53475L,53476L,53477L,53478L,53479L,53480L,53481L,53482L,53483L,53484L, |
| 97433 | 53485L,53486L,53487L,53488L,53489L,53490L,53491L,53492L,53493L,53494L, |
| 97434 | 53495L,53496L,53497L,53498L,53499L,53500L,53501L,53502L,53503L,53504L, |
| 97435 | 53505L,53506L,53507L,53508L,53509L,53510L,53511L,53512L,53513L,53514L, |
| 97436 | 53515L,53516L,53517L,53518L,53519L,53520L,53521L,53522L,53523L,53524L, |
| 97437 | 53525L,53526L,53527L,53528L,53529L,53530L,53531L,53532L,53533L,53534L, |
| 97438 | 53535L,53536L,53537L,53538L,53539L,53540L,53541L,53542L,53543L,53544L, |
| 97439 | 53545L,53546L,53547L,53548L,53549L,53550L,53551L,53552L,53553L,53554L, |
| 97440 | 53555L,53556L,53557L,53558L,53559L,53560L,53561L,53562L,53563L,53564L, |
| 97441 | 53565L,53566L,53567L,53568L,53569L,53570L,53571L,53572L,53573L,53574L, |
| 97442 | 53575L,53576L,53577L,53578L,53579L,53580L,53581L,53582L,53583L,53584L, |
| 97443 | 53585L,53586L,53587L,53588L,53589L,53590L,53591L,53592L,53593L,53594L, |
| 97444 | 53595L,53596L,53597L,53598L,53599L,53600L,53601L,53602L,53603L,53604L, |
| 97445 | 53605L,53606L,53607L,53608L,53609L,53610L,53611L,53612L,53613L,53614L, |
| 97446 | 53615L,53616L,53617L,53618L,53619L,53620L,53621L,53622L,53623L,53624L, |
| 97447 | 53625L,53626L,53627L,53628L,53629L,53630L,53631L,53632L,53633L,53634L, |
| 97448 | 53635L,53636L,53637L,53638L,53639L,53640L,53641L,53642L,53643L,53644L, |
| 97449 | 53645L,53646L,53647L,53648L,53649L,53650L,53651L,53652L,53653L,53654L, |
| 97450 | 53655L,53656L,53657L,53658L,53659L,53660L,53661L,53662L,53663L,53664L, |
| 97451 | 53665L,53666L,53667L,53668L,53669L,53670L,53671L,53672L,53673L,53674L, |
| 97452 | 53675L,53676L,53677L,53678L,53679L,53680L,53681L,53682L,53683L,53684L, |
| 97453 | 53685L,53686L,53687L,53688L,53689L,53690L,53691L,53692L,53693L,53694L, |
| 97454 | 53695L,53696L,53697L,53698L,53699L,53700L,53701L,53702L,53703L,53704L, |
| 97455 | 53705L,53706L,53707L,53708L,53709L,53710L,53711L,53712L,53713L,53714L, |
| 97456 | 53715L,53716L,53717L,53718L,53719L,53720L,53721L,53722L,53723L,53724L, |
| 97457 | 53725L,53726L,53727L,53728L,53729L,53730L,53731L,53732L,53733L,53734L, |
| 97458 | 53735L,53736L,53737L,53738L,53739L,53740L,53741L,53742L,53743L,53744L, |
| 97459 | 53745L,53746L,53747L,53748L,53749L,53750L,53751L,53752L,53753L,53754L, |
| 97460 | 53755L,53756L,53757L,53758L,53759L,53760L,53761L,53762L,53763L,53764L, |
| 97461 | 53765L,53766L,53767L,53768L,53769L,53770L,53771L,53772L,53773L,53774L, |
| 97462 | 53775L,53776L,53777L,53778L,53779L,53780L,53781L,53782L,53783L,53784L, |
| 97463 | 53785L,53786L,53787L,53788L,53789L,53790L,53791L,53792L,53793L,53794L, |
| 97464 | 53795L,53796L,53797L,53798L,53799L,53800L,53801L,53802L,53803L,53804L, |
| 97465 | 53805L,53806L,53807L,53808L,53809L,53810L,53811L,53812L,53813L,53814L, |
| 97466 | 53815L,53816L,53817L,53818L,53819L,53820L,53821L,53822L,53823L,53824L, |
| 97467 | 53825L,53826L,53827L,53828L,53829L,53830L,53831L,53832L,53833L,53834L, |
| 97468 | 53835L,53836L,53837L,53838L,53839L,53840L,53841L,53842L,53843L,53844L, |
| 97469 | 53845L,53846L,53847L,53848L,53849L,53850L,53851L,53852L,53853L,53854L, |
| 97470 | 53855L,53856L,53857L,53858L,53859L,53860L,53861L,53862L,53863L,53864L, |
| 97471 | 53865L,53866L,53867L,53868L,53869L,53870L,53871L,53872L,53873L,53874L, |
| 97472 | 53875L,53876L,53877L,53878L,53879L,53880L,53881L,53882L,53883L,53884L, |
| 97473 | 53885L,53886L,53887L,53888L,53889L,53890L,53891L,53892L,53893L,53894L, |
| 97474 | 53895L,53896L,53897L,53898L,53899L,53900L,53901L,53902L,53903L,53904L, |
| 97475 | 53905L,53906L,53907L,53908L,53909L,53910L,53911L,53912L,53913L,53914L, |
| 97476 | 53915L,53916L,53917L,53918L,53919L,53920L,53921L,53922L,53923L,53924L, |
| 97477 | 53925L,53926L,53927L,53928L,53929L,53930L,53931L,53932L,53933L,53934L, |
| 97478 | 53935L,53936L,53937L,53938L,53939L,53940L,53941L,53942L,53943L,53944L, |
| 97479 | 53945L,53946L,53947L,53948L,53949L,53950L,53951L,53952L,53953L,53954L, |
| 97480 | 53955L,53956L,53957L,53958L,53959L,53960L,53961L,53962L,53963L,53964L, |
| 97481 | 53965L,53966L,53967L,53968L,53969L,53970L,53971L,53972L,53973L,53974L, |
| 97482 | 53975L,53976L,53977L,53978L,53979L,53980L,53981L,53982L,53983L,53984L, |
| 97483 | 53985L,53986L,53987L,53988L,53989L,53990L,53991L,53992L,53993L,53994L, |
| 97484 | 53995L,53996L,53997L,53998L,53999L,54000L,54001L,54002L,54003L,54004L, |
| 97485 | 54005L,54006L,54007L,54008L,54009L,54010L,54011L,54012L,54013L,54014L, |
| 97486 | 54015L,54016L,54017L,54018L,54019L,54020L,54021L,54022L,54023L,54024L, |
| 97487 | 54025L,54026L,54027L,54028L,54029L,54030L,54031L,54032L,54033L,54034L, |
| 97488 | 54035L,54036L,54037L,54038L,54039L,54040L,54041L,54042L,54043L,54044L, |
| 97489 | 54045L,54046L,54047L,54048L,54049L,54050L,54051L,54052L,54053L,54054L, |
| 97490 | 54055L,54056L,54057L,54058L,54059L,54060L,54061L,54062L,54063L,54064L, |
| 97491 | 54065L,54066L,54067L,54068L,54069L,54070L,54071L,54072L,54073L,54074L, |
| 97492 | 54075L,54076L,54077L,54078L,54079L,54080L,54081L,54082L,54083L,54084L, |
| 97493 | 54085L,54086L,54087L,54088L,54089L,54090L,54091L,54092L,54093L,54094L, |
| 97494 | 54095L,54096L,54097L,54098L,54099L,54100L,54101L,54102L,54103L,54104L, |
| 97495 | 54105L,54106L,54107L,54108L,54109L,54110L,54111L,54112L,54113L,54114L, |
| 97496 | 54115L,54116L,54117L,54118L,54119L,54120L,54121L,54122L,54123L,54124L, |
| 97497 | 54125L,54126L,54127L,54128L,54129L,54130L,54131L,54132L,54133L,54134L, |
| 97498 | 54135L,54136L,54137L,54138L,54139L,54140L,54141L,54142L,54143L,54144L, |
| 97499 | 54145L,54146L,54147L,54148L,54149L,54150L,54151L,54152L,54153L,54154L, |
| 97500 | 54155L,54156L,54157L,54158L,54159L,54160L,54161L,54162L,54163L,54164L, |
| 97501 | 54165L,54166L,54167L,54168L,54169L,54170L,54171L,54172L,54173L,54174L, |
| 97502 | 54175L,54176L,54177L,54178L,54179L,54180L,54181L,54182L,54183L,54184L, |
| 97503 | 54185L,54186L,54187L,54188L,54189L,54190L,54191L,54192L,54193L,54194L, |
| 97504 | 54195L,54196L,54197L,54198L,54199L,54200L,54201L,54202L,54203L,54204L, |
| 97505 | 54205L,54206L,54207L,54208L,54209L,54210L,54211L,54212L,54213L,54214L, |
| 97506 | 54215L,54216L,54217L,54218L,54219L,54220L,54221L,54222L,54223L,54224L, |
| 97507 | 54225L,54226L,54227L,54228L,54229L,54230L,54231L,54232L,54233L,54234L, |
| 97508 | 54235L,54236L,54237L,54238L,54239L,54240L,54241L,54242L,54243L,54244L, |
| 97509 | 54245L,54246L,54247L,54248L,54249L,54250L,54251L,54252L,54253L,54254L, |
| 97510 | 54255L,54256L,54257L,54258L,54259L,54260L,54261L,54262L,54263L,54264L, |
| 97511 | 54265L,54266L,54267L,54268L,54269L,54270L,54271L,54272L,54273L,54274L, |
| 97512 | 54275L,54276L,54277L,54278L,54279L,54280L,54281L,54282L,54283L,54284L, |
| 97513 | 54285L,54286L,54287L,54288L,54289L,54290L,54291L,54292L,54293L,54294L, |
| 97514 | 54295L,54296L,54297L,54298L,54299L,54300L,54301L,54302L,54303L,54304L, |
| 97515 | 54305L,54306L,54307L,54308L,54309L,54310L,54311L,54312L,54313L,54314L, |
| 97516 | 54315L,54316L,54317L,54318L,54319L,54320L,54321L,54322L,54323L,54324L, |
| 97517 | 54325L,54326L,54327L,54328L,54329L,54330L,54331L,54332L,54333L,54334L, |
| 97518 | 54335L,54336L,54337L,54338L,54339L,54340L,54341L,54342L,54343L,54344L, |
| 97519 | 54345L,54346L,54347L,54348L,54349L,54350L,54351L,54352L,54353L,54354L, |
| 97520 | 54355L,54356L,54357L,54358L,54359L,54360L,54361L,54362L,54363L,54364L, |
| 97521 | 54365L,54366L,54367L,54368L,54369L,54370L,54371L,54372L,54373L,54374L, |
| 97522 | 54375L,54376L,54377L,54378L,54379L,54380L,54381L,54382L,54383L,54384L, |
| 97523 | 54385L,54386L,54387L,54388L,54389L,54390L,54391L,54392L,54393L,54394L, |
| 97524 | 54395L,54396L,54397L,54398L,54399L,54400L,54401L,54402L,54403L,54404L, |
| 97525 | 54405L,54406L,54407L,54408L,54409L,54410L,54411L,54412L,54413L,54414L, |
| 97526 | 54415L,54416L,54417L,54418L,54419L,54420L,54421L,54422L,54423L,54424L, |
| 97527 | 54425L,54426L,54427L,54428L,54429L,54430L,54431L,54432L,54433L,54434L, |
| 97528 | 54435L,54436L,54437L,54438L,54439L,54440L,54441L,54442L,54443L,54444L, |
| 97529 | 54445L,54446L,54447L,54448L,54449L,54450L,54451L,54452L,54453L,54454L, |
| 97530 | 54455L,54456L,54457L,54458L,54459L,54460L,54461L,54462L,54463L,54464L, |
| 97531 | 54465L,54466L,54467L,54468L,54469L,54470L,54471L,54472L,54473L,54474L, |
| 97532 | 54475L,54476L,54477L,54478L,54479L,54480L,54481L,54482L,54483L,54484L, |
| 97533 | 54485L,54486L,54487L,54488L,54489L,54490L,54491L,54492L,54493L,54494L, |
| 97534 | 54495L,54496L,54497L,54498L,54499L,54500L,54501L,54502L,54503L,54504L, |
| 97535 | 54505L,54506L,54507L,54508L,54509L,54510L,54511L,54512L,54513L,54514L, |
| 97536 | 54515L,54516L,54517L,54518L,54519L,54520L,54521L,54522L,54523L,54524L, |
| 97537 | 54525L,54526L,54527L,54528L,54529L,54530L,54531L,54532L,54533L,54534L, |
| 97538 | 54535L,54536L,54537L,54538L,54539L,54540L,54541L,54542L,54543L,54544L, |
| 97539 | 54545L,54546L,54547L,54548L,54549L,54550L,54551L,54552L,54553L,54554L, |
| 97540 | 54555L,54556L,54557L,54558L,54559L,54560L,54561L,54562L,54563L,54564L, |
| 97541 | 54565L,54566L,54567L,54568L,54569L,54570L,54571L,54572L,54573L,54574L, |
| 97542 | 54575L,54576L,54577L,54578L,54579L,54580L,54581L,54582L,54583L,54584L, |
| 97543 | 54585L,54586L,54587L,54588L,54589L,54590L,54591L,54592L,54593L,54594L, |
| 97544 | 54595L,54596L,54597L,54598L,54599L,54600L,54601L,54602L,54603L,54604L, |
| 97545 | 54605L,54606L,54607L,54608L,54609L,54610L,54611L,54612L,54613L,54614L, |
| 97546 | 54615L,54616L,54617L,54618L,54619L,54620L,54621L,54622L,54623L,54624L, |
| 97547 | 54625L,54626L,54627L,54628L,54629L,54630L,54631L,54632L,54633L,54634L, |
| 97548 | 54635L,54636L,54637L,54638L,54639L,54640L,54641L,54642L,54643L,54644L, |
| 97549 | 54645L,54646L,54647L,54648L,54649L,54650L,54651L,54652L,54653L,54654L, |
| 97550 | 54655L,54656L,54657L,54658L,54659L,54660L,54661L,54662L,54663L,54664L, |
| 97551 | 54665L,54666L,54667L,54668L,54669L,54670L,54671L,54672L,54673L,54674L, |
| 97552 | 54675L,54676L,54677L,54678L,54679L,54680L,54681L,54682L,54683L,54684L, |
| 97553 | 54685L,54686L,54687L,54688L,54689L,54690L,54691L,54692L,54693L,54694L, |
| 97554 | 54695L,54696L,54697L,54698L,54699L,54700L,54701L,54702L,54703L,54704L, |
| 97555 | 54705L,54706L,54707L,54708L,54709L,54710L,54711L,54712L,54713L,54714L, |
| 97556 | 54715L,54716L,54717L,54718L,54719L,54720L,54721L,54722L,54723L,54724L, |
| 97557 | 54725L,54726L,54727L,54728L,54729L,54730L,54731L,54732L,54733L,54734L, |
| 97558 | 54735L,54736L,54737L,54738L,54739L,54740L,54741L,54742L,54743L,54744L, |
| 97559 | 54745L,54746L,54747L,54748L,54749L,54750L,54751L,54752L,54753L,54754L, |
| 97560 | 54755L,54756L,54757L,54758L,54759L,54760L,54761L,54762L,54763L,54764L, |
| 97561 | 54765L,54766L,54767L,54768L,54769L,54770L,54771L,54772L,54773L,54774L, |
| 97562 | 54775L,54776L,54777L,54778L,54779L,54780L,54781L,54782L,54783L,54784L, |
| 97563 | 54785L,54786L,54787L,54788L,54789L,54790L,54791L,54792L,54793L,54794L, |
| 97564 | 54795L,54796L,54797L,54798L,54799L,54800L,54801L,54802L,54803L,54804L, |
| 97565 | 54805L,54806L,54807L,54808L,54809L,54810L,54811L,54812L,54813L,54814L, |
| 97566 | 54815L,54816L,54817L,54818L,54819L,54820L,54821L,54822L,54823L,54824L, |
| 97567 | 54825L,54826L,54827L,54828L,54829L,54830L,54831L,54832L,54833L,54834L, |
| 97568 | 54835L,54836L,54837L,54838L,54839L,54840L,54841L,54842L,54843L,54844L, |
| 97569 | 54845L,54846L,54847L,54848L,54849L,54850L,54851L,54852L,54853L,54854L, |
| 97570 | 54855L,54856L,54857L,54858L,54859L,54860L,54861L,54862L,54863L,54864L, |
| 97571 | 54865L,54866L,54867L,54868L,54869L,54870L,54871L,54872L,54873L,54874L, |
| 97572 | 54875L,54876L,54877L,54878L,54879L,54880L,54881L,54882L,54883L,54884L, |
| 97573 | 54885L,54886L,54887L,54888L,54889L,54890L,54891L,54892L,54893L,54894L, |
| 97574 | 54895L,54896L,54897L,54898L,54899L,54900L,54901L,54902L,54903L,54904L, |
| 97575 | 54905L,54906L,54907L,54908L,54909L,54910L,54911L,54912L,54913L,54914L, |
| 97576 | 54915L,54916L,54917L,54918L,54919L,54920L,54921L,54922L,54923L,54924L, |
| 97577 | 54925L,54926L,54927L,54928L,54929L,54930L,54931L,54932L,54933L,54934L, |
| 97578 | 54935L,54936L,54937L,54938L,54939L,54940L,54941L,54942L,54943L,54944L, |
| 97579 | 54945L,54946L,54947L,54948L,54949L,54950L,54951L,54952L,54953L,54954L, |
| 97580 | 54955L,54956L,54957L,54958L,54959L,54960L,54961L,54962L,54963L,54964L, |
| 97581 | 54965L,54966L,54967L,54968L,54969L,54970L,54971L,54972L,54973L,54974L, |
| 97582 | 54975L,54976L,54977L,54978L,54979L,54980L,54981L,54982L,54983L,54984L, |
| 97583 | 54985L,54986L,54987L,54988L,54989L,54990L,54991L,54992L,54993L,54994L, |
| 97584 | 54995L,54996L,54997L,54998L,54999L,55000L,55001L,55002L,55003L,55004L, |
| 97585 | 55005L,55006L,55007L,55008L,55009L,55010L,55011L,55012L,55013L,55014L, |
| 97586 | 55015L,55016L,55017L,55018L,55019L,55020L,55021L,55022L,55023L,55024L, |
| 97587 | 55025L,55026L,55027L,55028L,55029L,55030L,55031L,55032L,55033L,55034L, |
| 97588 | 55035L,55036L,55037L,55038L,55039L,55040L,55041L,55042L,55043L,55044L, |
| 97589 | 55045L,55046L,55047L,55048L,55049L,55050L,55051L,55052L,55053L,55054L, |
| 97590 | 55055L,55056L,55057L,55058L,55059L,55060L,55061L,55062L,55063L,55064L, |
| 97591 | 55065L,55066L,55067L,55068L,55069L,55070L,55071L,55072L,55073L,55074L, |
| 97592 | 55075L,55076L,55077L,55078L,55079L,55080L,55081L,55082L,55083L,55084L, |
| 97593 | 55085L,55086L,55087L,55088L,55089L,55090L,55091L,55092L,55093L,55094L, |
| 97594 | 55095L,55096L,55097L,55098L,55099L,55100L,55101L,55102L,55103L,55104L, |
| 97595 | 55105L,55106L,55107L,55108L,55109L,55110L,55111L,55112L,55113L,55114L, |
| 97596 | 55115L,55116L,55117L,55118L,55119L,55120L,55121L,55122L,55123L,55124L, |
| 97597 | 55125L,55126L,55127L,55128L,55129L,55130L,55131L,55132L,55133L,55134L, |
| 97598 | 55135L,55136L,55137L,55138L,55139L,55140L,55141L,55142L,55143L,55144L, |
| 97599 | 55145L,55146L,55147L,55148L,55149L,55150L,55151L,55152L,55153L,55154L, |
| 97600 | 55155L,55156L,55157L,55158L,55159L,55160L,55161L,55162L,55163L,55164L, |
| 97601 | 55165L,55166L,55167L,55168L,55169L,55170L,55171L,55172L,55173L,55174L, |
| 97602 | 55175L,55176L,55177L,55178L,55179L,55180L,55181L,55182L,55183L,55184L, |
| 97603 | 55185L,55186L,55187L,55188L,55189L,55190L,55191L,55192L,55193L,55194L, |
| 97604 | 55195L,55196L,55197L,55198L,55199L,55200L,55201L,55202L,55203L,55204L, |
| 97605 | 55205L,55206L,55207L,55208L,55209L,55210L,55211L,55212L,55213L,55214L, |
| 97606 | 55215L,55216L,55217L,55218L,55219L,55220L,55221L,55222L,55223L,55224L, |
| 97607 | 55225L,55226L,55227L,55228L,55229L,55230L,55231L,55232L,55233L,55234L, |
| 97608 | 55235L,55236L,55237L,55238L,55239L,55240L,55241L,55242L,55243L,55244L, |
| 97609 | 55245L,55246L,55247L,55248L,55249L,55250L,55251L,55252L,55253L,55254L, |
| 97610 | 55255L,55256L,55257L,55258L,55259L,55260L,55261L,55262L,55263L,55264L, |
| 97611 | 55265L,55266L,55267L,55268L,55269L,55270L,55271L,55272L,55273L,55274L, |
| 97612 | 55275L,55276L,55277L,55278L,55279L,55280L,55281L,55282L,55283L,55284L, |
| 97613 | 55285L,55286L,55287L,55288L,55289L,55290L,55291L,55292L,55293L,55294L, |
| 97614 | 55295L,55296L,55297L,55298L,55299L,55300L,55301L,55302L,55303L,55304L, |
| 97615 | 55305L,55306L,55307L,55308L,55309L,55310L,55311L,55312L,55313L,55314L, |
| 97616 | 55315L,55316L,55317L,55318L,55319L,55320L,55321L,55322L,55323L,55324L, |
| 97617 | 55325L,55326L,55327L,55328L,55329L,55330L,55331L,55332L,55333L,55334L, |
| 97618 | 55335L,55336L,55337L,55338L,55339L,55340L,55341L,55342L,55343L,55344L, |
| 97619 | 55345L,55346L,55347L,55348L,55349L,55350L,55351L,55352L,55353L,55354L, |
| 97620 | 55355L,55356L,55357L,55358L,55359L,55360L,55361L,55362L,55363L,55364L, |
| 97621 | 55365L,55366L,55367L,55368L,55369L,55370L,55371L,55372L,55373L,55374L, |
| 97622 | 55375L,55376L,55377L,55378L,55379L,55380L,55381L,55382L,55383L,55384L, |
| 97623 | 55385L,55386L,55387L,55388L,55389L,55390L,55391L,55392L,55393L,55394L, |
| 97624 | 55395L,55396L,55397L,55398L,55399L,55400L,55401L,55402L,55403L,55404L, |
| 97625 | 55405L,55406L,55407L,55408L,55409L,55410L,55411L,55412L,55413L,55414L, |
| 97626 | 55415L,55416L,55417L,55418L,55419L,55420L,55421L,55422L,55423L,55424L, |
| 97627 | 55425L,55426L,55427L,55428L,55429L,55430L,55431L,55432L,55433L,55434L, |
| 97628 | 55435L,55436L,55437L,55438L,55439L,55440L,55441L,55442L,55443L,55444L, |
| 97629 | 55445L,55446L,55447L,55448L,55449L,55450L,55451L,55452L,55453L,55454L, |
| 97630 | 55455L,55456L,55457L,55458L,55459L,55460L,55461L,55462L,55463L,55464L, |
| 97631 | 55465L,55466L,55467L,55468L,55469L,55470L,55471L,55472L,55473L,55474L, |
| 97632 | 55475L,55476L,55477L,55478L,55479L,55480L,55481L,55482L,55483L,55484L, |
| 97633 | 55485L,55486L,55487L,55488L,55489L,55490L,55491L,55492L,55493L,55494L, |
| 97634 | 55495L,55496L,55497L,55498L,55499L,55500L,55501L,55502L,55503L,55504L, |
| 97635 | 55505L,55506L,55507L,55508L,55509L,55510L,55511L,55512L,55513L,55514L, |
| 97636 | 55515L,55516L,55517L,55518L,55519L,55520L,55521L,55522L,55523L,55524L, |
| 97637 | 55525L,55526L,55527L,55528L,55529L,55530L,55531L,55532L,55533L,55534L, |
| 97638 | 55535L,55536L,55537L,55538L,55539L,55540L,55541L,55542L,55543L,55544L, |
| 97639 | 55545L,55546L,55547L,55548L,55549L,55550L,55551L,55552L,55553L,55554L, |
| 97640 | 55555L,55556L,55557L,55558L,55559L,55560L,55561L,55562L,55563L,55564L, |
| 97641 | 55565L,55566L,55567L,55568L,55569L,55570L,55571L,55572L,55573L,55574L, |
| 97642 | 55575L,55576L,55577L,55578L,55579L,55580L,55581L,55582L,55583L,55584L, |
| 97643 | 55585L,55586L,55587L,55588L,55589L,55590L,55591L,55592L,55593L,55594L, |
| 97644 | 55595L,55596L,55597L,55598L,55599L,55600L,55601L,55602L,55603L,55604L, |
| 97645 | 55605L,55606L,55607L,55608L,55609L,55610L,55611L,55612L,55613L,55614L, |
| 97646 | 55615L,55616L,55617L,55618L,55619L,55620L,55621L,55622L,55623L,55624L, |
| 97647 | 55625L,55626L,55627L,55628L,55629L,55630L,55631L,55632L,55633L,55634L, |
| 97648 | 55635L,55636L,55637L,55638L,55639L,55640L,55641L,55642L,55643L,55644L, |
| 97649 | 55645L,55646L,55647L,55648L,55649L,55650L,55651L,55652L,55653L,55654L, |
| 97650 | 55655L,55656L,55657L,55658L,55659L,55660L,55661L,55662L,55663L,55664L, |
| 97651 | 55665L,55666L,55667L,55668L,55669L,55670L,55671L,55672L,55673L,55674L, |
| 97652 | 55675L,55676L,55677L,55678L,55679L,55680L,55681L,55682L,55683L,55684L, |
| 97653 | 55685L,55686L,55687L,55688L,55689L,55690L,55691L,55692L,55693L,55694L, |
| 97654 | 55695L,55696L,55697L,55698L,55699L,55700L,55701L,55702L,55703L,55704L, |
| 97655 | 55705L,55706L,55707L,55708L,55709L,55710L,55711L,55712L,55713L,55714L, |
| 97656 | 55715L,55716L,55717L,55718L,55719L,55720L,55721L,55722L,55723L,55724L, |
| 97657 | 55725L,55726L,55727L,55728L,55729L,55730L,55731L,55732L,55733L,55734L, |
| 97658 | 55735L,55736L,55737L,55738L,55739L,55740L,55741L,55742L,55743L,55744L, |
| 97659 | 55745L,55746L,55747L,55748L,55749L,55750L,55751L,55752L,55753L,55754L, |
| 97660 | 55755L,55756L,55757L,55758L,55759L,55760L,55761L,55762L,55763L,55764L, |
| 97661 | 55765L,55766L,55767L,55768L,55769L,55770L,55771L,55772L,55773L,55774L, |
| 97662 | 55775L,55776L,55777L,55778L,55779L,55780L,55781L,55782L,55783L,55784L, |
| 97663 | 55785L,55786L,55787L,55788L,55789L,55790L,55791L,55792L,55793L,55794L, |
| 97664 | 55795L,55796L,55797L,55798L,55799L,55800L,55801L,55802L,55803L,55804L, |
| 97665 | 55805L,55806L,55807L,55808L,55809L,55810L,55811L,55812L,55813L,55814L, |
| 97666 | 55815L,55816L,55817L,55818L,55819L,55820L,55821L,55822L,55823L,55824L, |
| 97667 | 55825L,55826L,55827L,55828L,55829L,55830L,55831L,55832L,55833L,55834L, |
| 97668 | 55835L,55836L,55837L,55838L,55839L,55840L,55841L,55842L,55843L,55844L, |
| 97669 | 55845L,55846L,55847L,55848L,55849L,55850L,55851L,55852L,55853L,55854L, |
| 97670 | 55855L,55856L,55857L,55858L,55859L,55860L,55861L,55862L,55863L,55864L, |
| 97671 | 55865L,55866L,55867L,55868L,55869L,55870L,55871L,55872L,55873L,55874L, |
| 97672 | 55875L,55876L,55877L,55878L,55879L,55880L,55881L,55882L,55883L,55884L, |
| 97673 | 55885L,55886L,55887L,55888L,55889L,55890L,55891L,55892L,55893L,55894L, |
| 97674 | 55895L,55896L,55897L,55898L,55899L,55900L,55901L,55902L,55903L,55904L, |
| 97675 | 55905L,55906L,55907L,55908L,55909L,55910L,55911L,55912L,55913L,55914L, |
| 97676 | 55915L,55916L,55917L,55918L,55919L,55920L,55921L,55922L,55923L,55924L, |
| 97677 | 55925L,55926L,55927L,55928L,55929L,55930L,55931L,55932L,55933L,55934L, |
| 97678 | 55935L,55936L,55937L,55938L,55939L,55940L,55941L,55942L,55943L,55944L, |
| 97679 | 55945L,55946L,55947L,55948L,55949L,55950L,55951L,55952L,55953L,55954L, |
| 97680 | 55955L,55956L,55957L,55958L,55959L,55960L,55961L,55962L,55963L,55964L, |
| 97681 | 55965L,55966L,55967L,55968L,55969L,55970L,55971L,55972L,55973L,55974L, |
| 97682 | 55975L,55976L,55977L,55978L,55979L,55980L,55981L,55982L,55983L,55984L, |
| 97683 | 55985L,55986L,55987L,55988L,55989L,55990L,55991L,55992L,55993L,55994L, |
| 97684 | 55995L,55996L,55997L,55998L,55999L,56000L,56001L,56002L,56003L,56004L, |
| 97685 | 56005L,56006L,56007L,56008L,56009L,56010L,56011L,56012L,56013L,56014L, |
| 97686 | 56015L,56016L,56017L,56018L,56019L,56020L,56021L,56022L,56023L,56024L, |
| 97687 | 56025L,56026L,56027L,56028L,56029L,56030L,56031L,56032L,56033L,56034L, |
| 97688 | 56035L,56036L,56037L,56038L,56039L,56040L,56041L,56042L,56043L,56044L, |
| 97689 | 56045L,56046L,56047L,56048L,56049L,56050L,56051L,56052L,56053L,56054L, |
| 97690 | 56055L,56056L,56057L,56058L,56059L,56060L,56061L,56062L,56063L,56064L, |
| 97691 | 56065L,56066L,56067L,56068L,56069L,56070L,56071L,56072L,56073L,56074L, |
| 97692 | 56075L,56076L,56077L,56078L,56079L,56080L,56081L,56082L,56083L,56084L, |
| 97693 | 56085L,56086L,56087L,56088L,56089L,56090L,56091L,56092L,56093L,56094L, |
| 97694 | 56095L,56096L,56097L,56098L,56099L,56100L,56101L,56102L,56103L,56104L, |
| 97695 | 56105L,56106L,56107L,56108L,56109L,56110L,56111L,56112L,56113L,56114L, |
| 97696 | 56115L,56116L,56117L,56118L,56119L,56120L,56121L,56122L,56123L,56124L, |
| 97697 | 56125L,56126L,56127L,56128L,56129L,56130L,56131L,56132L,56133L,56134L, |
| 97698 | 56135L,56136L,56137L,56138L,56139L,56140L,56141L,56142L,56143L,56144L, |
| 97699 | 56145L,56146L,56147L,56148L,56149L,56150L,56151L,56152L,56153L,56154L, |
| 97700 | 56155L,56156L,56157L,56158L,56159L,56160L,56161L,56162L,56163L,56164L, |
| 97701 | 56165L,56166L,56167L,56168L,56169L,56170L,56171L,56172L,56173L,56174L, |
| 97702 | 56175L,56176L,56177L,56178L,56179L,56180L,56181L,56182L,56183L,56184L, |
| 97703 | 56185L,56186L,56187L,56188L,56189L,56190L,56191L,56192L,56193L,56194L, |
| 97704 | 56195L,56196L,56197L,56198L,56199L,56200L,56201L,56202L,56203L,56204L, |
| 97705 | 56205L,56206L,56207L,56208L,56209L,56210L,56211L,56212L,56213L,56214L, |
| 97706 | 56215L,56216L,56217L,56218L,56219L,56220L,56221L,56222L,56223L,56224L, |
| 97707 | 56225L,56226L,56227L,56228L,56229L,56230L,56231L,56232L,56233L,56234L, |
| 97708 | 56235L,56236L,56237L,56238L,56239L,56240L,56241L,56242L,56243L,56244L, |
| 97709 | 56245L,56246L,56247L,56248L,56249L,56250L,56251L,56252L,56253L,56254L, |
| 97710 | 56255L,56256L,56257L,56258L,56259L,56260L,56261L,56262L,56263L,56264L, |
| 97711 | 56265L,56266L,56267L,56268L,56269L,56270L,56271L,56272L,56273L,56274L, |
| 97712 | 56275L,56276L,56277L,56278L,56279L,56280L,56281L,56282L,56283L,56284L, |
| 97713 | 56285L,56286L,56287L,56288L,56289L,56290L,56291L,56292L,56293L,56294L, |
| 97714 | 56295L,56296L,56297L,56298L,56299L,56300L,56301L,56302L,56303L,56304L, |
| 97715 | 56305L,56306L,56307L,56308L,56309L,56310L,56311L,56312L,56313L,56314L, |
| 97716 | 56315L,56316L,56317L,56318L,56319L,56320L,56321L,56322L,56323L,56324L, |
| 97717 | 56325L,56326L,56327L,56328L,56329L,56330L,56331L,56332L,56333L,56334L, |
| 97718 | 56335L,56336L,56337L,56338L,56339L,56340L,56341L,56342L,56343L,56344L, |
| 97719 | 56345L,56346L,56347L,56348L,56349L,56350L,56351L,56352L,56353L,56354L, |
| 97720 | 56355L,56356L,56357L,56358L,56359L,56360L,56361L,56362L,56363L,56364L, |
| 97721 | 56365L,56366L,56367L,56368L,56369L,56370L,56371L,56372L,56373L,56374L, |
| 97722 | 56375L,56376L,56377L,56378L,56379L,56380L,56381L,56382L,56383L,56384L, |
| 97723 | 56385L,56386L,56387L,56388L,56389L,56390L,56391L,56392L,56393L,56394L, |
| 97724 | 56395L,56396L,56397L,56398L,56399L,56400L,56401L,56402L,56403L,56404L, |
| 97725 | 56405L,56406L,56407L,56408L,56409L,56410L,56411L,56412L,56413L,56414L, |
| 97726 | 56415L,56416L,56417L,56418L,56419L,56420L,56421L,56422L,56423L,56424L, |
| 97727 | 56425L,56426L,56427L,56428L,56429L,56430L,56431L,56432L,56433L,56434L, |
| 97728 | 56435L,56436L,56437L,56438L,56439L,56440L,56441L,56442L,56443L,56444L, |
| 97729 | 56445L,56446L,56447L,56448L,56449L,56450L,56451L,56452L,56453L,56454L, |
| 97730 | 56455L,56456L,56457L,56458L,56459L,56460L,56461L,56462L,56463L,56464L, |
| 97731 | 56465L,56466L,56467L,56468L,56469L,56470L,56471L,56472L,56473L,56474L, |
| 97732 | 56475L,56476L,56477L,56478L,56479L,56480L,56481L,56482L,56483L,56484L, |
| 97733 | 56485L,56486L,56487L,56488L,56489L,56490L,56491L,56492L,56493L,56494L, |
| 97734 | 56495L,56496L,56497L,56498L,56499L,56500L,56501L,56502L,56503L,56504L, |
| 97735 | 56505L,56506L,56507L,56508L,56509L,56510L,56511L,56512L,56513L,56514L, |
| 97736 | 56515L,56516L,56517L,56518L,56519L,56520L,56521L,56522L,56523L,56524L, |
| 97737 | 56525L,56526L,56527L,56528L,56529L,56530L,56531L,56532L,56533L,56534L, |
| 97738 | 56535L,56536L,56537L,56538L,56539L,56540L,56541L,56542L,56543L,56544L, |
| 97739 | 56545L,56546L,56547L,56548L,56549L,56550L,56551L,56552L,56553L,56554L, |
| 97740 | 56555L,56556L,56557L,56558L,56559L,56560L,56561L,56562L,56563L,56564L, |
| 97741 | 56565L,56566L,56567L,56568L,56569L,56570L,56571L,56572L,56573L,56574L, |
| 97742 | 56575L,56576L,56577L,56578L,56579L,56580L,56581L,56582L,56583L,56584L, |
| 97743 | 56585L,56586L,56587L,56588L,56589L,56590L,56591L,56592L,56593L,56594L, |
| 97744 | 56595L,56596L,56597L,56598L,56599L,56600L,56601L,56602L,56603L,56604L, |
| 97745 | 56605L,56606L,56607L,56608L,56609L,56610L,56611L,56612L,56613L,56614L, |
| 97746 | 56615L,56616L,56617L,56618L,56619L,56620L,56621L,56622L,56623L,56624L, |
| 97747 | 56625L,56626L,56627L,56628L,56629L,56630L,56631L,56632L,56633L,56634L, |
| 97748 | 56635L,56636L,56637L,56638L,56639L,56640L,56641L,56642L,56643L,56644L, |
| 97749 | 56645L,56646L,56647L,56648L,56649L,56650L,56651L,56652L,56653L,56654L, |
| 97750 | 56655L,56656L,56657L,56658L,56659L,56660L,56661L,56662L,56663L,56664L, |
| 97751 | 56665L,56666L,56667L,56668L,56669L,56670L,56671L,56672L,56673L,56674L, |
| 97752 | 56675L,56676L,56677L,56678L,56679L,56680L,56681L,56682L,56683L,56684L, |
| 97753 | 56685L,56686L,56687L,56688L,56689L,56690L,56691L,56692L,56693L,56694L, |
| 97754 | 56695L,56696L,56697L,56698L,56699L,56700L,56701L,56702L,56703L,56704L, |
| 97755 | 56705L,56706L,56707L,56708L,56709L,56710L,56711L,56712L,56713L,56714L, |
| 97756 | 56715L,56716L,56717L,56718L,56719L,56720L,56721L,56722L,56723L,56724L, |
| 97757 | 56725L,56726L,56727L,56728L,56729L,56730L,56731L,56732L,56733L,56734L, |
| 97758 | 56735L,56736L,56737L,56738L,56739L,56740L,56741L,56742L,56743L,56744L, |
| 97759 | 56745L,56746L,56747L,56748L,56749L,56750L,56751L,56752L,56753L,56754L, |
| 97760 | 56755L,56756L,56757L,56758L,56759L,56760L,56761L,56762L,56763L,56764L, |
| 97761 | 56765L,56766L,56767L,56768L,56769L,56770L,56771L,56772L,56773L,56774L, |
| 97762 | 56775L,56776L,56777L,56778L,56779L,56780L,56781L,56782L,56783L,56784L, |
| 97763 | 56785L,56786L,56787L,56788L,56789L,56790L,56791L,56792L,56793L,56794L, |
| 97764 | 56795L,56796L,56797L,56798L,56799L,56800L,56801L,56802L,56803L,56804L, |
| 97765 | 56805L,56806L,56807L,56808L,56809L,56810L,56811L,56812L,56813L,56814L, |
| 97766 | 56815L,56816L,56817L,56818L,56819L,56820L,56821L,56822L,56823L,56824L, |
| 97767 | 56825L,56826L,56827L,56828L,56829L,56830L,56831L,56832L,56833L,56834L, |
| 97768 | 56835L,56836L,56837L,56838L,56839L,56840L,56841L,56842L,56843L,56844L, |
| 97769 | 56845L,56846L,56847L,56848L,56849L,56850L,56851L,56852L,56853L,56854L, |
| 97770 | 56855L,56856L,56857L,56858L,56859L,56860L,56861L,56862L,56863L,56864L, |
| 97771 | 56865L,56866L,56867L,56868L,56869L,56870L,56871L,56872L,56873L,56874L, |
| 97772 | 56875L,56876L,56877L,56878L,56879L,56880L,56881L,56882L,56883L,56884L, |
| 97773 | 56885L,56886L,56887L,56888L,56889L,56890L,56891L,56892L,56893L,56894L, |
| 97774 | 56895L,56896L,56897L,56898L,56899L,56900L,56901L,56902L,56903L,56904L, |
| 97775 | 56905L,56906L,56907L,56908L,56909L,56910L,56911L,56912L,56913L,56914L, |
| 97776 | 56915L,56916L,56917L,56918L,56919L,56920L,56921L,56922L,56923L,56924L, |
| 97777 | 56925L,56926L,56927L,56928L,56929L,56930L,56931L,56932L,56933L,56934L, |
| 97778 | 56935L,56936L,56937L,56938L,56939L,56940L,56941L,56942L,56943L,56944L, |
| 97779 | 56945L,56946L,56947L,56948L,56949L,56950L,56951L,56952L,56953L,56954L, |
| 97780 | 56955L,56956L,56957L,56958L,56959L,56960L,56961L,56962L,56963L,56964L, |
| 97781 | 56965L,56966L,56967L,56968L,56969L,56970L,56971L,56972L,56973L,56974L, |
| 97782 | 56975L,56976L,56977L,56978L,56979L,56980L,56981L,56982L,56983L,56984L, |
| 97783 | 56985L,56986L,56987L,56988L,56989L,56990L,56991L,56992L,56993L,56994L, |
| 97784 | 56995L,56996L,56997L,56998L,56999L,57000L,57001L,57002L,57003L,57004L, |
| 97785 | 57005L,57006L,57007L,57008L,57009L,57010L,57011L,57012L,57013L,57014L, |
| 97786 | 57015L,57016L,57017L,57018L,57019L,57020L,57021L,57022L,57023L,57024L, |
| 97787 | 57025L,57026L,57027L,57028L,57029L,57030L,57031L,57032L,57033L,57034L, |
| 97788 | 57035L,57036L,57037L,57038L,57039L,57040L,57041L,57042L,57043L,57044L, |
| 97789 | 57045L,57046L,57047L,57048L,57049L,57050L,57051L,57052L,57053L,57054L, |
| 97790 | 57055L,57056L,57057L,57058L,57059L,57060L,57061L,57062L,57063L,57064L, |
| 97791 | 57065L,57066L,57067L,57068L,57069L,57070L,57071L,57072L,57073L,57074L, |
| 97792 | 57075L,57076L,57077L,57078L,57079L,57080L,57081L,57082L,57083L,57084L, |
| 97793 | 57085L,57086L,57087L,57088L,57089L,57090L,57091L,57092L,57093L,57094L, |
| 97794 | 57095L,57096L,57097L,57098L,57099L,57100L,57101L,57102L,57103L,57104L, |
| 97795 | 57105L,57106L,57107L,57108L,57109L,57110L,57111L,57112L,57113L,57114L, |
| 97796 | 57115L,57116L,57117L,57118L,57119L,57120L,57121L,57122L,57123L,57124L, |
| 97797 | 57125L,57126L,57127L,57128L,57129L,57130L,57131L,57132L,57133L,57134L, |
| 97798 | 57135L,57136L,57137L,57138L,57139L,57140L,57141L,57142L,57143L,57144L, |
| 97799 | 57145L,57146L,57147L,57148L,57149L,57150L,57151L,57152L,57153L,57154L, |
| 97800 | 57155L,57156L,57157L,57158L,57159L,57160L,57161L,57162L,57163L,57164L, |
| 97801 | 57165L,57166L,57167L,57168L,57169L,57170L,57171L,57172L,57173L,57174L, |
| 97802 | 57175L,57176L,57177L,57178L,57179L,57180L,57181L,57182L,57183L,57184L, |
| 97803 | 57185L,57186L,57187L,57188L,57189L,57190L,57191L,57192L,57193L,57194L, |
| 97804 | 57195L,57196L,57197L,57198L,57199L,57200L,57201L,57202L,57203L,57204L, |
| 97805 | 57205L,57206L,57207L,57208L,57209L,57210L,57211L,57212L,57213L,57214L, |
| 97806 | 57215L,57216L,57217L,57218L,57219L,57220L,57221L,57222L,57223L,57224L, |
| 97807 | 57225L,57226L,57227L,57228L,57229L,57230L,57231L,57232L,57233L,57234L, |
| 97808 | 57235L,57236L,57237L,57238L,57239L,57240L,57241L,57242L,57243L,57244L, |
| 97809 | 57245L,57246L,57247L,57248L,57249L,57250L,57251L,57252L,57253L,57254L, |
| 97810 | 57255L,57256L,57257L,57258L,57259L,57260L,57261L,57262L,57263L,57264L, |
| 97811 | 57265L,57266L,57267L,57268L,57269L,57270L,57271L,57272L,57273L,57274L, |
| 97812 | 57275L,57276L,57277L,57278L,57279L,57280L,57281L,57282L,57283L,57284L, |
| 97813 | 57285L,57286L,57287L,57288L,57289L,57290L,57291L,57292L,57293L,57294L, |
| 97814 | 57295L,57296L,57297L,57298L,57299L,57300L,57301L,57302L,57303L,57304L, |
| 97815 | 57305L,57306L,57307L,57308L,57309L,57310L,57311L,57312L,57313L,57314L, |
| 97816 | 57315L,57316L,57317L,57318L,57319L,57320L,57321L,57322L,57323L,57324L, |
| 97817 | 57325L,57326L,57327L,57328L,57329L,57330L,57331L,57332L,57333L,57334L, |
| 97818 | 57335L,57336L,57337L,57338L,57339L,57340L,57341L,57342L,57343L,57344L, |
| 97819 | 57345L,57346L,57347L,57348L,57349L,57350L,57351L,57352L,57353L,57354L, |
| 97820 | 57355L,57356L,57357L,57358L,57359L,57360L,57361L,57362L,57363L,57364L, |
| 97821 | 57365L,57366L,57367L,57368L,57369L,57370L,57371L,57372L,57373L,57374L, |
| 97822 | 57375L,57376L,57377L,57378L,57379L,57380L,57381L,57382L,57383L,57384L, |
| 97823 | 57385L,57386L,57387L,57388L,57389L,57390L,57391L,57392L,57393L,57394L, |
| 97824 | 57395L,57396L,57397L,57398L,57399L,57400L,57401L,57402L,57403L,57404L, |
| 97825 | 57405L,57406L,57407L,57408L,57409L,57410L,57411L,57412L,57413L,57414L, |
| 97826 | 57415L,57416L,57417L,57418L,57419L,57420L,57421L,57422L,57423L,57424L, |
| 97827 | 57425L,57426L,57427L,57428L,57429L,57430L,57431L,57432L,57433L,57434L, |
| 97828 | 57435L,57436L,57437L,57438L,57439L,57440L,57441L,57442L,57443L,57444L, |
| 97829 | 57445L,57446L,57447L,57448L,57449L,57450L,57451L,57452L,57453L,57454L, |
| 97830 | 57455L,57456L,57457L,57458L,57459L,57460L,57461L,57462L,57463L,57464L, |
| 97831 | 57465L,57466L,57467L,57468L,57469L,57470L,57471L,57472L,57473L,57474L, |
| 97832 | 57475L,57476L,57477L,57478L,57479L,57480L,57481L,57482L,57483L,57484L, |
| 97833 | 57485L,57486L,57487L,57488L,57489L,57490L,57491L,57492L,57493L,57494L, |
| 97834 | 57495L,57496L,57497L,57498L,57499L,57500L,57501L,57502L,57503L,57504L, |
| 97835 | 57505L,57506L,57507L,57508L,57509L,57510L,57511L,57512L,57513L,57514L, |
| 97836 | 57515L,57516L,57517L,57518L,57519L,57520L,57521L,57522L,57523L,57524L, |
| 97837 | 57525L,57526L,57527L,57528L,57529L,57530L,57531L,57532L,57533L,57534L, |
| 97838 | 57535L,57536L,57537L,57538L,57539L,57540L,57541L,57542L,57543L,57544L, |
| 97839 | 57545L,57546L,57547L,57548L,57549L,57550L,57551L,57552L,57553L,57554L, |
| 97840 | 57555L,57556L,57557L,57558L,57559L,57560L,57561L,57562L,57563L,57564L, |
| 97841 | 57565L,57566L,57567L,57568L,57569L,57570L,57571L,57572L,57573L,57574L, |
| 97842 | 57575L,57576L,57577L,57578L,57579L,57580L,57581L,57582L,57583L,57584L, |
| 97843 | 57585L,57586L,57587L,57588L,57589L,57590L,57591L,57592L,57593L,57594L, |
| 97844 | 57595L,57596L,57597L,57598L,57599L,57600L,57601L,57602L,57603L,57604L, |
| 97845 | 57605L,57606L,57607L,57608L,57609L,57610L,57611L,57612L,57613L,57614L, |
| 97846 | 57615L,57616L,57617L,57618L,57619L,57620L,57621L,57622L,57623L,57624L, |
| 97847 | 57625L,57626L,57627L,57628L,57629L,57630L,57631L,57632L,57633L,57634L, |
| 97848 | 57635L,57636L,57637L,57638L,57639L,57640L,57641L,57642L,57643L,57644L, |
| 97849 | 57645L,57646L,57647L,57648L,57649L,57650L,57651L,57652L,57653L,57654L, |
| 97850 | 57655L,57656L,57657L,57658L,57659L,57660L,57661L,57662L,57663L,57664L, |
| 97851 | 57665L,57666L,57667L,57668L,57669L,57670L,57671L,57672L,57673L,57674L, |
| 97852 | 57675L,57676L,57677L,57678L,57679L,57680L,57681L,57682L,57683L,57684L, |
| 97853 | 57685L,57686L,57687L,57688L,57689L,57690L,57691L,57692L,57693L,57694L, |
| 97854 | 57695L,57696L,57697L,57698L,57699L,57700L,57701L,57702L,57703L,57704L, |
| 97855 | 57705L,57706L,57707L,57708L,57709L,57710L,57711L,57712L,57713L,57714L, |
| 97856 | 57715L,57716L,57717L,57718L,57719L,57720L,57721L,57722L,57723L,57724L, |
| 97857 | 57725L,57726L,57727L,57728L,57729L,57730L,57731L,57732L,57733L,57734L, |
| 97858 | 57735L,57736L,57737L,57738L,57739L,57740L,57741L,57742L,57743L,57744L, |
| 97859 | 57745L,57746L,57747L,57748L,57749L,57750L,57751L,57752L,57753L,57754L, |
| 97860 | 57755L,57756L,57757L,57758L,57759L,57760L,57761L,57762L,57763L,57764L, |
| 97861 | 57765L,57766L,57767L,57768L,57769L,57770L,57771L,57772L,57773L,57774L, |
| 97862 | 57775L,57776L,57777L,57778L,57779L,57780L,57781L,57782L,57783L,57784L, |
| 97863 | 57785L,57786L,57787L,57788L,57789L,57790L,57791L,57792L,57793L,57794L, |
| 97864 | 57795L,57796L,57797L,57798L,57799L,57800L,57801L,57802L,57803L,57804L, |
| 97865 | 57805L,57806L,57807L,57808L,57809L,57810L,57811L,57812L,57813L,57814L, |
| 97866 | 57815L,57816L,57817L,57818L,57819L,57820L,57821L,57822L,57823L,57824L, |
| 97867 | 57825L,57826L,57827L,57828L,57829L,57830L,57831L,57832L,57833L,57834L, |
| 97868 | 57835L,57836L,57837L,57838L,57839L,57840L,57841L,57842L,57843L,57844L, |
| 97869 | 57845L,57846L,57847L,57848L,57849L,57850L,57851L,57852L,57853L,57854L, |
| 97870 | 57855L,57856L,57857L,57858L,57859L,57860L,57861L,57862L,57863L,57864L, |
| 97871 | 57865L,57866L,57867L,57868L,57869L,57870L,57871L,57872L,57873L,57874L, |
| 97872 | 57875L,57876L,57877L,57878L,57879L,57880L,57881L,57882L,57883L,57884L, |
| 97873 | 57885L,57886L,57887L,57888L,57889L,57890L,57891L,57892L,57893L,57894L, |
| 97874 | 57895L,57896L,57897L,57898L,57899L,57900L,57901L,57902L,57903L,57904L, |
| 97875 | 57905L,57906L,57907L,57908L,57909L,57910L,57911L,57912L,57913L,57914L, |
| 97876 | 57915L,57916L,57917L,57918L,57919L,57920L,57921L,57922L,57923L,57924L, |
| 97877 | 57925L,57926L,57927L,57928L,57929L,57930L,57931L,57932L,57933L,57934L, |
| 97878 | 57935L,57936L,57937L,57938L,57939L,57940L,57941L,57942L,57943L,57944L, |
| 97879 | 57945L,57946L,57947L,57948L,57949L,57950L,57951L,57952L,57953L,57954L, |
| 97880 | 57955L,57956L,57957L,57958L,57959L,57960L,57961L,57962L,57963L,57964L, |
| 97881 | 57965L,57966L,57967L,57968L,57969L,57970L,57971L,57972L,57973L,57974L, |
| 97882 | 57975L,57976L,57977L,57978L,57979L,57980L,57981L,57982L,57983L,57984L, |
| 97883 | 57985L,57986L,57987L,57988L,57989L,57990L,57991L,57992L,57993L,57994L, |
| 97884 | 57995L,57996L,57997L,57998L,57999L,58000L,58001L,58002L,58003L,58004L, |
| 97885 | 58005L,58006L,58007L,58008L,58009L,58010L,58011L,58012L,58013L,58014L, |
| 97886 | 58015L,58016L,58017L,58018L,58019L,58020L,58021L,58022L,58023L,58024L, |
| 97887 | 58025L,58026L,58027L,58028L,58029L,58030L,58031L,58032L,58033L,58034L, |
| 97888 | 58035L,58036L,58037L,58038L,58039L,58040L,58041L,58042L,58043L,58044L, |
| 97889 | 58045L,58046L,58047L,58048L,58049L,58050L,58051L,58052L,58053L,58054L, |
| 97890 | 58055L,58056L,58057L,58058L,58059L,58060L,58061L,58062L,58063L,58064L, |
| 97891 | 58065L,58066L,58067L,58068L,58069L,58070L,58071L,58072L,58073L,58074L, |
| 97892 | 58075L,58076L,58077L,58078L,58079L,58080L,58081L,58082L,58083L,58084L, |
| 97893 | 58085L,58086L,58087L,58088L,58089L,58090L,58091L,58092L,58093L,58094L, |
| 97894 | 58095L,58096L,58097L,58098L,58099L,58100L,58101L,58102L,58103L,58104L, |
| 97895 | 58105L,58106L,58107L,58108L,58109L,58110L,58111L,58112L,58113L,58114L, |
| 97896 | 58115L,58116L,58117L,58118L,58119L,58120L,58121L,58122L,58123L,58124L, |
| 97897 | 58125L,58126L,58127L,58128L,58129L,58130L,58131L,58132L,58133L,58134L, |
| 97898 | 58135L,58136L,58137L,58138L,58139L,58140L,58141L,58142L,58143L,58144L, |
| 97899 | 58145L,58146L,58147L,58148L,58149L,58150L,58151L,58152L,58153L,58154L, |
| 97900 | 58155L,58156L,58157L,58158L,58159L,58160L,58161L,58162L,58163L,58164L, |
| 97901 | 58165L,58166L,58167L,58168L,58169L,58170L,58171L,58172L,58173L,58174L, |
| 97902 | 58175L,58176L,58177L,58178L,58179L,58180L,58181L,58182L,58183L,58184L, |
| 97903 | 58185L,58186L,58187L,58188L,58189L,58190L,58191L,58192L,58193L,58194L, |
| 97904 | 58195L,58196L,58197L,58198L,58199L,58200L,58201L,58202L,58203L,58204L, |
| 97905 | 58205L,58206L,58207L,58208L,58209L,58210L,58211L,58212L,58213L,58214L, |
| 97906 | 58215L,58216L,58217L,58218L,58219L,58220L,58221L,58222L,58223L,58224L, |
| 97907 | 58225L,58226L,58227L,58228L,58229L,58230L,58231L,58232L,58233L,58234L, |
| 97908 | 58235L,58236L,58237L,58238L,58239L,58240L,58241L,58242L,58243L,58244L, |
| 97909 | 58245L,58246L,58247L,58248L,58249L,58250L,58251L,58252L,58253L,58254L, |
| 97910 | 58255L,58256L,58257L,58258L,58259L,58260L,58261L,58262L,58263L,58264L, |
| 97911 | 58265L,58266L,58267L,58268L,58269L,58270L,58271L,58272L,58273L,58274L, |
| 97912 | 58275L,58276L,58277L,58278L,58279L,58280L,58281L,58282L,58283L,58284L, |
| 97913 | 58285L,58286L,58287L,58288L,58289L,58290L,58291L,58292L,58293L,58294L, |
| 97914 | 58295L,58296L,58297L,58298L,58299L,58300L,58301L,58302L,58303L,58304L, |
| 97915 | 58305L,58306L,58307L,58308L,58309L,58310L,58311L,58312L,58313L,58314L, |
| 97916 | 58315L,58316L,58317L,58318L,58319L,58320L,58321L,58322L,58323L,58324L, |
| 97917 | 58325L,58326L,58327L,58328L,58329L,58330L,58331L,58332L,58333L,58334L, |
| 97918 | 58335L,58336L,58337L,58338L,58339L,58340L,58341L,58342L,58343L,58344L, |
| 97919 | 58345L,58346L,58347L,58348L,58349L,58350L,58351L,58352L,58353L,58354L, |
| 97920 | 58355L,58356L,58357L,58358L,58359L,58360L,58361L,58362L,58363L,58364L, |
| 97921 | 58365L,58366L,58367L,58368L,58369L,58370L,58371L,58372L,58373L,58374L, |
| 97922 | 58375L,58376L,58377L,58378L,58379L,58380L,58381L,58382L,58383L,58384L, |
| 97923 | 58385L,58386L,58387L,58388L,58389L,58390L,58391L,58392L,58393L,58394L, |
| 97924 | 58395L,58396L,58397L,58398L,58399L,58400L,58401L,58402L,58403L,58404L, |
| 97925 | 58405L,58406L,58407L,58408L,58409L,58410L,58411L,58412L,58413L,58414L, |
| 97926 | 58415L,58416L,58417L,58418L,58419L,58420L,58421L,58422L,58423L,58424L, |
| 97927 | 58425L,58426L,58427L,58428L,58429L,58430L,58431L,58432L,58433L,58434L, |
| 97928 | 58435L,58436L,58437L,58438L,58439L,58440L,58441L,58442L,58443L,58444L, |
| 97929 | 58445L,58446L,58447L,58448L,58449L,58450L,58451L,58452L,58453L,58454L, |
| 97930 | 58455L,58456L,58457L,58458L,58459L,58460L,58461L,58462L,58463L,58464L, |
| 97931 | 58465L,58466L,58467L,58468L,58469L,58470L,58471L,58472L,58473L,58474L, |
| 97932 | 58475L,58476L,58477L,58478L,58479L,58480L,58481L,58482L,58483L,58484L, |
| 97933 | 58485L,58486L,58487L,58488L,58489L,58490L,58491L,58492L,58493L,58494L, |
| 97934 | 58495L,58496L,58497L,58498L,58499L,58500L,58501L,58502L,58503L,58504L, |
| 97935 | 58505L,58506L,58507L,58508L,58509L,58510L,58511L,58512L,58513L,58514L, |
| 97936 | 58515L,58516L,58517L,58518L,58519L,58520L,58521L,58522L,58523L,58524L, |
| 97937 | 58525L,58526L,58527L,58528L,58529L,58530L,58531L,58532L,58533L,58534L, |
| 97938 | 58535L,58536L,58537L,58538L,58539L,58540L,58541L,58542L,58543L,58544L, |
| 97939 | 58545L,58546L,58547L,58548L,58549L,58550L,58551L,58552L,58553L,58554L, |
| 97940 | 58555L,58556L,58557L,58558L,58559L,58560L,58561L,58562L,58563L,58564L, |
| 97941 | 58565L,58566L,58567L,58568L,58569L,58570L,58571L,58572L,58573L,58574L, |
| 97942 | 58575L,58576L,58577L,58578L,58579L,58580L,58581L,58582L,58583L,58584L, |
| 97943 | 58585L,58586L,58587L,58588L,58589L,58590L,58591L,58592L,58593L,58594L, |
| 97944 | 58595L,58596L,58597L,58598L,58599L,58600L,58601L,58602L,58603L,58604L, |
| 97945 | 58605L,58606L,58607L,58608L,58609L,58610L,58611L,58612L,58613L,58614L, |
| 97946 | 58615L,58616L,58617L,58618L,58619L,58620L,58621L,58622L,58623L,58624L, |
| 97947 | 58625L,58626L,58627L,58628L,58629L,58630L,58631L,58632L,58633L,58634L, |
| 97948 | 58635L,58636L,58637L,58638L,58639L,58640L,58641L,58642L,58643L,58644L, |
| 97949 | 58645L,58646L,58647L,58648L,58649L,58650L,58651L,58652L,58653L,58654L, |
| 97950 | 58655L,58656L,58657L,58658L,58659L,58660L,58661L,58662L,58663L,58664L, |
| 97951 | 58665L,58666L,58667L,58668L,58669L,58670L,58671L,58672L,58673L,58674L, |
| 97952 | 58675L,58676L,58677L,58678L,58679L,58680L,58681L,58682L,58683L,58684L, |
| 97953 | 58685L,58686L,58687L,58688L,58689L,58690L,58691L,58692L,58693L,58694L, |
| 97954 | 58695L,58696L,58697L,58698L,58699L,58700L,58701L,58702L,58703L,58704L, |
| 97955 | 58705L,58706L,58707L,58708L,58709L,58710L,58711L,58712L,58713L,58714L, |
| 97956 | 58715L,58716L,58717L,58718L,58719L,58720L,58721L,58722L,58723L,58724L, |
| 97957 | 58725L,58726L,58727L,58728L,58729L,58730L,58731L,58732L,58733L,58734L, |
| 97958 | 58735L,58736L,58737L,58738L,58739L,58740L,58741L,58742L,58743L,58744L, |
| 97959 | 58745L,58746L,58747L,58748L,58749L,58750L,58751L,58752L,58753L,58754L, |
| 97960 | 58755L,58756L,58757L,58758L,58759L,58760L,58761L,58762L,58763L,58764L, |
| 97961 | 58765L,58766L,58767L,58768L,58769L,58770L,58771L,58772L,58773L,58774L, |
| 97962 | 58775L,58776L,58777L,58778L,58779L,58780L,58781L,58782L,58783L,58784L, |
| 97963 | 58785L,58786L,58787L,58788L,58789L,58790L,58791L,58792L,58793L,58794L, |
| 97964 | 58795L,58796L,58797L,58798L,58799L,58800L,58801L,58802L,58803L,58804L, |
| 97965 | 58805L,58806L,58807L,58808L,58809L,58810L,58811L,58812L,58813L,58814L, |
| 97966 | 58815L,58816L,58817L,58818L,58819L,58820L,58821L,58822L,58823L,58824L, |
| 97967 | 58825L,58826L,58827L,58828L,58829L,58830L,58831L,58832L,58833L,58834L, |
| 97968 | 58835L,58836L,58837L,58838L,58839L,58840L,58841L,58842L,58843L,58844L, |
| 97969 | 58845L,58846L,58847L,58848L,58849L,58850L,58851L,58852L,58853L,58854L, |
| 97970 | 58855L,58856L,58857L,58858L,58859L,58860L,58861L,58862L,58863L,58864L, |
| 97971 | 58865L,58866L,58867L,58868L,58869L,58870L,58871L,58872L,58873L,58874L, |
| 97972 | 58875L,58876L,58877L,58878L,58879L,58880L,58881L,58882L,58883L,58884L, |
| 97973 | 58885L,58886L,58887L,58888L,58889L,58890L,58891L,58892L,58893L,58894L, |
| 97974 | 58895L,58896L,58897L,58898L,58899L,58900L,58901L,58902L,58903L,58904L, |
| 97975 | 58905L,58906L,58907L,58908L,58909L,58910L,58911L,58912L,58913L,58914L, |
| 97976 | 58915L,58916L,58917L,58918L,58919L,58920L,58921L,58922L,58923L,58924L, |
| 97977 | 58925L,58926L,58927L,58928L,58929L,58930L,58931L,58932L,58933L,58934L, |
| 97978 | 58935L,58936L,58937L,58938L,58939L,58940L,58941L,58942L,58943L,58944L, |
| 97979 | 58945L,58946L,58947L,58948L,58949L,58950L,58951L,58952L,58953L,58954L, |
| 97980 | 58955L,58956L,58957L,58958L,58959L,58960L,58961L,58962L,58963L,58964L, |
| 97981 | 58965L,58966L,58967L,58968L,58969L,58970L,58971L,58972L,58973L,58974L, |
| 97982 | 58975L,58976L,58977L,58978L,58979L,58980L,58981L,58982L,58983L,58984L, |
| 97983 | 58985L,58986L,58987L,58988L,58989L,58990L,58991L,58992L,58993L,58994L, |
| 97984 | 58995L,58996L,58997L,58998L,58999L,59000L,59001L,59002L,59003L,59004L, |
| 97985 | 59005L,59006L,59007L,59008L,59009L,59010L,59011L,59012L,59013L,59014L, |
| 97986 | 59015L,59016L,59017L,59018L,59019L,59020L,59021L,59022L,59023L,59024L, |
| 97987 | 59025L,59026L,59027L,59028L,59029L,59030L,59031L,59032L,59033L,59034L, |
| 97988 | 59035L,59036L,59037L,59038L,59039L,59040L,59041L,59042L,59043L,59044L, |
| 97989 | 59045L,59046L,59047L,59048L,59049L,59050L,59051L,59052L,59053L,59054L, |
| 97990 | 59055L,59056L,59057L,59058L,59059L,59060L,59061L,59062L,59063L,59064L, |
| 97991 | 59065L,59066L,59067L,59068L,59069L,59070L,59071L,59072L,59073L,59074L, |
| 97992 | 59075L,59076L,59077L,59078L,59079L,59080L,59081L,59082L,59083L,59084L, |
| 97993 | 59085L,59086L,59087L,59088L,59089L,59090L,59091L,59092L,59093L,59094L, |
| 97994 | 59095L,59096L,59097L,59098L,59099L,59100L,59101L,59102L,59103L,59104L, |
| 97995 | 59105L,59106L,59107L,59108L,59109L,59110L,59111L,59112L,59113L,59114L, |
| 97996 | 59115L,59116L,59117L,59118L,59119L,59120L,59121L,59122L,59123L,59124L, |
| 97997 | 59125L,59126L,59127L,59128L,59129L,59130L,59131L,59132L,59133L,59134L, |
| 97998 | 59135L,59136L,59137L,59138L,59139L,59140L,59141L,59142L,59143L,59144L, |
| 97999 | 59145L,59146L,59147L,59148L,59149L,59150L,59151L,59152L,59153L,59154L, |
| 98000 | 59155L,59156L,59157L,59158L,59159L,59160L,59161L,59162L,59163L,59164L, |
| 98001 | 59165L,59166L,59167L,59168L,59169L,59170L,59171L,59172L,59173L,59174L, |
| 98002 | 59175L,59176L,59177L,59178L,59179L,59180L,59181L,59182L,59183L,59184L, |
| 98003 | 59185L,59186L,59187L,59188L,59189L,59190L,59191L,59192L,59193L,59194L, |
| 98004 | 59195L,59196L,59197L,59198L,59199L,59200L,59201L,59202L,59203L,59204L, |
| 98005 | 59205L,59206L,59207L,59208L,59209L,59210L,59211L,59212L,59213L,59214L, |
| 98006 | 59215L,59216L,59217L,59218L,59219L,59220L,59221L,59222L,59223L,59224L, |
| 98007 | 59225L,59226L,59227L,59228L,59229L,59230L,59231L,59232L,59233L,59234L, |
| 98008 | 59235L,59236L,59237L,59238L,59239L,59240L,59241L,59242L,59243L,59244L, |
| 98009 | 59245L,59246L,59247L,59248L,59249L,59250L,59251L,59252L,59253L,59254L, |
| 98010 | 59255L,59256L,59257L,59258L,59259L,59260L,59261L,59262L,59263L,59264L, |
| 98011 | 59265L,59266L,59267L,59268L,59269L,59270L,59271L,59272L,59273L,59274L, |
| 98012 | 59275L,59276L,59277L,59278L,59279L,59280L,59281L,59282L,59283L,59284L, |
| 98013 | 59285L,59286L,59287L,59288L,59289L,59290L,59291L,59292L,59293L,59294L, |
| 98014 | 59295L,59296L,59297L,59298L,59299L,59300L,59301L,59302L,59303L,59304L, |
| 98015 | 59305L,59306L,59307L,59308L,59309L,59310L,59311L,59312L,59313L,59314L, |
| 98016 | 59315L,59316L,59317L,59318L,59319L,59320L,59321L,59322L,59323L,59324L, |
| 98017 | 59325L,59326L,59327L,59328L,59329L,59330L,59331L,59332L,59333L,59334L, |
| 98018 | 59335L,59336L,59337L,59338L,59339L,59340L,59341L,59342L,59343L,59344L, |
| 98019 | 59345L,59346L,59347L,59348L,59349L,59350L,59351L,59352L,59353L,59354L, |
| 98020 | 59355L,59356L,59357L,59358L,59359L,59360L,59361L,59362L,59363L,59364L, |
| 98021 | 59365L,59366L,59367L,59368L,59369L,59370L,59371L,59372L,59373L,59374L, |
| 98022 | 59375L,59376L,59377L,59378L,59379L,59380L,59381L,59382L,59383L,59384L, |
| 98023 | 59385L,59386L,59387L,59388L,59389L,59390L,59391L,59392L,59393L,59394L, |
| 98024 | 59395L,59396L,59397L,59398L,59399L,59400L,59401L,59402L,59403L,59404L, |
| 98025 | 59405L,59406L,59407L,59408L,59409L,59410L,59411L,59412L,59413L,59414L, |
| 98026 | 59415L,59416L,59417L,59418L,59419L,59420L,59421L,59422L,59423L,59424L, |
| 98027 | 59425L,59426L,59427L,59428L,59429L,59430L,59431L,59432L,59433L,59434L, |
| 98028 | 59435L,59436L,59437L,59438L,59439L,59440L,59441L,59442L,59443L,59444L, |
| 98029 | 59445L,59446L,59447L,59448L,59449L,59450L,59451L,59452L,59453L,59454L, |
| 98030 | 59455L,59456L,59457L,59458L,59459L,59460L,59461L,59462L,59463L,59464L, |
| 98031 | 59465L,59466L,59467L,59468L,59469L,59470L,59471L,59472L,59473L,59474L, |
| 98032 | 59475L,59476L,59477L,59478L,59479L,59480L,59481L,59482L,59483L,59484L, |
| 98033 | 59485L,59486L,59487L,59488L,59489L,59490L,59491L,59492L,59493L,59494L, |
| 98034 | 59495L,59496L,59497L,59498L,59499L,59500L,59501L,59502L,59503L,59504L, |
| 98035 | 59505L,59506L,59507L,59508L,59509L,59510L,59511L,59512L,59513L,59514L, |
| 98036 | 59515L,59516L,59517L,59518L,59519L,59520L,59521L,59522L,59523L,59524L, |
| 98037 | 59525L,59526L,59527L,59528L,59529L,59530L,59531L,59532L,59533L,59534L, |
| 98038 | 59535L,59536L,59537L,59538L,59539L,59540L,59541L,59542L,59543L,59544L, |
| 98039 | 59545L,59546L,59547L,59548L,59549L,59550L,59551L,59552L,59553L,59554L, |
| 98040 | 59555L,59556L,59557L,59558L,59559L,59560L,59561L,59562L,59563L,59564L, |
| 98041 | 59565L,59566L,59567L,59568L,59569L,59570L,59571L,59572L,59573L,59574L, |
| 98042 | 59575L,59576L,59577L,59578L,59579L,59580L,59581L,59582L,59583L,59584L, |
| 98043 | 59585L,59586L,59587L,59588L,59589L,59590L,59591L,59592L,59593L,59594L, |
| 98044 | 59595L,59596L,59597L,59598L,59599L,59600L,59601L,59602L,59603L,59604L, |
| 98045 | 59605L,59606L,59607L,59608L,59609L,59610L,59611L,59612L,59613L,59614L, |
| 98046 | 59615L,59616L,59617L,59618L,59619L,59620L,59621L,59622L,59623L,59624L, |
| 98047 | 59625L,59626L,59627L,59628L,59629L,59630L,59631L,59632L,59633L,59634L, |
| 98048 | 59635L,59636L,59637L,59638L,59639L,59640L,59641L,59642L,59643L,59644L, |
| 98049 | 59645L,59646L,59647L,59648L,59649L,59650L,59651L,59652L,59653L,59654L, |
| 98050 | 59655L,59656L,59657L,59658L,59659L,59660L,59661L,59662L,59663L,59664L, |
| 98051 | 59665L,59666L,59667L,59668L,59669L,59670L,59671L,59672L,59673L,59674L, |
| 98052 | 59675L,59676L,59677L,59678L,59679L,59680L,59681L,59682L,59683L,59684L, |
| 98053 | 59685L,59686L,59687L,59688L,59689L,59690L,59691L,59692L,59693L,59694L, |
| 98054 | 59695L,59696L,59697L,59698L,59699L,59700L,59701L,59702L,59703L,59704L, |
| 98055 | 59705L,59706L,59707L,59708L,59709L,59710L,59711L,59712L,59713L,59714L, |
| 98056 | 59715L,59716L,59717L,59718L,59719L,59720L,59721L,59722L,59723L,59724L, |
| 98057 | 59725L,59726L,59727L,59728L,59729L,59730L,59731L,59732L,59733L,59734L, |
| 98058 | 59735L,59736L,59737L,59738L,59739L,59740L,59741L,59742L,59743L,59744L, |
| 98059 | 59745L,59746L,59747L,59748L,59749L,59750L,59751L,59752L,59753L,59754L, |
| 98060 | 59755L,59756L,59757L,59758L,59759L,59760L,59761L,59762L,59763L,59764L, |
| 98061 | 59765L,59766L,59767L,59768L,59769L,59770L,59771L,59772L,59773L,59774L, |
| 98062 | 59775L,59776L,59777L,59778L,59779L,59780L,59781L,59782L,59783L,59784L, |
| 98063 | 59785L,59786L,59787L,59788L,59789L,59790L,59791L,59792L,59793L,59794L, |
| 98064 | 59795L,59796L,59797L,59798L,59799L,59800L,59801L,59802L,59803L,59804L, |
| 98065 | 59805L,59806L,59807L,59808L,59809L,59810L,59811L,59812L,59813L,59814L, |
| 98066 | 59815L,59816L,59817L,59818L,59819L,59820L,59821L,59822L,59823L,59824L, |
| 98067 | 59825L,59826L,59827L,59828L,59829L,59830L,59831L,59832L,59833L,59834L, |
| 98068 | 59835L,59836L,59837L,59838L,59839L,59840L,59841L,59842L,59843L,59844L, |
| 98069 | 59845L,59846L,59847L,59848L,59849L,59850L,59851L,59852L,59853L,59854L, |
| 98070 | 59855L,59856L,59857L,59858L,59859L,59860L,59861L,59862L,59863L,59864L, |
| 98071 | 59865L,59866L,59867L,59868L,59869L,59870L,59871L,59872L,59873L,59874L, |
| 98072 | 59875L,59876L,59877L,59878L,59879L,59880L,59881L,59882L,59883L,59884L, |
| 98073 | 59885L,59886L,59887L,59888L,59889L,59890L,59891L,59892L,59893L,59894L, |
| 98074 | 59895L,59896L,59897L,59898L,59899L,59900L,59901L,59902L,59903L,59904L, |
| 98075 | 59905L,59906L,59907L,59908L,59909L,59910L,59911L,59912L,59913L,59914L, |
| 98076 | 59915L,59916L,59917L,59918L,59919L,59920L,59921L,59922L,59923L,59924L, |
| 98077 | 59925L,59926L,59927L,59928L,59929L,59930L,59931L,59932L,59933L,59934L, |
| 98078 | 59935L,59936L,59937L,59938L,59939L,59940L,59941L,59942L,59943L,59944L, |
| 98079 | 59945L,59946L,59947L,59948L,59949L,59950L,59951L,59952L,59953L,59954L, |
| 98080 | 59955L,59956L,59957L,59958L,59959L,59960L,59961L,59962L,59963L,59964L, |
| 98081 | 59965L,59966L,59967L,59968L,59969L,59970L,59971L,59972L,59973L,59974L, |
| 98082 | 59975L,59976L,59977L,59978L,59979L,59980L,59981L,59982L,59983L,59984L, |
| 98083 | 59985L,59986L,59987L,59988L,59989L,59990L,59991L,59992L,59993L,59994L, |
| 98084 | 59995L,59996L,59997L,59998L,59999L,60000L,60001L,60002L,60003L,60004L, |
| 98085 | 60005L,60006L,60007L,60008L,60009L,60010L,60011L,60012L,60013L,60014L, |
| 98086 | 60015L,60016L,60017L,60018L,60019L,60020L,60021L,60022L,60023L,60024L, |
| 98087 | 60025L,60026L,60027L,60028L,60029L,60030L,60031L,60032L,60033L,60034L, |
| 98088 | 60035L,60036L,60037L,60038L,60039L,60040L,60041L,60042L,60043L,60044L, |
| 98089 | 60045L,60046L,60047L,60048L,60049L,60050L,60051L,60052L,60053L,60054L, |
| 98090 | 60055L,60056L,60057L,60058L,60059L,60060L,60061L,60062L,60063L,60064L, |
| 98091 | 60065L,60066L,60067L,60068L,60069L,60070L,60071L,60072L,60073L,60074L, |
| 98092 | 60075L,60076L,60077L,60078L,60079L,60080L,60081L,60082L,60083L,60084L, |
| 98093 | 60085L,60086L,60087L,60088L,60089L,60090L,60091L,60092L,60093L,60094L, |
| 98094 | 60095L,60096L,60097L,60098L,60099L,60100L,60101L,60102L,60103L,60104L, |
| 98095 | 60105L,60106L,60107L,60108L,60109L,60110L,60111L,60112L,60113L,60114L, |
| 98096 | 60115L,60116L,60117L,60118L,60119L,60120L,60121L,60122L,60123L,60124L, |
| 98097 | 60125L,60126L,60127L,60128L,60129L,60130L,60131L,60132L,60133L,60134L, |
| 98098 | 60135L,60136L,60137L,60138L,60139L,60140L,60141L,60142L,60143L,60144L, |
| 98099 | 60145L,60146L,60147L,60148L,60149L,60150L,60151L,60152L,60153L,60154L, |
| 98100 | 60155L,60156L,60157L,60158L,60159L,60160L,60161L,60162L,60163L,60164L, |
| 98101 | 60165L,60166L,60167L,60168L,60169L,60170L,60171L,60172L,60173L,60174L, |
| 98102 | 60175L,60176L,60177L,60178L,60179L,60180L,60181L,60182L,60183L,60184L, |
| 98103 | 60185L,60186L,60187L,60188L,60189L,60190L,60191L,60192L,60193L,60194L, |
| 98104 | 60195L,60196L,60197L,60198L,60199L,60200L,60201L,60202L,60203L,60204L, |
| 98105 | 60205L,60206L,60207L,60208L,60209L,60210L,60211L,60212L,60213L,60214L, |
| 98106 | 60215L,60216L,60217L,60218L,60219L,60220L,60221L,60222L,60223L,60224L, |
| 98107 | 60225L,60226L,60227L,60228L,60229L,60230L,60231L,60232L,60233L,60234L, |
| 98108 | 60235L,60236L,60237L,60238L,60239L,60240L,60241L,60242L,60243L,60244L, |
| 98109 | 60245L,60246L,60247L,60248L,60249L,60250L,60251L,60252L,60253L,60254L, |
| 98110 | 60255L,60256L,60257L,60258L,60259L,60260L,60261L,60262L,60263L,60264L, |
| 98111 | 60265L,60266L,60267L,60268L,60269L,60270L,60271L,60272L,60273L,60274L, |
| 98112 | 60275L,60276L,60277L,60278L,60279L,60280L,60281L,60282L,60283L,60284L, |
| 98113 | 60285L,60286L,60287L,60288L,60289L,60290L,60291L,60292L,60293L,60294L, |
| 98114 | 60295L,60296L,60297L,60298L,60299L,60300L,60301L,60302L,60303L,60304L, |
| 98115 | 60305L,60306L,60307L,60308L,60309L,60310L,60311L,60312L,60313L,60314L, |
| 98116 | 60315L,60316L,60317L,60318L,60319L,60320L,60321L,60322L,60323L,60324L, |
| 98117 | 60325L,60326L,60327L,60328L,60329L,60330L,60331L,60332L,60333L,60334L, |
| 98118 | 60335L,60336L,60337L,60338L,60339L,60340L,60341L,60342L,60343L,60344L, |
| 98119 | 60345L,60346L,60347L,60348L,60349L,60350L,60351L,60352L,60353L,60354L, |
| 98120 | 60355L,60356L,60357L,60358L,60359L,60360L,60361L,60362L,60363L,60364L, |
| 98121 | 60365L,60366L,60367L,60368L,60369L,60370L,60371L,60372L,60373L,60374L, |
| 98122 | 60375L,60376L,60377L,60378L,60379L,60380L,60381L,60382L,60383L,60384L, |
| 98123 | 60385L,60386L,60387L,60388L,60389L,60390L,60391L,60392L,60393L,60394L, |
| 98124 | 60395L,60396L,60397L,60398L,60399L,60400L,60401L,60402L,60403L,60404L, |
| 98125 | 60405L,60406L,60407L,60408L,60409L,60410L,60411L,60412L,60413L,60414L, |
| 98126 | 60415L,60416L,60417L,60418L,60419L,60420L,60421L,60422L,60423L,60424L, |
| 98127 | 60425L,60426L,60427L,60428L,60429L,60430L,60431L,60432L,60433L,60434L, |
| 98128 | 60435L,60436L,60437L,60438L,60439L,60440L,60441L,60442L,60443L,60444L, |
| 98129 | 60445L,60446L,60447L,60448L,60449L,60450L,60451L,60452L,60453L,60454L, |
| 98130 | 60455L,60456L,60457L,60458L,60459L,60460L,60461L,60462L,60463L,60464L, |
| 98131 | 60465L,60466L,60467L,60468L,60469L,60470L,60471L,60472L,60473L,60474L, |
| 98132 | 60475L,60476L,60477L,60478L,60479L,60480L,60481L,60482L,60483L,60484L, |
| 98133 | 60485L,60486L,60487L,60488L,60489L,60490L,60491L,60492L,60493L,60494L, |
| 98134 | 60495L,60496L,60497L,60498L,60499L,60500L,60501L,60502L,60503L,60504L, |
| 98135 | 60505L,60506L,60507L,60508L,60509L,60510L,60511L,60512L,60513L,60514L, |
| 98136 | 60515L,60516L,60517L,60518L,60519L,60520L,60521L,60522L,60523L,60524L, |
| 98137 | 60525L,60526L,60527L,60528L,60529L,60530L,60531L,60532L,60533L,60534L, |
| 98138 | 60535L,60536L,60537L,60538L,60539L,60540L,60541L,60542L,60543L,60544L, |
| 98139 | 60545L,60546L,60547L,60548L,60549L,60550L,60551L,60552L,60553L,60554L, |
| 98140 | 60555L,60556L,60557L,60558L,60559L,60560L,60561L,60562L,60563L,60564L, |
| 98141 | 60565L,60566L,60567L,60568L,60569L,60570L,60571L,60572L,60573L,60574L, |
| 98142 | 60575L,60576L,60577L,60578L,60579L,60580L,60581L,60582L,60583L,60584L, |
| 98143 | 60585L,60586L,60587L,60588L,60589L,60590L,60591L,60592L,60593L,60594L, |
| 98144 | 60595L,60596L,60597L,60598L,60599L,60600L,60601L,60602L,60603L,60604L, |
| 98145 | 60605L,60606L,60607L,60608L,60609L,60610L,60611L,60612L,60613L,60614L, |
| 98146 | 60615L,60616L,60617L,60618L,60619L,60620L,60621L,60622L,60623L,60624L, |
| 98147 | 60625L,60626L,60627L,60628L,60629L,60630L,60631L,60632L,60633L,60634L, |
| 98148 | 60635L,60636L,60637L,60638L,60639L,60640L,60641L,60642L,60643L,60644L, |
| 98149 | 60645L,60646L,60647L,60648L,60649L,60650L,60651L,60652L,60653L,60654L, |
| 98150 | 60655L,60656L,60657L,60658L,60659L,60660L,60661L,60662L,60663L,60664L, |
| 98151 | 60665L,60666L,60667L,60668L,60669L,60670L,60671L,60672L,60673L,60674L, |
| 98152 | 60675L,60676L,60677L,60678L,60679L,60680L,60681L,60682L,60683L,60684L, |
| 98153 | 60685L,60686L,60687L,60688L,60689L,60690L,60691L,60692L,60693L,60694L, |
| 98154 | 60695L,60696L,60697L,60698L,60699L,60700L,60701L,60702L,60703L,60704L, |
| 98155 | 60705L,60706L,60707L,60708L,60709L,60710L,60711L,60712L,60713L,60714L, |
| 98156 | 60715L,60716L,60717L,60718L,60719L,60720L,60721L,60722L,60723L,60724L, |
| 98157 | 60725L,60726L,60727L,60728L,60729L,60730L,60731L,60732L,60733L,60734L, |
| 98158 | 60735L,60736L,60737L,60738L,60739L,60740L,60741L,60742L,60743L,60744L, |
| 98159 | 60745L,60746L,60747L,60748L,60749L,60750L,60751L,60752L,60753L,60754L, |
| 98160 | 60755L,60756L,60757L,60758L,60759L,60760L,60761L,60762L,60763L,60764L, |
| 98161 | 60765L,60766L,60767L,60768L,60769L,60770L,60771L,60772L,60773L,60774L, |
| 98162 | 60775L,60776L,60777L,60778L,60779L,60780L,60781L,60782L,60783L,60784L, |
| 98163 | 60785L,60786L,60787L,60788L,60789L,60790L,60791L,60792L,60793L,60794L, |
| 98164 | 60795L,60796L,60797L,60798L,60799L,60800L,60801L,60802L,60803L,60804L, |
| 98165 | 60805L,60806L,60807L,60808L,60809L,60810L,60811L,60812L,60813L,60814L, |
| 98166 | 60815L,60816L,60817L,60818L,60819L,60820L,60821L,60822L,60823L,60824L, |
| 98167 | 60825L,60826L,60827L,60828L,60829L,60830L,60831L,60832L,60833L,60834L, |
| 98168 | 60835L,60836L,60837L,60838L,60839L,60840L,60841L,60842L,60843L,60844L, |
| 98169 | 60845L,60846L,60847L,60848L,60849L,60850L,60851L,60852L,60853L,60854L, |
| 98170 | 60855L,60856L,60857L,60858L,60859L,60860L,60861L,60862L,60863L,60864L, |
| 98171 | 60865L,60866L,60867L,60868L,60869L,60870L,60871L,60872L,60873L,60874L, |
| 98172 | 60875L,60876L,60877L,60878L,60879L,60880L,60881L,60882L,60883L,60884L, |
| 98173 | 60885L,60886L,60887L,60888L,60889L,60890L,60891L,60892L,60893L,60894L, |
| 98174 | 60895L,60896L,60897L,60898L,60899L,60900L,60901L,60902L,60903L,60904L, |
| 98175 | 60905L,60906L,60907L,60908L,60909L,60910L,60911L,60912L,60913L,60914L, |
| 98176 | 60915L,60916L,60917L,60918L,60919L,60920L,60921L,60922L,60923L,60924L, |
| 98177 | 60925L,60926L,60927L,60928L,60929L,60930L,60931L,60932L,60933L,60934L, |
| 98178 | 60935L,60936L,60937L,60938L,60939L,60940L,60941L,60942L,60943L,60944L, |
| 98179 | 60945L,60946L,60947L,60948L,60949L,60950L,60951L,60952L,60953L,60954L, |
| 98180 | 60955L,60956L,60957L,60958L,60959L,60960L,60961L,60962L,60963L,60964L, |
| 98181 | 60965L,60966L,60967L,60968L,60969L,60970L,60971L,60972L,60973L,60974L, |
| 98182 | 60975L,60976L,60977L,60978L,60979L,60980L,60981L,60982L,60983L,60984L, |
| 98183 | 60985L,60986L,60987L,60988L,60989L,60990L,60991L,60992L,60993L,60994L, |
| 98184 | 60995L,60996L,60997L,60998L,60999L,61000L,61001L,61002L,61003L,61004L, |
| 98185 | 61005L,61006L,61007L,61008L,61009L,61010L,61011L,61012L,61013L,61014L, |
| 98186 | 61015L,61016L,61017L,61018L,61019L,61020L,61021L,61022L,61023L,61024L, |
| 98187 | 61025L,61026L,61027L,61028L,61029L,61030L,61031L,61032L,61033L,61034L, |
| 98188 | 61035L,61036L,61037L,61038L,61039L,61040L,61041L,61042L,61043L,61044L, |
| 98189 | 61045L,61046L,61047L,61048L,61049L,61050L,61051L,61052L,61053L,61054L, |
| 98190 | 61055L,61056L,61057L,61058L,61059L,61060L,61061L,61062L,61063L,61064L, |
| 98191 | 61065L,61066L,61067L,61068L,61069L,61070L,61071L,61072L,61073L,61074L, |
| 98192 | 61075L,61076L,61077L,61078L,61079L,61080L,61081L,61082L,61083L,61084L, |
| 98193 | 61085L,61086L,61087L,61088L,61089L,61090L,61091L,61092L,61093L,61094L, |
| 98194 | 61095L,61096L,61097L,61098L,61099L,61100L,61101L,61102L,61103L,61104L, |
| 98195 | 61105L,61106L,61107L,61108L,61109L,61110L,61111L,61112L,61113L,61114L, |
| 98196 | 61115L,61116L,61117L,61118L,61119L,61120L,61121L,61122L,61123L,61124L, |
| 98197 | 61125L,61126L,61127L,61128L,61129L,61130L,61131L,61132L,61133L,61134L, |
| 98198 | 61135L,61136L,61137L,61138L,61139L,61140L,61141L,61142L,61143L,61144L, |
| 98199 | 61145L,61146L,61147L,61148L,61149L,61150L,61151L,61152L,61153L,61154L, |
| 98200 | 61155L,61156L,61157L,61158L,61159L,61160L,61161L,61162L,61163L,61164L, |
| 98201 | 61165L,61166L,61167L,61168L,61169L,61170L,61171L,61172L,61173L,61174L, |
| 98202 | 61175L,61176L,61177L,61178L,61179L,61180L,61181L,61182L,61183L,61184L, |
| 98203 | 61185L,61186L,61187L,61188L,61189L,61190L,61191L,61192L,61193L,61194L, |
| 98204 | 61195L,61196L,61197L,61198L,61199L,61200L,61201L,61202L,61203L,61204L, |
| 98205 | 61205L,61206L,61207L,61208L,61209L,61210L,61211L,61212L,61213L,61214L, |
| 98206 | 61215L,61216L,61217L,61218L,61219L,61220L,61221L,61222L,61223L,61224L, |
| 98207 | 61225L,61226L,61227L,61228L,61229L,61230L,61231L,61232L,61233L,61234L, |
| 98208 | 61235L,61236L,61237L,61238L,61239L,61240L,61241L,61242L,61243L,61244L, |
| 98209 | 61245L,61246L,61247L,61248L,61249L,61250L,61251L,61252L,61253L,61254L, |
| 98210 | 61255L,61256L,61257L,61258L,61259L,61260L,61261L,61262L,61263L,61264L, |
| 98211 | 61265L,61266L,61267L,61268L,61269L,61270L,61271L,61272L,61273L,61274L, |
| 98212 | 61275L,61276L,61277L,61278L,61279L,61280L,61281L,61282L,61283L,61284L, |
| 98213 | 61285L,61286L,61287L,61288L,61289L,61290L,61291L,61292L,61293L,61294L, |
| 98214 | 61295L,61296L,61297L,61298L,61299L,61300L,61301L,61302L,61303L,61304L, |
| 98215 | 61305L,61306L,61307L,61308L,61309L,61310L,61311L,61312L,61313L,61314L, |
| 98216 | 61315L,61316L,61317L,61318L,61319L,61320L,61321L,61322L,61323L,61324L, |
| 98217 | 61325L,61326L,61327L,61328L,61329L,61330L,61331L,61332L,61333L,61334L, |
| 98218 | 61335L,61336L,61337L,61338L,61339L,61340L,61341L,61342L,61343L,61344L, |
| 98219 | 61345L,61346L,61347L,61348L,61349L,61350L,61351L,61352L,61353L,61354L, |
| 98220 | 61355L,61356L,61357L,61358L,61359L,61360L,61361L,61362L,61363L,61364L, |
| 98221 | 61365L,61366L,61367L,61368L,61369L,61370L,61371L,61372L,61373L,61374L, |
| 98222 | 61375L,61376L,61377L,61378L,61379L,61380L,61381L,61382L,61383L,61384L, |
| 98223 | 61385L,61386L,61387L,61388L,61389L,61390L,61391L,61392L,61393L,61394L, |
| 98224 | 61395L,61396L,61397L,61398L,61399L,61400L,61401L,61402L,61403L,61404L, |
| 98225 | 61405L,61406L,61407L,61408L,61409L,61410L,61411L,61412L,61413L,61414L, |
| 98226 | 61415L,61416L,61417L,61418L,61419L,61420L,61421L,61422L,61423L,61424L, |
| 98227 | 61425L,61426L,61427L,61428L,61429L,61430L,61431L,61432L,61433L,61434L, |
| 98228 | 61435L,61436L,61437L,61438L,61439L,61440L,61441L,61442L,61443L,61444L, |
| 98229 | 61445L,61446L,61447L,61448L,61449L,61450L,61451L,61452L,61453L,61454L, |
| 98230 | 61455L,61456L,61457L,61458L,61459L,61460L,61461L,61462L,61463L,61464L, |
| 98231 | 61465L,61466L,61467L,61468L,61469L,61470L,61471L,61472L,61473L,61474L, |
| 98232 | 61475L,61476L,61477L,61478L,61479L,61480L,61481L,61482L,61483L,61484L, |
| 98233 | 61485L,61486L,61487L,61488L,61489L,61490L,61491L,61492L,61493L,61494L, |
| 98234 | 61495L,61496L,61497L,61498L,61499L,61500L,61501L,61502L,61503L,61504L, |
| 98235 | 61505L,61506L,61507L,61508L,61509L,61510L,61511L,61512L,61513L,61514L, |
| 98236 | 61515L,61516L,61517L,61518L,61519L,61520L,61521L,61522L,61523L,61524L, |
| 98237 | 61525L,61526L,61527L,61528L,61529L,61530L,61531L,61532L,61533L,61534L, |
| 98238 | 61535L,61536L,61537L,61538L,61539L,61540L,61541L,61542L,61543L,61544L, |
| 98239 | 61545L,61546L,61547L,61548L,61549L,61550L,61551L,61552L,61553L,61554L, |
| 98240 | 61555L,61556L,61557L,61558L,61559L,61560L,61561L,61562L,61563L,61564L, |
| 98241 | 61565L,61566L,61567L,61568L,61569L,61570L,61571L,61572L,61573L,61574L, |
| 98242 | 61575L,61576L,61577L,61578L,61579L,61580L,61581L,61582L,61583L,61584L, |
| 98243 | 61585L,61586L,61587L,61588L,61589L,61590L,61591L,61592L,61593L,61594L, |
| 98244 | 61595L,61596L,61597L,61598L,61599L,61600L,61601L,61602L,61603L,61604L, |
| 98245 | 61605L,61606L,61607L,61608L,61609L,61610L,61611L,61612L,61613L,61614L, |
| 98246 | 61615L,61616L,61617L,61618L,61619L,61620L,61621L,61622L,61623L,61624L, |
| 98247 | 61625L,61626L,61627L,61628L,61629L,61630L,61631L,61632L,61633L,61634L, |
| 98248 | 61635L,61636L,61637L,61638L,61639L,61640L,61641L,61642L,61643L,61644L, |
| 98249 | 61645L,61646L,61647L,61648L,61649L,61650L,61651L,61652L,61653L,61654L, |
| 98250 | 61655L,61656L,61657L,61658L,61659L,61660L,61661L,61662L,61663L,61664L, |
| 98251 | 61665L,61666L,61667L,61668L,61669L,61670L,61671L,61672L,61673L,61674L, |
| 98252 | 61675L,61676L,61677L,61678L,61679L,61680L,61681L,61682L,61683L,61684L, |
| 98253 | 61685L,61686L,61687L,61688L,61689L,61690L,61691L,61692L,61693L,61694L, |
| 98254 | 61695L,61696L,61697L,61698L,61699L,61700L,61701L,61702L,61703L,61704L, |
| 98255 | 61705L,61706L,61707L,61708L,61709L,61710L,61711L,61712L,61713L,61714L, |
| 98256 | 61715L,61716L,61717L,61718L,61719L,61720L,61721L,61722L,61723L,61724L, |
| 98257 | 61725L,61726L,61727L,61728L,61729L,61730L,61731L,61732L,61733L,61734L, |
| 98258 | 61735L,61736L,61737L,61738L,61739L,61740L,61741L,61742L,61743L,61744L, |
| 98259 | 61745L,61746L,61747L,61748L,61749L,61750L,61751L,61752L,61753L,61754L, |
| 98260 | 61755L,61756L,61757L,61758L,61759L,61760L,61761L,61762L,61763L,61764L, |
| 98261 | 61765L,61766L,61767L,61768L,61769L,61770L,61771L,61772L,61773L,61774L, |
| 98262 | 61775L,61776L,61777L,61778L,61779L,61780L,61781L,61782L,61783L,61784L, |
| 98263 | 61785L,61786L,61787L,61788L,61789L,61790L,61791L,61792L,61793L,61794L, |
| 98264 | 61795L,61796L,61797L,61798L,61799L,61800L,61801L,61802L,61803L,61804L, |
| 98265 | 61805L,61806L,61807L,61808L,61809L,61810L,61811L,61812L,61813L,61814L, |
| 98266 | 61815L,61816L,61817L,61818L,61819L,61820L,61821L,61822L,61823L,61824L, |
| 98267 | 61825L,61826L,61827L,61828L,61829L,61830L,61831L,61832L,61833L,61834L, |
| 98268 | 61835L,61836L,61837L,61838L,61839L,61840L,61841L,61842L,61843L,61844L, |
| 98269 | 61845L,61846L,61847L,61848L,61849L,61850L,61851L,61852L,61853L,61854L, |
| 98270 | 61855L,61856L,61857L,61858L,61859L,61860L,61861L,61862L,61863L,61864L, |
| 98271 | 61865L,61866L,61867L,61868L,61869L,61870L,61871L,61872L,61873L,61874L, |
| 98272 | 61875L,61876L,61877L,61878L,61879L,61880L,61881L,61882L,61883L,61884L, |
| 98273 | 61885L,61886L,61887L,61888L,61889L,61890L,61891L,61892L,61893L,61894L, |
| 98274 | 61895L,61896L,61897L,61898L,61899L,61900L,61901L,61902L,61903L,61904L, |
| 98275 | 61905L,61906L,61907L,61908L,61909L,61910L,61911L,61912L,61913L,61914L, |
| 98276 | 61915L,61916L,61917L,61918L,61919L,61920L,61921L,61922L,61923L,61924L, |
| 98277 | 61925L,61926L,61927L,61928L,61929L,61930L,61931L,61932L,61933L,61934L, |
| 98278 | 61935L,61936L,61937L,61938L,61939L,61940L,61941L,61942L,61943L,61944L, |
| 98279 | 61945L,61946L,61947L,61948L,61949L,61950L,61951L,61952L,61953L,61954L, |
| 98280 | 61955L,61956L,61957L,61958L,61959L,61960L,61961L,61962L,61963L,61964L, |
| 98281 | 61965L,61966L,61967L,61968L,61969L,61970L,61971L,61972L,61973L,61974L, |
| 98282 | 61975L,61976L,61977L,61978L,61979L,61980L,61981L,61982L,61983L,61984L, |
| 98283 | 61985L,61986L,61987L,61988L,61989L,61990L,61991L,61992L,61993L,61994L, |
| 98284 | 61995L,61996L,61997L,61998L,61999L,62000L,62001L,62002L,62003L,62004L, |
| 98285 | 62005L,62006L,62007L,62008L,62009L,62010L,62011L,62012L,62013L,62014L, |
| 98286 | 62015L,62016L,62017L,62018L,62019L,62020L,62021L,62022L,62023L,62024L, |
| 98287 | 62025L,62026L,62027L,62028L,62029L,62030L,62031L,62032L,62033L,62034L, |
| 98288 | 62035L,62036L,62037L,62038L,62039L,62040L,62041L,62042L,62043L,62044L, |
| 98289 | 62045L,62046L,62047L,62048L,62049L,62050L,62051L,62052L,62053L,62054L, |
| 98290 | 62055L,62056L,62057L,62058L,62059L,62060L,62061L,62062L,62063L,62064L, |
| 98291 | 62065L,62066L,62067L,62068L,62069L,62070L,62071L,62072L,62073L,62074L, |
| 98292 | 62075L,62076L,62077L,62078L,62079L,62080L,62081L,62082L,62083L,62084L, |
| 98293 | 62085L,62086L,62087L,62088L,62089L,62090L,62091L,62092L,62093L,62094L, |
| 98294 | 62095L,62096L,62097L,62098L,62099L,62100L,62101L,62102L,62103L,62104L, |
| 98295 | 62105L,62106L,62107L,62108L,62109L,62110L,62111L,62112L,62113L,62114L, |
| 98296 | 62115L,62116L,62117L,62118L,62119L,62120L,62121L,62122L,62123L,62124L, |
| 98297 | 62125L,62126L,62127L,62128L,62129L,62130L,62131L,62132L,62133L,62134L, |
| 98298 | 62135L,62136L,62137L,62138L,62139L,62140L,62141L,62142L,62143L,62144L, |
| 98299 | 62145L,62146L,62147L,62148L,62149L,62150L,62151L,62152L,62153L,62154L, |
| 98300 | 62155L,62156L,62157L,62158L,62159L,62160L,62161L,62162L,62163L,62164L, |
| 98301 | 62165L,62166L,62167L,62168L,62169L,62170L,62171L,62172L,62173L,62174L, |
| 98302 | 62175L,62176L,62177L,62178L,62179L,62180L,62181L,62182L,62183L,62184L, |
| 98303 | 62185L,62186L,62187L,62188L,62189L,62190L,62191L,62192L,62193L,62194L, |
| 98304 | 62195L,62196L,62197L,62198L,62199L,62200L,62201L,62202L,62203L,62204L, |
| 98305 | 62205L,62206L,62207L,62208L,62209L,62210L,62211L,62212L,62213L,62214L, |
| 98306 | 62215L,62216L,62217L,62218L,62219L,62220L,62221L,62222L,62223L,62224L, |
| 98307 | 62225L,62226L,62227L,62228L,62229L,62230L,62231L,62232L,62233L,62234L, |
| 98308 | 62235L,62236L,62237L,62238L,62239L,62240L,62241L,62242L,62243L,62244L, |
| 98309 | 62245L,62246L,62247L,62248L,62249L,62250L,62251L,62252L,62253L,62254L, |
| 98310 | 62255L,62256L,62257L,62258L,62259L,62260L,62261L,62262L,62263L,62264L, |
| 98311 | 62265L,62266L,62267L,62268L,62269L,62270L,62271L,62272L,62273L,62274L, |
| 98312 | 62275L,62276L,62277L,62278L,62279L,62280L,62281L,62282L,62283L,62284L, |
| 98313 | 62285L,62286L,62287L,62288L,62289L,62290L,62291L,62292L,62293L,62294L, |
| 98314 | 62295L,62296L,62297L,62298L,62299L,62300L,62301L,62302L,62303L,62304L, |
| 98315 | 62305L,62306L,62307L,62308L,62309L,62310L,62311L,62312L,62313L,62314L, |
| 98316 | 62315L,62316L,62317L,62318L,62319L,62320L,62321L,62322L,62323L,62324L, |
| 98317 | 62325L,62326L,62327L,62328L,62329L,62330L,62331L,62332L,62333L,62334L, |
| 98318 | 62335L,62336L,62337L,62338L,62339L,62340L,62341L,62342L,62343L,62344L, |
| 98319 | 62345L,62346L,62347L,62348L,62349L,62350L,62351L,62352L,62353L,62354L, |
| 98320 | 62355L,62356L,62357L,62358L,62359L,62360L,62361L,62362L,62363L,62364L, |
| 98321 | 62365L,62366L,62367L,62368L,62369L,62370L,62371L,62372L,62373L,62374L, |
| 98322 | 62375L,62376L,62377L,62378L,62379L,62380L,62381L,62382L,62383L,62384L, |
| 98323 | 62385L,62386L,62387L,62388L,62389L,62390L,62391L,62392L,62393L,62394L, |
| 98324 | 62395L,62396L,62397L,62398L,62399L,62400L,62401L,62402L,62403L,62404L, |
| 98325 | 62405L,62406L,62407L,62408L,62409L,62410L,62411L,62412L,62413L,62414L, |
| 98326 | 62415L,62416L,62417L,62418L,62419L,62420L,62421L,62422L,62423L,62424L, |
| 98327 | 62425L,62426L,62427L,62428L,62429L,62430L,62431L,62432L,62433L,62434L, |
| 98328 | 62435L,62436L,62437L,62438L,62439L,62440L,62441L,62442L,62443L,62444L, |
| 98329 | 62445L,62446L,62447L,62448L,62449L,62450L,62451L,62452L,62453L,62454L, |
| 98330 | 62455L,62456L,62457L,62458L,62459L,62460L,62461L,62462L,62463L,62464L, |
| 98331 | 62465L,62466L,62467L,62468L,62469L,62470L,62471L,62472L,62473L,62474L, |
| 98332 | 62475L,62476L,62477L,62478L,62479L,62480L,62481L,62482L,62483L,62484L, |
| 98333 | 62485L,62486L,62487L,62488L,62489L,62490L,62491L,62492L,62493L,62494L, |
| 98334 | 62495L,62496L,62497L,62498L,62499L,62500L,62501L,62502L,62503L,62504L, |
| 98335 | 62505L,62506L,62507L,62508L,62509L,62510L,62511L,62512L,62513L,62514L, |
| 98336 | 62515L,62516L,62517L,62518L,62519L,62520L,62521L,62522L,62523L,62524L, |
| 98337 | 62525L,62526L,62527L,62528L,62529L,62530L,62531L,62532L,62533L,62534L, |
| 98338 | 62535L,62536L,62537L,62538L,62539L,62540L,62541L,62542L,62543L,62544L, |
| 98339 | 62545L,62546L,62547L,62548L,62549L,62550L,62551L,62552L,62553L,62554L, |
| 98340 | 62555L,62556L,62557L,62558L,62559L,62560L,62561L,62562L,62563L,62564L, |
| 98341 | 62565L,62566L,62567L,62568L,62569L,62570L,62571L,62572L,62573L,62574L, |
| 98342 | 62575L,62576L,62577L,62578L,62579L,62580L,62581L,62582L,62583L,62584L, |
| 98343 | 62585L,62586L,62587L,62588L,62589L,62590L,62591L,62592L,62593L,62594L, |
| 98344 | 62595L,62596L,62597L,62598L,62599L,62600L,62601L,62602L,62603L,62604L, |
| 98345 | 62605L,62606L,62607L,62608L,62609L,62610L,62611L,62612L,62613L,62614L, |
| 98346 | 62615L,62616L,62617L,62618L,62619L,62620L,62621L,62622L,62623L,62624L, |
| 98347 | 62625L,62626L,62627L,62628L,62629L,62630L,62631L,62632L,62633L,62634L, |
| 98348 | 62635L,62636L,62637L,62638L,62639L,62640L,62641L,62642L,62643L,62644L, |
| 98349 | 62645L,62646L,62647L,62648L,62649L,62650L,62651L,62652L,62653L,62654L, |
| 98350 | 62655L,62656L,62657L,62658L,62659L,62660L,62661L,62662L,62663L,62664L, |
| 98351 | 62665L,62666L,62667L,62668L,62669L,62670L,62671L,62672L,62673L,62674L, |
| 98352 | 62675L,62676L,62677L,62678L,62679L,62680L,62681L,62682L,62683L,62684L, |
| 98353 | 62685L,62686L,62687L,62688L,62689L,62690L,62691L,62692L,62693L,62694L, |
| 98354 | 62695L,62696L,62697L,62698L,62699L,62700L,62701L,62702L,62703L,62704L, |
| 98355 | 62705L,62706L,62707L,62708L,62709L,62710L,62711L,62712L,62713L,62714L, |
| 98356 | 62715L,62716L,62717L,62718L,62719L,62720L,62721L,62722L,62723L,62724L, |
| 98357 | 62725L,62726L,62727L,62728L,62729L,62730L,62731L,62732L,62733L,62734L, |
| 98358 | 62735L,62736L,62737L,62738L,62739L,62740L,62741L,62742L,62743L,62744L, |
| 98359 | 62745L,62746L,62747L,62748L,62749L,62750L,62751L,62752L,62753L,62754L, |
| 98360 | 62755L,62756L,62757L,62758L,62759L,62760L,62761L,62762L,62763L,62764L, |
| 98361 | 62765L,62766L,62767L,62768L,62769L,62770L,62771L,62772L,62773L,62774L, |
| 98362 | 62775L,62776L,62777L,62778L,62779L,62780L,62781L,62782L,62783L,62784L, |
| 98363 | 62785L,62786L,62787L,62788L,62789L,62790L,62791L,62792L,62793L,62794L, |
| 98364 | 62795L,62796L,62797L,62798L,62799L,62800L,62801L,62802L,62803L,62804L, |
| 98365 | 62805L,62806L,62807L,62808L,62809L,62810L,62811L,62812L,62813L,62814L, |
| 98366 | 62815L,62816L,62817L,62818L,62819L,62820L,62821L,62822L,62823L,62824L, |
| 98367 | 62825L,62826L,62827L,62828L,62829L,62830L,62831L,62832L,62833L,62834L, |
| 98368 | 62835L,62836L,62837L,62838L,62839L,62840L,62841L,62842L,62843L,62844L, |
| 98369 | 62845L,62846L,62847L,62848L,62849L,62850L,62851L,62852L,62853L,62854L, |
| 98370 | 62855L,62856L,62857L,62858L,62859L,62860L,62861L,62862L,62863L,62864L, |
| 98371 | 62865L,62866L,62867L,62868L,62869L,62870L,62871L,62872L,62873L,62874L, |
| 98372 | 62875L,62876L,62877L,62878L,62879L,62880L,62881L,62882L,62883L,62884L, |
| 98373 | 62885L,62886L,62887L,62888L,62889L,62890L,62891L,62892L,62893L,62894L, |
| 98374 | 62895L,62896L,62897L,62898L,62899L,62900L,62901L,62902L,62903L,62904L, |
| 98375 | 62905L,62906L,62907L,62908L,62909L,62910L,62911L,62912L,62913L,62914L, |
| 98376 | 62915L,62916L,62917L,62918L,62919L,62920L,62921L,62922L,62923L,62924L, |
| 98377 | 62925L,62926L,62927L,62928L,62929L,62930L,62931L,62932L,62933L,62934L, |
| 98378 | 62935L,62936L,62937L,62938L,62939L,62940L,62941L,62942L,62943L,62944L, |
| 98379 | 62945L,62946L,62947L,62948L,62949L,62950L,62951L,62952L,62953L,62954L, |
| 98380 | 62955L,62956L,62957L,62958L,62959L,62960L,62961L,62962L,62963L,62964L, |
| 98381 | 62965L,62966L,62967L,62968L,62969L,62970L,62971L,62972L,62973L,62974L, |
| 98382 | 62975L,62976L,62977L,62978L,62979L,62980L,62981L,62982L,62983L,62984L, |
| 98383 | 62985L,62986L,62987L,62988L,62989L,62990L,62991L,62992L,62993L,62994L, |
| 98384 | 62995L,62996L,62997L,62998L,62999L,63000L,63001L,63002L,63003L,63004L, |
| 98385 | 63005L,63006L,63007L,63008L,63009L,63010L,63011L,63012L,63013L,63014L, |
| 98386 | 63015L,63016L,63017L,63018L,63019L,63020L,63021L,63022L,63023L,63024L, |
| 98387 | 63025L,63026L,63027L,63028L,63029L,63030L,63031L,63032L,63033L,63034L, |
| 98388 | 63035L,63036L,63037L,63038L,63039L,63040L,63041L,63042L,63043L,63044L, |
| 98389 | 63045L,63046L,63047L,63048L,63049L,63050L,63051L,63052L,63053L,63054L, |
| 98390 | 63055L,63056L,63057L,63058L,63059L,63060L,63061L,63062L,63063L,63064L, |
| 98391 | 63065L,63066L,63067L,63068L,63069L,63070L,63071L,63072L,63073L,63074L, |
| 98392 | 63075L,63076L,63077L,63078L,63079L,63080L,63081L,63082L,63083L,63084L, |
| 98393 | 63085L,63086L,63087L,63088L,63089L,63090L,63091L,63092L,63093L,63094L, |
| 98394 | 63095L,63096L,63097L,63098L,63099L,63100L,63101L,63102L,63103L,63104L, |
| 98395 | 63105L,63106L,63107L,63108L,63109L,63110L,63111L,63112L,63113L,63114L, |
| 98396 | 63115L,63116L,63117L,63118L,63119L,63120L,63121L,63122L,63123L,63124L, |
| 98397 | 63125L,63126L,63127L,63128L,63129L,63130L,63131L,63132L,63133L,63134L, |
| 98398 | 63135L,63136L,63137L,63138L,63139L,63140L,63141L,63142L,63143L,63144L, |
| 98399 | 63145L,63146L,63147L,63148L,63149L,63150L,63151L,63152L,63153L,63154L, |
| 98400 | 63155L,63156L,63157L,63158L,63159L,63160L,63161L,63162L,63163L,63164L, |
| 98401 | 63165L,63166L,63167L,63168L,63169L,63170L,63171L,63172L,63173L,63174L, |
| 98402 | 63175L,63176L,63177L,63178L,63179L,63180L,63181L,63182L,63183L,63184L, |
| 98403 | 63185L,63186L,63187L,63188L,63189L,63190L,63191L,63192L,63193L,63194L, |
| 98404 | 63195L,63196L,63197L,63198L,63199L,63200L,63201L,63202L,63203L,63204L, |
| 98405 | 63205L,63206L,63207L,63208L,63209L,63210L,63211L,63212L,63213L,63214L, |
| 98406 | 63215L,63216L,63217L,63218L,63219L,63220L,63221L,63222L,63223L,63224L, |
| 98407 | 63225L,63226L,63227L,63228L,63229L,63230L,63231L,63232L,63233L,63234L, |
| 98408 | 63235L,63236L,63237L,63238L,63239L,63240L,63241L,63242L,63243L,63244L, |
| 98409 | 63245L,63246L,63247L,63248L,63249L,63250L,63251L,63252L,63253L,63254L, |
| 98410 | 63255L,63256L,63257L,63258L,63259L,63260L,63261L,63262L,63263L,63264L, |
| 98411 | 63265L,63266L,63267L,63268L,63269L,63270L,63271L,63272L,63273L,63274L, |
| 98412 | 63275L,63276L,63277L,63278L,63279L,63280L,63281L,63282L,63283L,63284L, |
| 98413 | 63285L,63286L,63287L,63288L,63289L,63290L,63291L,63292L,63293L,63294L, |
| 98414 | 63295L,63296L,63297L,63298L,63299L,63300L,63301L,63302L,63303L,63304L, |
| 98415 | 63305L,63306L,63307L,63308L,63309L,63310L,63311L,63312L,63313L,63314L, |
| 98416 | 63315L,63316L,63317L,63318L,63319L,63320L,63321L,63322L,63323L,63324L, |
| 98417 | 63325L,63326L,63327L,63328L,63329L,63330L,63331L,63332L,63333L,63334L, |
| 98418 | 63335L,63336L,63337L,63338L,63339L,63340L,63341L,63342L,63343L,63344L, |
| 98419 | 63345L,63346L,63347L,63348L,63349L,63350L,63351L,63352L,63353L,63354L, |
| 98420 | 63355L,63356L,63357L,63358L,63359L,63360L,63361L,63362L,63363L,63364L, |
| 98421 | 63365L,63366L,63367L,63368L,63369L,63370L,63371L,63372L,63373L,63374L, |
| 98422 | 63375L,63376L,63377L,63378L,63379L,63380L,63381L,63382L,63383L,63384L, |
| 98423 | 63385L,63386L,63387L,63388L,63389L,63390L,63391L,63392L,63393L,63394L, |
| 98424 | 63395L,63396L,63397L,63398L,63399L,63400L,63401L,63402L,63403L,63404L, |
| 98425 | 63405L,63406L,63407L,63408L,63409L,63410L,63411L,63412L,63413L,63414L, |
| 98426 | 63415L,63416L,63417L,63418L,63419L,63420L,63421L,63422L,63423L,63424L, |
| 98427 | 63425L,63426L,63427L,63428L,63429L,63430L,63431L,63432L,63433L,63434L, |
| 98428 | 63435L,63436L,63437L,63438L,63439L,63440L,63441L,63442L,63443L,63444L, |
| 98429 | 63445L,63446L,63447L,63448L,63449L,63450L,63451L,63452L,63453L,63454L, |
| 98430 | 63455L,63456L,63457L,63458L,63459L,63460L,63461L,63462L,63463L,63464L, |
| 98431 | 63465L,63466L,63467L,63468L,63469L,63470L,63471L,63472L,63473L,63474L, |
| 98432 | 63475L,63476L,63477L,63478L,63479L,63480L,63481L,63482L,63483L,63484L, |
| 98433 | 63485L,63486L,63487L,63488L,63489L,63490L,63491L,63492L,63493L,63494L, |
| 98434 | 63495L,63496L,63497L,63498L,63499L,63500L,63501L,63502L,63503L,63504L, |
| 98435 | 63505L,63506L,63507L,63508L,63509L,63510L,63511L,63512L,63513L,63514L, |
| 98436 | 63515L,63516L,63517L,63518L,63519L,63520L,63521L,63522L,63523L,63524L, |
| 98437 | 63525L,63526L,63527L,63528L,63529L,63530L,63531L,63532L,63533L,63534L, |
| 98438 | 63535L,63536L,63537L,63538L,63539L,63540L,63541L,63542L,63543L,63544L, |
| 98439 | 63545L,63546L,63547L,63548L,63549L,63550L,63551L,63552L,63553L,63554L, |
| 98440 | 63555L,63556L,63557L,63558L,63559L,63560L,63561L,63562L,63563L,63564L, |
| 98441 | 63565L,63566L,63567L,63568L,63569L,63570L,63571L,63572L,63573L,63574L, |
| 98442 | 63575L,63576L,63577L,63578L,63579L,63580L,63581L,63582L,63583L,63584L, |
| 98443 | 63585L,63586L,63587L,63588L,63589L,63590L,63591L,63592L,63593L,63594L, |
| 98444 | 63595L,63596L,63597L,63598L,63599L,63600L,63601L,63602L,63603L,63604L, |
| 98445 | 63605L,63606L,63607L,63608L,63609L,63610L,63611L,63612L,63613L,63614L, |
| 98446 | 63615L,63616L,63617L,63618L,63619L,63620L,63621L,63622L,63623L,63624L, |
| 98447 | 63625L,63626L,63627L,63628L,63629L,63630L,63631L,63632L,63633L,63634L, |
| 98448 | 63635L,63636L,63637L,63638L,63639L,63640L,63641L,63642L,63643L,63644L, |
| 98449 | 63645L,63646L,63647L,63648L,63649L,63650L,63651L,63652L,63653L,63654L, |
| 98450 | 63655L,63656L,63657L,63658L,63659L,63660L,63661L,63662L,63663L,63664L, |
| 98451 | 63665L,63666L,63667L,63668L,63669L,63670L,63671L,63672L,63673L,63674L, |
| 98452 | 63675L,63676L,63677L,63678L,63679L,63680L,63681L,63682L,63683L,63684L, |
| 98453 | 63685L,63686L,63687L,63688L,63689L,63690L,63691L,63692L,63693L,63694L, |
| 98454 | 63695L,63696L,63697L,63698L,63699L,63700L,63701L,63702L,63703L,63704L, |
| 98455 | 63705L,63706L,63707L,63708L,63709L,63710L,63711L,63712L,63713L,63714L, |
| 98456 | 63715L,63716L,63717L,63718L,63719L,63720L,63721L,63722L,63723L,63724L, |
| 98457 | 63725L,63726L,63727L,63728L,63729L,63730L,63731L,63732L,63733L,63734L, |
| 98458 | 63735L,63736L,63737L,63738L,63739L,63740L,63741L,63742L,63743L,63744L, |
| 98459 | 63745L,63746L,63747L,63748L,63749L,63750L,63751L,63752L,63753L,63754L, |
| 98460 | 63755L,63756L,63757L,63758L,63759L,63760L,63761L,63762L,63763L,63764L, |
| 98461 | 63765L,63766L,63767L,63768L,63769L,63770L,63771L,63772L,63773L,63774L, |
| 98462 | 63775L,63776L,63777L,63778L,63779L,63780L,63781L,63782L,63783L,63784L, |
| 98463 | 63785L,63786L,63787L,63788L,63789L,63790L,63791L,63792L,63793L,63794L, |
| 98464 | 63795L,63796L,63797L,63798L,63799L,63800L,63801L,63802L,63803L,63804L, |
| 98465 | 63805L,63806L,63807L,63808L,63809L,63810L,63811L,63812L,63813L,63814L, |
| 98466 | 63815L,63816L,63817L,63818L,63819L,63820L,63821L,63822L,63823L,63824L, |
| 98467 | 63825L,63826L,63827L,63828L,63829L,63830L,63831L,63832L,63833L,63834L, |
| 98468 | 63835L,63836L,63837L,63838L,63839L,63840L,63841L,63842L,63843L,63844L, |
| 98469 | 63845L,63846L,63847L,63848L,63849L,63850L,63851L,63852L,63853L,63854L, |
| 98470 | 63855L,63856L,63857L,63858L,63859L,63860L,63861L,63862L,63863L,63864L, |
| 98471 | 63865L,63866L,63867L,63868L,63869L,63870L,63871L,63872L,63873L,63874L, |
| 98472 | 63875L,63876L,63877L,63878L,63879L,63880L,63881L,63882L,63883L,63884L, |
| 98473 | 63885L,63886L,63887L,63888L,63889L,63890L,63891L,63892L,63893L,63894L, |
| 98474 | 63895L,63896L,63897L,63898L,63899L,63900L,63901L,63902L,63903L,63904L, |
| 98475 | 63905L,63906L,63907L,63908L,63909L,63910L,63911L,63912L,63913L,63914L, |
| 98476 | 63915L,63916L,63917L,63918L,63919L,63920L,63921L,63922L,63923L,63924L, |
| 98477 | 63925L,63926L,63927L,63928L,63929L,63930L,63931L,63932L,63933L,63934L, |
| 98478 | 63935L,63936L,63937L,63938L,63939L,63940L,63941L,63942L,63943L,63944L, |
| 98479 | 63945L,63946L,63947L,63948L,63949L,63950L,63951L,63952L,63953L,63954L, |
| 98480 | 63955L,63956L,63957L,63958L,63959L,63960L,63961L,63962L,63963L,63964L, |
| 98481 | 63965L,63966L,63967L,63968L,63969L,63970L,63971L,63972L,63973L,63974L, |
| 98482 | 63975L,63976L,63977L,63978L,63979L,63980L,63981L,63982L,63983L,63984L, |
| 98483 | 63985L,63986L,63987L,63988L,63989L,63990L,63991L,63992L,63993L,63994L, |
| 98484 | 63995L,63996L,63997L,63998L,63999L,64000L,64001L,64002L,64003L,64004L, |
| 98485 | 64005L,64006L,64007L,64008L,64009L,64010L,64011L,64012L,64013L,64014L, |
| 98486 | 64015L,64016L,64017L,64018L,64019L,64020L,64021L,64022L,64023L,64024L, |
| 98487 | 64025L,64026L,64027L,64028L,64029L,64030L,64031L,64032L,64033L,64034L, |
| 98488 | 64035L,64036L,64037L,64038L,64039L,64040L,64041L,64042L,64043L,64044L, |
| 98489 | 64045L,64046L,64047L,64048L,64049L,64050L,64051L,64052L,64053L,64054L, |
| 98490 | 64055L,64056L,64057L,64058L,64059L,64060L,64061L,64062L,64063L,64064L, |
| 98491 | 64065L,64066L,64067L,64068L,64069L,64070L,64071L,64072L,64073L,64074L, |
| 98492 | 64075L,64076L,64077L,64078L,64079L,64080L,64081L,64082L,64083L,64084L, |
| 98493 | 64085L,64086L,64087L,64088L,64089L,64090L,64091L,64092L,64093L,64094L, |
| 98494 | 64095L,64096L,64097L,64098L,64099L,64100L,64101L,64102L,64103L,64104L, |
| 98495 | 64105L,64106L,64107L,64108L,64109L,64110L,64111L,64112L,64113L,64114L, |
| 98496 | 64115L,64116L,64117L,64118L,64119L,64120L,64121L,64122L,64123L,64124L, |
| 98497 | 64125L,64126L,64127L,64128L,64129L,64130L,64131L,64132L,64133L,64134L, |
| 98498 | 64135L,64136L,64137L,64138L,64139L,64140L,64141L,64142L,64143L,64144L, |
| 98499 | 64145L,64146L,64147L,64148L,64149L,64150L,64151L,64152L,64153L,64154L, |
| 98500 | 64155L,64156L,64157L,64158L,64159L,64160L,64161L,64162L,64163L,64164L, |
| 98501 | 64165L,64166L,64167L,64168L,64169L,64170L,64171L,64172L,64173L,64174L, |
| 98502 | 64175L,64176L,64177L,64178L,64179L,64180L,64181L,64182L,64183L,64184L, |
| 98503 | 64185L,64186L,64187L,64188L,64189L,64190L,64191L,64192L,64193L,64194L, |
| 98504 | 64195L,64196L,64197L,64198L,64199L,64200L,64201L,64202L,64203L,64204L, |
| 98505 | 64205L,64206L,64207L,64208L,64209L,64210L,64211L,64212L,64213L,64214L, |
| 98506 | 64215L,64216L,64217L,64218L,64219L,64220L,64221L,64222L,64223L,64224L, |
| 98507 | 64225L,64226L,64227L,64228L,64229L,64230L,64231L,64232L,64233L,64234L, |
| 98508 | 64235L,64236L,64237L,64238L,64239L,64240L,64241L,64242L,64243L,64244L, |
| 98509 | 64245L,64246L,64247L,64248L,64249L,64250L,64251L,64252L,64253L,64254L, |
| 98510 | 64255L,64256L,64257L,64258L,64259L,64260L,64261L,64262L,64263L,64264L, |
| 98511 | 64265L,64266L,64267L,64268L,64269L,64270L,64271L,64272L,64273L,64274L, |
| 98512 | 64275L,64276L,64277L,64278L,64279L,64280L,64281L,64282L,64283L,64284L, |
| 98513 | 64285L,64286L,64287L,64288L,64289L,64290L,64291L,64292L,64293L,64294L, |
| 98514 | 64295L,64296L,64297L,64298L,64299L,64300L,64301L,64302L,64303L,64304L, |
| 98515 | 64305L,64306L,64307L,64308L,64309L,64310L,64311L,64312L,64313L,64314L, |
| 98516 | 64315L,64316L,64317L,64318L,64319L,64320L,64321L,64322L,64323L,64324L, |
| 98517 | 64325L,64326L,64327L,64328L,64329L,64330L,64331L,64332L,64333L,64334L, |
| 98518 | 64335L,64336L,64337L,64338L,64339L,64340L,64341L,64342L,64343L,64344L, |
| 98519 | 64345L,64346L,64347L,64348L,64349L,64350L,64351L,64352L,64353L,64354L, |
| 98520 | 64355L,64356L,64357L,64358L,64359L,64360L,64361L,64362L,64363L,64364L, |
| 98521 | 64365L,64366L,64367L,64368L,64369L,64370L,64371L,64372L,64373L,64374L, |
| 98522 | 64375L,64376L,64377L,64378L,64379L,64380L,64381L,64382L,64383L,64384L, |
| 98523 | 64385L,64386L,64387L,64388L,64389L,64390L,64391L,64392L,64393L,64394L, |
| 98524 | 64395L,64396L,64397L,64398L,64399L,64400L,64401L,64402L,64403L,64404L, |
| 98525 | 64405L,64406L,64407L,64408L,64409L,64410L,64411L,64412L,64413L,64414L, |
| 98526 | 64415L,64416L,64417L,64418L,64419L,64420L,64421L,64422L,64423L,64424L, |
| 98527 | 64425L,64426L,64427L,64428L,64429L,64430L,64431L,64432L,64433L,64434L, |
| 98528 | 64435L,64436L,64437L,64438L,64439L,64440L,64441L,64442L,64443L,64444L, |
| 98529 | 64445L,64446L,64447L,64448L,64449L,64450L,64451L,64452L,64453L,64454L, |
| 98530 | 64455L,64456L,64457L,64458L,64459L,64460L,64461L,64462L,64463L,64464L, |
| 98531 | 64465L,64466L,64467L,64468L,64469L,64470L,64471L,64472L,64473L,64474L, |
| 98532 | 64475L,64476L,64477L,64478L,64479L,64480L,64481L,64482L,64483L,64484L, |
| 98533 | 64485L,64486L,64487L,64488L,64489L,64490L,64491L,64492L,64493L,64494L, |
| 98534 | 64495L,64496L,64497L,64498L,64499L,64500L,64501L,64502L,64503L,64504L, |
| 98535 | 64505L,64506L,64507L,64508L,64509L,64510L,64511L,64512L,64513L,64514L, |
| 98536 | 64515L,64516L,64517L,64518L,64519L,64520L,64521L,64522L,64523L,64524L, |
| 98537 | 64525L,64526L,64527L,64528L,64529L,64530L,64531L,64532L,64533L,64534L, |
| 98538 | 64535L,64536L,64537L,64538L,64539L,64540L,64541L,64542L,64543L,64544L, |
| 98539 | 64545L,64546L,64547L,64548L,64549L,64550L,64551L,64552L,64553L,64554L, |
| 98540 | 64555L,64556L,64557L,64558L,64559L,64560L,64561L,64562L,64563L,64564L, |
| 98541 | 64565L,64566L,64567L,64568L,64569L,64570L,64571L,64572L,64573L,64574L, |
| 98542 | 64575L,64576L,64577L,64578L,64579L,64580L,64581L,64582L,64583L,64584L, |
| 98543 | 64585L,64586L,64587L,64588L,64589L,64590L,64591L,64592L,64593L,64594L, |
| 98544 | 64595L,64596L,64597L,64598L,64599L,64600L,64601L,64602L,64603L,64604L, |
| 98545 | 64605L,64606L,64607L,64608L,64609L,64610L,64611L,64612L,64613L,64614L, |
| 98546 | 64615L,64616L,64617L,64618L,64619L,64620L,64621L,64622L,64623L,64624L, |
| 98547 | 64625L,64626L,64627L,64628L,64629L,64630L,64631L,64632L,64633L,64634L, |
| 98548 | 64635L,64636L,64637L,64638L,64639L,64640L,64641L,64642L,64643L,64644L, |
| 98549 | 64645L,64646L,64647L,64648L,64649L,64650L,64651L,64652L,64653L,64654L, |
| 98550 | 64655L,64656L,64657L,64658L,64659L,64660L,64661L,64662L,64663L,64664L, |
| 98551 | 64665L,64666L,64667L,64668L,64669L,64670L,64671L,64672L,64673L,64674L, |
| 98552 | 64675L,64676L,64677L,64678L,64679L,64680L,64681L,64682L,64683L,64684L, |
| 98553 | 64685L,64686L,64687L,64688L,64689L,64690L,64691L,64692L,64693L,64694L, |
| 98554 | 64695L,64696L,64697L,64698L,64699L,64700L,64701L,64702L,64703L,64704L, |
| 98555 | 64705L,64706L,64707L,64708L,64709L,64710L,64711L,64712L,64713L,64714L, |
| 98556 | 64715L,64716L,64717L,64718L,64719L,64720L,64721L,64722L,64723L,64724L, |
| 98557 | 64725L,64726L,64727L,64728L,64729L,64730L,64731L,64732L,64733L,64734L, |
| 98558 | 64735L,64736L,64737L,64738L,64739L,64740L,64741L,64742L,64743L,64744L, |
| 98559 | 64745L,64746L,64747L,64748L,64749L,64750L,64751L,64752L,64753L,64754L, |
| 98560 | 64755L,64756L,64757L,64758L,64759L,64760L,64761L,64762L,64763L,64764L, |
| 98561 | 64765L,64766L,64767L,64768L,64769L,64770L,64771L,64772L,64773L,64774L, |
| 98562 | 64775L,64776L,64777L,64778L,64779L,64780L,64781L,64782L,64783L,64784L, |
| 98563 | 64785L,64786L,64787L,64788L,64789L,64790L,64791L,64792L,64793L,64794L, |
| 98564 | 64795L,64796L,64797L,64798L,64799L,64800L,64801L,64802L,64803L,64804L, |
| 98565 | 64805L,64806L,64807L,64808L,64809L,64810L,64811L,64812L,64813L,64814L, |
| 98566 | 64815L,64816L,64817L,64818L,64819L,64820L,64821L,64822L,64823L,64824L, |
| 98567 | 64825L,64826L,64827L,64828L,64829L,64830L,64831L,64832L,64833L,64834L, |
| 98568 | 64835L,64836L,64837L,64838L,64839L,64840L,64841L,64842L,64843L,64844L, |
| 98569 | 64845L,64846L,64847L,64848L,64849L,64850L,64851L,64852L,64853L,64854L, |
| 98570 | 64855L,64856L,64857L,64858L,64859L,64860L,64861L,64862L,64863L,64864L, |
| 98571 | 64865L,64866L,64867L,64868L,64869L,64870L,64871L,64872L,64873L,64874L, |
| 98572 | 64875L,64876L,64877L,64878L,64879L,64880L,64881L,64882L,64883L,64884L, |
| 98573 | 64885L,64886L,64887L,64888L,64889L,64890L,64891L,64892L,64893L,64894L, |
| 98574 | 64895L,64896L,64897L,64898L,64899L,64900L,64901L,64902L,64903L,64904L, |
| 98575 | 64905L,64906L,64907L,64908L,64909L,64910L,64911L,64912L,64913L,64914L, |
| 98576 | 64915L,64916L,64917L,64918L,64919L,64920L,64921L,64922L,64923L,64924L, |
| 98577 | 64925L,64926L,64927L,64928L,64929L,64930L,64931L,64932L,64933L,64934L, |
| 98578 | 64935L,64936L,64937L,64938L,64939L,64940L,64941L,64942L,64943L,64944L, |
| 98579 | 64945L,64946L,64947L,64948L,64949L,64950L,64951L,64952L,64953L,64954L, |
| 98580 | 64955L,64956L,64957L,64958L,64959L,64960L,64961L,64962L,64963L,64964L, |
| 98581 | 64965L,64966L,64967L,64968L,64969L,64970L,64971L,64972L,64973L,64974L, |
| 98582 | 64975L,64976L,64977L,64978L,64979L,64980L,64981L,64982L,64983L,64984L, |
| 98583 | 64985L,64986L,64987L,64988L,64989L,64990L,64991L,64992L,64993L,64994L, |
| 98584 | 64995L,64996L,64997L,64998L,64999L,65000L,65001L,65002L,65003L,65004L, |
| 98585 | 65005L,65006L,65007L,65008L,65009L,65010L,65011L,65012L,65013L,65014L, |
| 98586 | 65015L,65016L,65017L,65018L,65019L,65020L,65021L,65022L,65023L,65024L, |
| 98587 | 65025L,65026L,65027L,65028L,65029L,65030L,65031L,65032L,65033L,65034L, |
| 98588 | 65035L,65036L,65037L,65038L,65039L,65040L,65041L,65042L,65043L,65044L, |
| 98589 | 65045L,65046L,65047L,65048L,65049L,65050L,65051L,65052L,65053L,65054L, |
| 98590 | 65055L,65056L,65057L,65058L,65059L,65060L,65061L,65062L,65063L,65064L, |
| 98591 | 65065L,65066L,65067L,65068L,65069L,65070L,65071L,65072L,65073L,65074L, |
| 98592 | 65075L,65076L,65077L,65078L,65079L,65080L,65081L,65082L,65083L,65084L, |
| 98593 | 65085L,65086L,65087L,65088L,65089L,65090L,65091L,65092L,65093L,65094L, |
| 98594 | 65095L,65096L,65097L,65098L,65099L,65100L,65101L,65102L,65103L,65104L, |
| 98595 | 65105L,65106L,65107L,65108L,65109L,65110L,65111L,65112L,65113L,65114L, |
| 98596 | 65115L,65116L,65117L,65118L,65119L,65120L,65121L,65122L,65123L,65124L, |
| 98597 | 65125L,65126L,65127L,65128L,65129L,65130L,65131L,65132L,65133L,65134L, |
| 98598 | 65135L,65136L,65137L,65138L,65139L,65140L,65141L,65142L,65143L,65144L, |
| 98599 | 65145L,65146L,65147L,65148L,65149L,65150L,65151L,65152L,65153L,65154L, |
| 98600 | 65155L,65156L,65157L,65158L,65159L,65160L,65161L,65162L,65163L,65164L, |
| 98601 | 65165L,65166L,65167L,65168L,65169L,65170L,65171L,65172L,65173L,65174L, |
| 98602 | 65175L,65176L,65177L,65178L,65179L,65180L,65181L,65182L,65183L,65184L, |
| 98603 | 65185L,65186L,65187L,65188L,65189L,65190L,65191L,65192L,65193L,65194L, |
| 98604 | 65195L,65196L,65197L,65198L,65199L,65200L,65201L,65202L,65203L,65204L, |
| 98605 | 65205L,65206L,65207L,65208L,65209L,65210L,65211L,65212L,65213L,65214L, |
| 98606 | 65215L,65216L,65217L,65218L,65219L,65220L,65221L,65222L,65223L,65224L, |
| 98607 | 65225L,65226L,65227L,65228L,65229L,65230L,65231L,65232L,65233L,65234L, |
| 98608 | 65235L,65236L,65237L,65238L,65239L,65240L,65241L,65242L,65243L,65244L, |
| 98609 | 65245L,65246L,65247L,65248L,65249L,65250L,65251L,65252L,65253L,65254L, |
| 98610 | 65255L,65256L,65257L,65258L,65259L,65260L,65261L,65262L,65263L,65264L, |
| 98611 | 65265L,65266L,65267L,65268L,65269L,65270L,65271L,65272L,65273L,65274L, |
| 98612 | 65275L,65276L,65277L,65278L,65279L,65280L,65281L,65282L,65283L,65284L, |
| 98613 | 65285L,65286L,65287L,65288L,65289L,65290L,65291L,65292L,65293L,65294L, |
| 98614 | 65295L,65296L,65297L,65298L,65299L,65300L,65301L,65302L,65303L,65304L, |
| 98615 | 65305L,65306L,65307L,65308L,65309L,65310L,65311L,65312L,65313L,65314L, |
| 98616 | 65315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L,65323L,65324L, |
| 98617 | 65325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L,65333L,65334L, |
| 98618 | 65335L,65336L,65337L,65338L,65339L,65340L,65341L,65342L,65343L,65344L, |
| 98619 | 65313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L, |
| 98620 | 65323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L, |
| 98621 | 65333L,65334L,65335L,65336L,65337L,65338L,65371L,65372L,65373L,65374L, |
| 98622 | 65375L,65376L,65377L,65378L,65379L,65380L,65381L,65382L,65383L,65384L, |
| 98623 | 65385L,65386L,65387L,65388L,65389L,65390L,65391L,65392L,65393L,65394L, |
| 98624 | 65395L,65396L,65397L,65398L,65399L,65400L,65401L,65402L,65403L,65404L, |
| 98625 | 65405L,65406L,65407L,65408L,65409L,65410L,65411L,65412L,65413L,65414L, |
| 98626 | 65415L,65416L,65417L,65418L,65419L,65420L,65421L,65422L,65423L,65424L, |
| 98627 | 65425L,65426L,65427L,65428L,65429L,65430L,65431L,65432L,65433L,65434L, |
| 98628 | 65435L,65436L,65437L,65438L,65439L,65440L,65441L,65442L,65443L,65444L, |
| 98629 | 65445L,65446L,65447L,65448L,65449L,65450L,65451L,65452L,65453L,65454L, |
| 98630 | 65455L,65456L,65457L,65458L,65459L,65460L,65461L,65462L,65463L,65464L, |
| 98631 | 65465L,65466L,65467L,65468L,65469L,65470L,65471L,65472L,65473L,65474L, |
| 98632 | 65475L,65476L,65477L,65478L,65479L,65480L,65481L,65482L,65483L,65484L, |
| 98633 | 65485L,65486L,65487L,65488L,65489L,65490L,65491L,65492L,65493L,65494L, |
| 98634 | 65495L,65496L,65497L,65498L,65499L,65500L,65501L,65502L,65503L,65504L, |
| 98635 | 65505L,65506L,65507L,65508L,65509L,65510L,65511L,65512L,65513L,65514L, |
| 98636 | 65515L,65516L,65517L,65518L,65519L,65520L,65521L,65522L,65523L,65524L, |
| 98637 | 65525L,65526L,65527L,65528L,65529L,65530L,65531L,65532L,65533L,65534L, |
| 98638 | 65535L, |
| 98639 | }; |
| 98640 | #endif |
| 98641 | |
| 98642 | #if defined(DUK_USE_REGEXP_CANON_BITMAP) |
| 98643 | /* |
| 98644 | * Automatically generated by extract_caseconv.py, do not edit! |
| 98645 | */ |
| 98646 | |
| 98647 | const duk_uint8_t duk_unicode_re_canon_bitmap[256] = { |
| 98648 | 23,0,224,19,1,228,255,255,255,255,255,255,255,255,255,255,63,254,255,127, |
| 98649 | 255,255,255,255,255,255,255,255,231,231,0,16,255,227,255,255,63,255,255, |
| 98650 | 255,255,255,255,255,1,252,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98651 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98652 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98653 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98654 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98655 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98656 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98657 | 227,129,255,255,255,147,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98658 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98659 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98660 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, |
| 98661 | 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,251, |
| 98662 | }; |
| 98663 | #endif |
| 98664 | #line 1 "duk_util_bitdecoder.c" |
| 98665 | /* |
| 98666 | * Bitstream decoder. |
| 98667 | */ |
| 98668 | |
| 98669 | /* #include duk_internal.h -> already included */ |
| 98670 | |
| 98671 | /* Decode 'bits' bits from the input stream (bits must be 1...24). |
| 98672 | * When reading past bitstream end, zeroes are shifted in. The result |
| 98673 | * is signed to match duk_bd_decode_flagged. |
| 98674 | */ |
| 98675 | DUK_INTERNAL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) { |
| 98676 | duk_small_int_t shift; |
| 98677 | duk_uint32_t mask; |
| 98678 | duk_uint32_t tmp; |
| 98679 | |
| 98680 | /* Note: cannot read more than 24 bits without possibly shifting top bits out. |
| 98681 | * Fixable, but adds complexity. |
| 98682 | */ |
| 98683 | DUK_ASSERT(bits >= 1 && bits <= 24); |
| 98684 | |
| 98685 | while (ctx->currbits < bits) { |
| 98686 | #if 0 |
| 98687 | DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)" , |
| 98688 | (long) bits, (long) ctx->currbits)); |
| 98689 | #endif |
| 98690 | ctx->currval <<= 8; |
| 98691 | if (ctx->offset < ctx->length) { |
| 98692 | /* If ctx->offset >= ctx->length, we "shift zeroes in" |
| 98693 | * instead of croaking. |
| 98694 | */ |
| 98695 | ctx->currval |= ctx->data[ctx->offset++]; |
| 98696 | } |
| 98697 | ctx->currbits += 8; |
| 98698 | } |
| 98699 | #if 0 |
| 98700 | DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx" , |
| 98701 | (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval)); |
| 98702 | #endif |
| 98703 | |
| 98704 | /* Extract 'top' bits of currval; note that the extracted bits do not need |
| 98705 | * to be cleared, we just ignore them on next round. |
| 98706 | */ |
| 98707 | shift = ctx->currbits - bits; |
| 98708 | mask = (((duk_uint32_t) 1U) << bits) - 1U; |
| 98709 | tmp = (ctx->currval >> shift) & mask; |
| 98710 | ctx->currbits = shift; /* remaining */ |
| 98711 | |
| 98712 | #if 0 |
| 98713 | DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx" , |
| 98714 | (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval)); |
| 98715 | #endif |
| 98716 | |
| 98717 | return tmp; |
| 98718 | } |
| 98719 | |
| 98720 | DUK_INTERNAL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) { |
| 98721 | return (duk_small_uint_t) duk_bd_decode(ctx, 1); |
| 98722 | } |
| 98723 | |
| 98724 | /* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return |
| 98725 | * default value. |
| 98726 | */ |
| 98727 | DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) { |
| 98728 | if (duk_bd_decode_flag(ctx)) { |
| 98729 | return duk_bd_decode(ctx, bits); |
| 98730 | } else { |
| 98731 | return def_value; |
| 98732 | } |
| 98733 | } |
| 98734 | |
| 98735 | /* Signed variant, allows negative marker value. */ |
| 98736 | DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) { |
| 98737 | return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value); |
| 98738 | } |
| 98739 | |
| 98740 | /* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */ |
| 98741 | DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) { |
| 98742 | duk_small_uint_t t; |
| 98743 | |
| 98744 | /* The bit encoding choices here are based on manual testing against |
| 98745 | * the actual varuints generated by genbuiltins.py. |
| 98746 | */ |
| 98747 | switch (duk_bd_decode(ctx, 2)) { |
| 98748 | case 0: |
| 98749 | return 0; /* [0,0] */ |
| 98750 | case 1: |
| 98751 | return duk_bd_decode(ctx, 2) + 1; /* [1,4] */ |
| 98752 | case 2: |
| 98753 | return duk_bd_decode(ctx, 5) + 5; /* [5,36] */ |
| 98754 | default: |
| 98755 | t = duk_bd_decode(ctx, 7); |
| 98756 | if (t == 0) { |
| 98757 | return duk_bd_decode(ctx, 20); |
| 98758 | } |
| 98759 | return (t - 1) + 37; /* [37,163] */ |
| 98760 | } |
| 98761 | } |
| 98762 | |
| 98763 | /* Decode a bit packed string from a custom format used by genbuiltins.py. |
| 98764 | * This function is here because it's used for both heap and thread inits. |
| 98765 | * Caller must supply the output buffer whose size is NOT checked! |
| 98766 | */ |
| 98767 | |
| 98768 | #define DUK__BITPACK_LETTER_LIMIT 26 |
| 98769 | #define DUK__BITPACK_LOOKUP1 26 |
| 98770 | #define DUK__BITPACK_LOOKUP2 27 |
| 98771 | #define DUK__BITPACK_SWITCH1 28 |
| 98772 | #define DUK__BITPACK_SWITCH 29 |
| 98773 | #define DUK__BITPACK_UNUSED1 30 |
| 98774 | #define DUK__BITPACK_EIGHTBIT 31 |
| 98775 | |
| 98776 | DUK_LOCAL const duk_uint8_t duk__bitpacked_lookup[16] = { |
| 98777 | DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3, |
| 98778 | DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7, |
| 98779 | DUK_ASC_8, DUK_ASC_9, DUK_ASC_UNDERSCORE, DUK_ASC_SPACE, |
| 98780 | 0x82, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY |
| 98781 | }; |
| 98782 | |
| 98783 | DUK_INTERNAL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out) { |
| 98784 | duk_small_uint_t len; |
| 98785 | duk_small_uint_t mode; |
| 98786 | duk_small_uint_t t; |
| 98787 | duk_small_uint_t i; |
| 98788 | |
| 98789 | len = duk_bd_decode(bd, 5); |
| 98790 | if (len == 31) { |
| 98791 | len = duk_bd_decode(bd, 8); /* Support up to 256 bytes; rare. */ |
| 98792 | } |
| 98793 | |
| 98794 | mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */ |
| 98795 | for (i = 0; i < len; i++) { |
| 98796 | t = duk_bd_decode(bd, 5); |
| 98797 | if (t < DUK__BITPACK_LETTER_LIMIT) { |
| 98798 | t = t + DUK_ASC_UC_A + mode; |
| 98799 | } else if (t == DUK__BITPACK_LOOKUP1) { |
| 98800 | t = duk__bitpacked_lookup[duk_bd_decode(bd, 3)]; |
| 98801 | } else if (t == DUK__BITPACK_LOOKUP2) { |
| 98802 | t = duk__bitpacked_lookup[8 + duk_bd_decode(bd, 3)]; |
| 98803 | } else if (t == DUK__BITPACK_SWITCH1) { |
| 98804 | t = duk_bd_decode(bd, 5); |
| 98805 | DUK_ASSERT_DISABLE(t >= 0); /* unsigned */ |
| 98806 | DUK_ASSERT(t <= 25); |
| 98807 | t = t + DUK_ASC_UC_A + (mode ^ 32); |
| 98808 | } else if (t == DUK__BITPACK_SWITCH) { |
| 98809 | mode = mode ^ 32; |
| 98810 | t = duk_bd_decode(bd, 5); |
| 98811 | DUK_ASSERT_DISABLE(t >= 0); |
| 98812 | DUK_ASSERT(t <= 25); |
| 98813 | t = t + DUK_ASC_UC_A + mode; |
| 98814 | } else if (t == DUK__BITPACK_EIGHTBIT) { |
| 98815 | t = duk_bd_decode(bd, 8); |
| 98816 | } |
| 98817 | out[i] = (duk_uint8_t) t; |
| 98818 | } |
| 98819 | |
| 98820 | return len; |
| 98821 | } |
| 98822 | |
| 98823 | /* automatic undefs */ |
| 98824 | #undef DUK__BITPACK_EIGHTBIT |
| 98825 | #undef DUK__BITPACK_LETTER_LIMIT |
| 98826 | #undef DUK__BITPACK_LOOKUP1 |
| 98827 | #undef DUK__BITPACK_LOOKUP2 |
| 98828 | #undef DUK__BITPACK_SWITCH |
| 98829 | #undef DUK__BITPACK_SWITCH1 |
| 98830 | #undef DUK__BITPACK_UNUSED1 |
| 98831 | #line 1 "duk_util_bitencoder.c" |
| 98832 | /* |
| 98833 | * Bitstream encoder. |
| 98834 | */ |
| 98835 | |
| 98836 | /* #include duk_internal.h -> already included */ |
| 98837 | |
| 98838 | DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) { |
| 98839 | duk_uint8_t tmp; |
| 98840 | |
| 98841 | DUK_ASSERT(ctx != NULL); |
| 98842 | DUK_ASSERT(ctx->currbits < 8); |
| 98843 | |
| 98844 | /* This limitation would be fixable but adds unnecessary complexity. */ |
| 98845 | DUK_ASSERT(bits >= 1 && bits <= 24); |
| 98846 | |
| 98847 | ctx->currval = (ctx->currval << bits) | data; |
| 98848 | ctx->currbits += bits; |
| 98849 | |
| 98850 | while (ctx->currbits >= 8) { |
| 98851 | if (ctx->offset < ctx->length) { |
| 98852 | tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff); |
| 98853 | ctx->data[ctx->offset++] = tmp; |
| 98854 | } else { |
| 98855 | /* If buffer has been exhausted, truncate bitstream */ |
| 98856 | ctx->truncated = 1; |
| 98857 | } |
| 98858 | |
| 98859 | ctx->currbits -= 8; |
| 98860 | } |
| 98861 | } |
| 98862 | |
| 98863 | DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) { |
| 98864 | duk_small_int_t npad; |
| 98865 | |
| 98866 | DUK_ASSERT(ctx != NULL); |
| 98867 | DUK_ASSERT(ctx->currbits < 8); |
| 98868 | |
| 98869 | npad = (duk_small_int_t) (8 - ctx->currbits); |
| 98870 | if (npad > 0) { |
| 98871 | duk_be_encode(ctx, 0, npad); |
| 98872 | } |
| 98873 | DUK_ASSERT(ctx->currbits == 0); |
| 98874 | } |
| 98875 | #line 1 "duk_util_bufwriter.c" |
| 98876 | /* |
| 98877 | * Fast buffer writer with slack management. |
| 98878 | */ |
| 98879 | |
| 98880 | /* #include duk_internal.h -> already included */ |
| 98881 | |
| 98882 | /* XXX: Avoid duk_{memcmp,memmove}_unsafe() by imposing a minimum length of |
| 98883 | * >0 for the underlying dynamic buffer. |
| 98884 | */ |
| 98885 | |
| 98886 | /* |
| 98887 | * Macro support functions (use only macros in calling code) |
| 98888 | */ |
| 98889 | |
| 98890 | DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) { |
| 98891 | duk_uint8_t *p; |
| 98892 | |
| 98893 | DUK_ASSERT(thr != NULL); |
| 98894 | DUK_ASSERT(bw_ctx != NULL); |
| 98895 | DUK_UNREF(thr); |
| 98896 | |
| 98897 | /* 'p' might be NULL when the underlying buffer is zero size. If so, |
| 98898 | * the resulting pointers are not used unsafely. |
| 98899 | */ |
| 98900 | p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf); |
| 98901 | DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0)); |
| 98902 | bw_ctx->p = p + curr_offset; |
| 98903 | bw_ctx->p_base = p; |
| 98904 | bw_ctx->p_limit = p + new_length; |
| 98905 | } |
| 98906 | |
| 98907 | DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) { |
| 98908 | DUK_ASSERT(thr != NULL); |
| 98909 | DUK_ASSERT(bw_ctx != NULL); |
| 98910 | DUK_ASSERT(h_buf != NULL); |
| 98911 | |
| 98912 | bw_ctx->buf = h_buf; |
| 98913 | duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf)); |
| 98914 | } |
| 98915 | |
| 98916 | DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) { |
| 98917 | DUK_ASSERT(thr != NULL); |
| 98918 | DUK_ASSERT(bw_ctx != NULL); |
| 98919 | |
| 98920 | (void) duk_push_dynamic_buffer(thr, buf_size); |
| 98921 | bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1); |
| 98922 | DUK_ASSERT(bw_ctx->buf != NULL); |
| 98923 | duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size); |
| 98924 | } |
| 98925 | |
| 98926 | /* Resize target buffer for requested size. Called by the macro only when the |
| 98927 | * fast path test (= there is space) fails. |
| 98928 | */ |
| 98929 | DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) { |
| 98930 | duk_size_t curr_off; |
| 98931 | duk_size_t add_sz; |
| 98932 | duk_size_t new_sz; |
| 98933 | |
| 98934 | DUK_ASSERT(thr != NULL); |
| 98935 | DUK_ASSERT(bw_ctx != NULL); |
| 98936 | |
| 98937 | /* We could do this operation without caller updating bw_ctx->ptr, |
| 98938 | * but by writing it back here we can share code better. |
| 98939 | */ |
| 98940 | |
| 98941 | curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); |
| 98942 | add_sz = (curr_off >> DUK_BW_SLACK_SHIFT) + DUK_BW_SLACK_ADD; |
| 98943 | new_sz = curr_off + sz + add_sz; |
| 98944 | if (DUK_UNLIKELY(new_sz < curr_off)) { |
| 98945 | /* overflow */ |
| 98946 | DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG); |
| 98947 | DUK_WO_NORETURN(return NULL;); |
| 98948 | } |
| 98949 | #if 0 /* for manual torture testing: tight allocation, useful with valgrind */ |
| 98950 | new_sz = curr_off + sz; |
| 98951 | #endif |
| 98952 | |
| 98953 | /* This is important to ensure dynamic buffer data pointer is not |
| 98954 | * NULL (which is possible if buffer size is zero), which in turn |
| 98955 | * causes portability issues with e.g. memmove() and memcpy(). |
| 98956 | */ |
| 98957 | DUK_ASSERT(new_sz >= 1); |
| 98958 | |
| 98959 | DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)" , (long) curr_off, (long) new_sz, (long) add_sz)); |
| 98960 | |
| 98961 | duk_hbuffer_resize(thr, bw_ctx->buf, new_sz); |
| 98962 | duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz); |
| 98963 | return bw_ctx->p; |
| 98964 | } |
| 98965 | |
| 98966 | /* Make buffer compact, matching current written size. */ |
| 98967 | DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) { |
| 98968 | duk_size_t len; |
| 98969 | |
| 98970 | DUK_ASSERT(thr != NULL); |
| 98971 | DUK_ASSERT(bw_ctx != NULL); |
| 98972 | DUK_UNREF(thr); |
| 98973 | |
| 98974 | len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base); |
| 98975 | duk_hbuffer_resize(thr, bw_ctx->buf, len); |
| 98976 | duk__bw_update_ptrs(thr, bw_ctx, len, len); |
| 98977 | } |
| 98978 | |
| 98979 | DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) { |
| 98980 | duk_uint8_t *p_base; |
| 98981 | |
| 98982 | DUK_ASSERT(thr != NULL); |
| 98983 | DUK_ASSERT(bw != NULL); |
| 98984 | DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 98985 | DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); |
| 98986 | DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); |
| 98987 | DUK_UNREF(thr); |
| 98988 | |
| 98989 | p_base = bw->p_base; |
| 98990 | duk_memcpy_unsafe((void *) bw->p, |
| 98991 | (const void *) (p_base + src_off), |
| 98992 | (size_t) len); |
| 98993 | bw->p += len; |
| 98994 | } |
| 98995 | |
| 98996 | DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) { |
| 98997 | DUK_ASSERT(thr != NULL); |
| 98998 | DUK_ASSERT(bw != NULL); |
| 98999 | DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99000 | DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99001 | DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99002 | |
| 99003 | DUK_BW_ENSURE(thr, bw, len); |
| 99004 | duk_bw_write_raw_slice(thr, bw, src_off, len); |
| 99005 | } |
| 99006 | |
| 99007 | DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) { |
| 99008 | duk_uint8_t *p_base; |
| 99009 | duk_size_t buf_sz, move_sz; |
| 99010 | |
| 99011 | DUK_ASSERT(thr != NULL); |
| 99012 | DUK_ASSERT(bw != NULL); |
| 99013 | DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99014 | DUK_ASSERT(buf != NULL); |
| 99015 | DUK_UNREF(thr); |
| 99016 | |
| 99017 | p_base = bw->p_base; |
| 99018 | buf_sz = (duk_size_t) (bw->p - p_base); /* constrained by maximum buffer size */ |
| 99019 | move_sz = buf_sz - dst_off; |
| 99020 | |
| 99021 | DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ |
| 99022 | duk_memmove_unsafe((void *) (p_base + dst_off + len), |
| 99023 | (const void *) (p_base + dst_off), |
| 99024 | (size_t) move_sz); |
| 99025 | duk_memcpy_unsafe((void *) (p_base + dst_off), |
| 99026 | (const void *) buf, |
| 99027 | (size_t) len); |
| 99028 | bw->p += len; |
| 99029 | } |
| 99030 | |
| 99031 | DUK_INTERNAL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) { |
| 99032 | DUK_ASSERT(thr != NULL); |
| 99033 | DUK_ASSERT(bw != NULL); |
| 99034 | DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99035 | DUK_ASSERT(buf != NULL); |
| 99036 | |
| 99037 | DUK_BW_ENSURE(thr, bw, len); |
| 99038 | duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len); |
| 99039 | } |
| 99040 | |
| 99041 | DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) { |
| 99042 | duk_uint8_t *p_base; |
| 99043 | duk_size_t buf_sz, move_sz; |
| 99044 | |
| 99045 | DUK_ASSERT(thr != NULL); |
| 99046 | DUK_ASSERT(bw != NULL); |
| 99047 | DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99048 | DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99049 | DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99050 | DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99051 | DUK_UNREF(thr); |
| 99052 | |
| 99053 | p_base = bw->p_base; |
| 99054 | |
| 99055 | /* Don't support "straddled" source now. */ |
| 99056 | DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len); |
| 99057 | |
| 99058 | if (dst_off <= src_off) { |
| 99059 | /* Target is before source. Source offset is expressed as |
| 99060 | * a "before change" offset. Account for the memmove. |
| 99061 | */ |
| 99062 | src_off += len; |
| 99063 | } |
| 99064 | |
| 99065 | buf_sz = (duk_size_t) (bw->p - p_base); |
| 99066 | move_sz = buf_sz - dst_off; |
| 99067 | |
| 99068 | DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */ |
| 99069 | duk_memmove_unsafe((void *) (p_base + dst_off + len), |
| 99070 | (const void *) (p_base + dst_off), |
| 99071 | (size_t) move_sz); |
| 99072 | duk_memcpy_unsafe((void *) (p_base + dst_off), |
| 99073 | (const void *) (p_base + src_off), |
| 99074 | (size_t) len); |
| 99075 | bw->p += len; |
| 99076 | } |
| 99077 | |
| 99078 | DUK_INTERNAL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) { |
| 99079 | DUK_ASSERT(thr != NULL); |
| 99080 | DUK_ASSERT(bw != NULL); |
| 99081 | DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99082 | DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99083 | DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99084 | DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99085 | |
| 99086 | /* Don't support "straddled" source now. */ |
| 99087 | DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len); |
| 99088 | |
| 99089 | DUK_BW_ENSURE(thr, bw, len); |
| 99090 | duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len); |
| 99091 | } |
| 99092 | |
| 99093 | DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) { |
| 99094 | duk_uint8_t *p_base, *p_dst, *p_src; |
| 99095 | duk_size_t buf_sz, move_sz; |
| 99096 | |
| 99097 | DUK_ASSERT(thr != NULL); |
| 99098 | DUK_ASSERT(bw != NULL); |
| 99099 | DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99100 | DUK_UNREF(thr); |
| 99101 | |
| 99102 | p_base = bw->p_base; |
| 99103 | buf_sz = (duk_size_t) (bw->p - p_base); |
| 99104 | move_sz = buf_sz - off; |
| 99105 | p_dst = p_base + off + len; |
| 99106 | p_src = p_base + off; |
| 99107 | duk_memmove_unsafe((void *) p_dst, (const void *) p_src, (size_t) move_sz); |
| 99108 | return p_src; /* point to start of 'reserved area' */ |
| 99109 | } |
| 99110 | |
| 99111 | DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) { |
| 99112 | DUK_ASSERT(thr != NULL); |
| 99113 | DUK_ASSERT(bw != NULL); |
| 99114 | DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99115 | |
| 99116 | DUK_BW_ENSURE(thr, bw, len); |
| 99117 | return duk_bw_insert_raw_area(thr, bw, off, len); |
| 99118 | } |
| 99119 | |
| 99120 | DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) { |
| 99121 | duk_size_t move_sz; |
| 99122 | |
| 99123 | duk_uint8_t *p_base; |
| 99124 | duk_uint8_t *p_src; |
| 99125 | duk_uint8_t *p_dst; |
| 99126 | |
| 99127 | DUK_ASSERT(thr != NULL); |
| 99128 | DUK_ASSERT(bw != NULL); |
| 99129 | DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw)); |
| 99130 | DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99131 | DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw)); |
| 99132 | DUK_UNREF(thr); |
| 99133 | |
| 99134 | p_base = bw->p_base; |
| 99135 | p_dst = p_base + off; |
| 99136 | p_src = p_dst + len; |
| 99137 | move_sz = (duk_size_t) (bw->p - p_src); |
| 99138 | duk_memmove_unsafe((void *) p_dst, |
| 99139 | (const void *) p_src, |
| 99140 | (size_t) move_sz); |
| 99141 | bw->p -= len; |
| 99142 | } |
| 99143 | |
| 99144 | /* |
| 99145 | * Assertion helpers |
| 99146 | */ |
| 99147 | |
| 99148 | #if defined(DUK_USE_ASSERTIONS) |
| 99149 | DUK_INTERNAL void duk_bw_assert_valid(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) { |
| 99150 | DUK_UNREF(thr); |
| 99151 | DUK_ASSERT(bw_ctx != NULL); |
| 99152 | DUK_ASSERT(bw_ctx->buf != NULL); |
| 99153 | DUK_ASSERT((DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0) || |
| 99154 | (bw_ctx->p != NULL && |
| 99155 | bw_ctx->p_base != NULL && |
| 99156 | bw_ctx->p_limit != NULL && |
| 99157 | bw_ctx->p_limit >= bw_ctx->p_base && |
| 99158 | bw_ctx->p >= bw_ctx->p_base && |
| 99159 | bw_ctx->p <= bw_ctx->p_limit)); |
| 99160 | } |
| 99161 | #endif |
| 99162 | #line 1 "duk_util_cast.c" |
| 99163 | /* |
| 99164 | * Cast helpers. |
| 99165 | * |
| 99166 | * C99+ coercion is challenging portability-wise because out-of-range casts |
| 99167 | * may invoke implementation defined or even undefined behavior. See e.g. |
| 99168 | * http://blog.frama-c.com/index.php?post/2013/10/09/Overflow-float-integer. |
| 99169 | * |
| 99170 | * Provide explicit cast helpers which try to avoid implementation defined |
| 99171 | * or undefined behavior. These helpers can then be simplified in the vast |
| 99172 | * majority of cases where the implementation defined or undefined behavior |
| 99173 | * is not problematic. |
| 99174 | */ |
| 99175 | |
| 99176 | /* #include duk_internal.h -> already included */ |
| 99177 | |
| 99178 | /* Portable double-to-integer cast which avoids undefined behavior and avoids |
| 99179 | * relying on fmin(), fmax(), or other intrinsics. Out-of-range results are |
| 99180 | * not assumed by caller, but here value is clamped, NaN converts to minval. |
| 99181 | */ |
| 99182 | #define DUK__DOUBLE_INT_CAST1(tname,minval,maxval) do { \ |
| 99183 | if (DUK_LIKELY(x >= (duk_double_t) (minval))) { \ |
| 99184 | DUK_ASSERT(!DUK_ISNAN(x)); \ |
| 99185 | if (DUK_LIKELY(x <= (duk_double_t) (maxval))) { \ |
| 99186 | return (tname) x; \ |
| 99187 | } else { \ |
| 99188 | return (tname) (maxval); \ |
| 99189 | } \ |
| 99190 | } else { \ |
| 99191 | /* NaN or below minval. Since we don't care about the result \ |
| 99192 | * for out-of-range values, just return the minimum value for \ |
| 99193 | * both. \ |
| 99194 | */ \ |
| 99195 | return (tname) (minval); \ |
| 99196 | } \ |
| 99197 | } while (0) |
| 99198 | |
| 99199 | /* Rely on specific NaN behavior for duk_double_{fmin,fmax}(): if either |
| 99200 | * argument is a NaN, return the second argument. This avoids a |
| 99201 | * NaN-to-integer cast which is undefined behavior. |
| 99202 | */ |
| 99203 | #define DUK__DOUBLE_INT_CAST2(tname,minval,maxval) do { \ |
| 99204 | return (tname) duk_double_fmin(duk_double_fmax(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \ |
| 99205 | } while (0) |
| 99206 | |
| 99207 | /* Another solution which doesn't need C99+ behavior for fmin() and fmax(). */ |
| 99208 | #define DUK__DOUBLE_INT_CAST3(tname,minval,maxval) do { \ |
| 99209 | if (DUK_ISNAN(x)) { \ |
| 99210 | /* 0 or any other value is fine. */ \ |
| 99211 | return (tname) 0; \ |
| 99212 | } else \ |
| 99213 | return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \ |
| 99214 | } \ |
| 99215 | } while (0) |
| 99216 | |
| 99217 | /* C99+ solution: relies on specific fmin() and fmax() behavior in C99: if |
| 99218 | * one argument is NaN but the other isn't, the non-NaN argument is returned. |
| 99219 | * Because the limits are non-NaN values, explicit NaN check is not needed. |
| 99220 | * This may not work on all legacy platforms, and also doesn't seem to inline |
| 99221 | * the fmin() and fmax() calls (unless one uses -ffast-math which we don't |
| 99222 | * support). |
| 99223 | */ |
| 99224 | #define DUK__DOUBLE_INT_CAST4(tname,minval,maxval) do { \ |
| 99225 | return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \ |
| 99226 | } while (0) |
| 99227 | |
| 99228 | DUK_INTERNAL duk_int_t duk_double_to_int_t(duk_double_t x) { |
| 99229 | #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 99230 | /* Real world solution: almost any practical platform will provide |
| 99231 | * an integer value without any guarantees what it is (which is fine). |
| 99232 | */ |
| 99233 | return (duk_int_t) x; |
| 99234 | #else |
| 99235 | DUK__DOUBLE_INT_CAST1(duk_int_t, DUK_INT_MIN, DUK_INT_MAX); |
| 99236 | #endif |
| 99237 | } |
| 99238 | |
| 99239 | DUK_INTERNAL duk_uint_t duk_double_to_uint_t(duk_double_t x) { |
| 99240 | #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 99241 | return (duk_uint_t) x; |
| 99242 | #else |
| 99243 | DUK__DOUBLE_INT_CAST1(duk_uint_t, DUK_UINT_MIN, DUK_UINT_MAX); |
| 99244 | #endif |
| 99245 | } |
| 99246 | |
| 99247 | DUK_INTERNAL duk_int32_t duk_double_to_int32_t(duk_double_t x) { |
| 99248 | #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 99249 | return (duk_int32_t) x; |
| 99250 | #else |
| 99251 | DUK__DOUBLE_INT_CAST1(duk_int32_t, DUK_INT32_MIN, DUK_INT32_MAX); |
| 99252 | #endif |
| 99253 | } |
| 99254 | |
| 99255 | DUK_INTERNAL duk_uint32_t duk_double_to_uint32_t(duk_double_t x) { |
| 99256 | #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 99257 | return (duk_uint32_t) x; |
| 99258 | #else |
| 99259 | DUK__DOUBLE_INT_CAST1(duk_uint32_t, DUK_UINT32_MIN, DUK_UINT32_MAX); |
| 99260 | #endif |
| 99261 | } |
| 99262 | |
| 99263 | /* Largest IEEE double that doesn't round to infinity in the default rounding |
| 99264 | * mode. The exact midpoint between (1 - 2^(-24)) * 2^128 and 2^128 rounds to |
| 99265 | * infinity, at least on x64. This number is one double unit below that |
| 99266 | * midpoint. See misc/float_cast.c. |
| 99267 | */ |
| 99268 | #define DUK__FLOAT_ROUND_LIMIT 340282356779733623858607532500980858880.0 |
| 99269 | |
| 99270 | /* Maximum IEEE float. Double-to-float conversion above this would be out of |
| 99271 | * range and thus technically undefined behavior. |
| 99272 | */ |
| 99273 | #define DUK__FLOAT_MAX 340282346638528859811704183484516925440.0 |
| 99274 | |
| 99275 | DUK_INTERNAL duk_float_t duk_double_to_float_t(duk_double_t x) { |
| 99276 | /* Even a double-to-float cast is technically undefined behavior if |
| 99277 | * the double is out-of-range. C99 Section 6.3.1.5: |
| 99278 | * |
| 99279 | * If the value being converted is in the range of values that can |
| 99280 | * be represented but cannot be represented exactly, the result is |
| 99281 | * either the nearest higher or nearest lower representable value, |
| 99282 | * chosen in an implementation-defined manner. If the value being |
| 99283 | * converted is outside the range of values that can be represented, |
| 99284 | * the behavior is undefined. |
| 99285 | */ |
| 99286 | #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 99287 | return (duk_float_t) x; |
| 99288 | #else |
| 99289 | duk_double_t t; |
| 99290 | |
| 99291 | t = DUK_FABS(x); |
| 99292 | DUK_ASSERT((DUK_ISNAN(x) && DUK_ISNAN(t)) || |
| 99293 | (!DUK_ISNAN(x) && !DUK_ISNAN(t))); |
| 99294 | |
| 99295 | if (DUK_LIKELY(t <= DUK__FLOAT_MAX)) { |
| 99296 | /* Standard in-range case, try to get here with a minimum |
| 99297 | * number of checks and branches. |
| 99298 | */ |
| 99299 | DUK_ASSERT(!DUK_ISNAN(x)); |
| 99300 | return (duk_float_t) x; |
| 99301 | } else if (t <= DUK__FLOAT_ROUND_LIMIT) { |
| 99302 | /* Out-of-range, but rounds to min/max float. */ |
| 99303 | DUK_ASSERT(!DUK_ISNAN(x)); |
| 99304 | if (x < 0.0) { |
| 99305 | return (duk_float_t) -DUK__FLOAT_MAX; |
| 99306 | } else { |
| 99307 | return (duk_float_t) DUK__FLOAT_MAX; |
| 99308 | } |
| 99309 | } else if (DUK_ISNAN(x)) { |
| 99310 | /* Assumes double NaN -> float NaN considered "in range". */ |
| 99311 | DUK_ASSERT(DUK_ISNAN(x)); |
| 99312 | return (duk_float_t) x; |
| 99313 | } else { |
| 99314 | /* Out-of-range, rounds to +/- Infinity. */ |
| 99315 | if (x < 0.0) { |
| 99316 | return (duk_float_t) -DUK_DOUBLE_INFINITY; |
| 99317 | } else { |
| 99318 | return (duk_float_t) DUK_DOUBLE_INFINITY; |
| 99319 | } |
| 99320 | } |
| 99321 | #endif |
| 99322 | } |
| 99323 | |
| 99324 | /* automatic undefs */ |
| 99325 | #undef DUK__DOUBLE_INT_CAST1 |
| 99326 | #undef DUK__DOUBLE_INT_CAST2 |
| 99327 | #undef DUK__DOUBLE_INT_CAST3 |
| 99328 | #undef DUK__DOUBLE_INT_CAST4 |
| 99329 | #undef DUK__FLOAT_MAX |
| 99330 | #undef DUK__FLOAT_ROUND_LIMIT |
| 99331 | #line 1 "duk_util_double.c" |
| 99332 | /* |
| 99333 | * IEEE double helpers. |
| 99334 | */ |
| 99335 | |
| 99336 | /* #include duk_internal.h -> already included */ |
| 99337 | |
| 99338 | DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) { |
| 99339 | duk_double_union du; |
| 99340 | du.d = x; |
| 99341 | return DUK_DBLUNION_IS_ANYINF(&du); |
| 99342 | } |
| 99343 | |
| 99344 | DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) { |
| 99345 | duk_double_union du; |
| 99346 | du.d = x; |
| 99347 | return DUK_DBLUNION_IS_POSINF(&du); |
| 99348 | } |
| 99349 | |
| 99350 | DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) { |
| 99351 | duk_double_union du; |
| 99352 | du.d = x; |
| 99353 | return DUK_DBLUNION_IS_NEGINF(&du); |
| 99354 | } |
| 99355 | |
| 99356 | DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) { |
| 99357 | duk_double_union du; |
| 99358 | du.d = x; |
| 99359 | /* Assumes we're dealing with a Duktape internal NaN which is |
| 99360 | * NaN normalized if duk_tval requires it. |
| 99361 | */ |
| 99362 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 99363 | return DUK_DBLUNION_IS_NAN(&du); |
| 99364 | } |
| 99365 | |
| 99366 | DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) { |
| 99367 | duk_double_union du; |
| 99368 | du.d = x; |
| 99369 | /* Assumes we're dealing with a Duktape internal NaN which is |
| 99370 | * NaN normalized if duk_tval requires it. |
| 99371 | */ |
| 99372 | DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); |
| 99373 | return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du); |
| 99374 | } |
| 99375 | |
| 99376 | DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) { |
| 99377 | duk_double_union du; |
| 99378 | du.d = x; |
| 99379 | /* If exponent is 0x7FF the argument is either a NaN or an |
| 99380 | * infinity. We don't need to check any other fields. |
| 99381 | */ |
| 99382 | #if defined(DUK_USE_64BIT_OPS) |
| 99383 | #if defined(DUK_USE_DOUBLE_ME) |
| 99384 | return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000); |
| 99385 | #else |
| 99386 | return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000); |
| 99387 | #endif |
| 99388 | #else |
| 99389 | return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL; |
| 99390 | #endif |
| 99391 | } |
| 99392 | |
| 99393 | DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) { |
| 99394 | duk_double_union du; |
| 99395 | #if defined(DUK_USE_64BIT_OPS) |
| 99396 | duk_uint64_t t; |
| 99397 | #else |
| 99398 | duk_uint32_t t; |
| 99399 | #endif |
| 99400 | du.d = x; |
| 99401 | #if defined(DUK_USE_64BIT_OPS) |
| 99402 | #if defined(DUK_USE_DOUBLE_ME) |
| 99403 | t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000); |
| 99404 | if (t == DUK_U64_CONSTANT(0x0000000000000000)) { |
| 99405 | t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000); |
| 99406 | return t == 0; |
| 99407 | } |
| 99408 | if (t == DUK_U64_CONSTANT(0x000000007ff00000)) { |
| 99409 | return 1; |
| 99410 | } |
| 99411 | #else |
| 99412 | t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000); |
| 99413 | if (t == DUK_U64_CONSTANT(0x0000000000000000)) { |
| 99414 | t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000); |
| 99415 | return t == 0; |
| 99416 | } |
| 99417 | if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) { |
| 99418 | return 1; |
| 99419 | } |
| 99420 | #endif |
| 99421 | #else |
| 99422 | t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL; |
| 99423 | if (t == 0x00000000UL) { |
| 99424 | return DUK_DBLUNION_IS_ANYZERO(&du); |
| 99425 | } |
| 99426 | if (t == 0x7ff00000UL) { |
| 99427 | return 1; |
| 99428 | } |
| 99429 | #endif |
| 99430 | return 0; |
| 99431 | } |
| 99432 | |
| 99433 | DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) { |
| 99434 | duk_double_union du; |
| 99435 | du.d = x; |
| 99436 | return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du); |
| 99437 | } |
| 99438 | |
| 99439 | DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) { |
| 99440 | /* XXX: optimize */ |
| 99441 | duk_small_uint_t s = duk_double_signbit(x); |
| 99442 | x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */ |
| 99443 | if (s) { |
| 99444 | x = -x; |
| 99445 | } |
| 99446 | return x; |
| 99447 | } |
| 99448 | |
| 99449 | DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) { |
| 99450 | duk_double_union du1; |
| 99451 | duk_double_union du2; |
| 99452 | du1.d = x; |
| 99453 | du2.d = y; |
| 99454 | |
| 99455 | return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0); |
| 99456 | } |
| 99457 | |
| 99458 | DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) { |
| 99459 | /* Doesn't replicate fmin() behavior exactly: for fmin() if one |
| 99460 | * argument is a NaN, the other argument should be returned. |
| 99461 | * Duktape doesn't rely on this behavior so the replacement can |
| 99462 | * be simplified. |
| 99463 | */ |
| 99464 | return (x < y ? x : y); |
| 99465 | } |
| 99466 | |
| 99467 | DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) { |
| 99468 | /* Doesn't replicate fmax() behavior exactly: for fmax() if one |
| 99469 | * argument is a NaN, the other argument should be returned. |
| 99470 | * Duktape doesn't rely on this behavior so the replacement can |
| 99471 | * be simplified. |
| 99472 | */ |
| 99473 | return (x > y ? x : y); |
| 99474 | } |
| 99475 | |
| 99476 | DUK_INTERNAL duk_bool_t duk_double_is_finite(duk_double_t x) { |
| 99477 | return !duk_double_is_nan_or_inf(x); |
| 99478 | } |
| 99479 | |
| 99480 | DUK_INTERNAL duk_bool_t duk_double_is_integer(duk_double_t x) { |
| 99481 | if (duk_double_is_nan_or_inf(x)) { |
| 99482 | return 0; |
| 99483 | } else { |
| 99484 | return duk_double_equals(duk_js_tointeger_number(x), x); |
| 99485 | } |
| 99486 | } |
| 99487 | |
| 99488 | DUK_INTERNAL duk_bool_t duk_double_is_safe_integer(duk_double_t x) { |
| 99489 | /* >>> 2**53-1 |
| 99490 | * 9007199254740991 |
| 99491 | */ |
| 99492 | return duk_double_is_integer(x) && DUK_FABS(x) <= 9007199254740991.0; |
| 99493 | } |
| 99494 | |
| 99495 | /* Check whether a duk_double_t is a whole number in the 32-bit range (reject |
| 99496 | * negative zero), and if so, return a duk_int32_t. |
| 99497 | * For compiler use: don't allow negative zero as it will cause trouble with |
| 99498 | * LDINT+LDINTX, positive zero is OK. |
| 99499 | */ |
| 99500 | DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) { |
| 99501 | duk_int32_t t; |
| 99502 | |
| 99503 | t = duk_double_to_int32_t(x); |
| 99504 | if (!duk_double_equals((duk_double_t) t, x)) { |
| 99505 | return 0; |
| 99506 | } |
| 99507 | if (t == 0) { |
| 99508 | duk_double_union du; |
| 99509 | du.d = x; |
| 99510 | if (DUK_DBLUNION_HAS_SIGNBIT(&du)) { |
| 99511 | return 0; |
| 99512 | } |
| 99513 | } |
| 99514 | *ival = t; |
| 99515 | return 1; |
| 99516 | } |
| 99517 | |
| 99518 | /* Check whether a duk_double_t is a whole number in the 32-bit range, and if |
| 99519 | * so, return a duk_int32_t. |
| 99520 | */ |
| 99521 | DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) { |
| 99522 | duk_int32_t t; |
| 99523 | |
| 99524 | t = duk_double_to_int32_t(x); |
| 99525 | if (!duk_double_equals((duk_double_t) t, x)) { |
| 99526 | return 0; |
| 99527 | } |
| 99528 | *ival = t; |
| 99529 | return 1; |
| 99530 | } |
| 99531 | |
| 99532 | /* Division: division by zero is undefined behavior (and may in fact trap) |
| 99533 | * so it needs special handling for portability. |
| 99534 | */ |
| 99535 | |
| 99536 | DUK_INTERNAL DUK_INLINE duk_double_t duk_double_div(duk_double_t x, duk_double_t y) { |
| 99537 | #if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 99538 | if (DUK_UNLIKELY(duk_double_equals(y, 0.0) != 0)) { |
| 99539 | /* In C99+ division by zero is undefined behavior so |
| 99540 | * avoid it entirely. Hopefully the compiler is |
| 99541 | * smart enough to avoid emitting any actual code |
| 99542 | * because almost all practical platforms behave as |
| 99543 | * expected. |
| 99544 | */ |
| 99545 | if (x > 0.0) { |
| 99546 | if (DUK_SIGNBIT(y)) { |
| 99547 | return -DUK_DOUBLE_INFINITY; |
| 99548 | } else { |
| 99549 | return DUK_DOUBLE_INFINITY; |
| 99550 | } |
| 99551 | } else if (x < 0.0) { |
| 99552 | if (DUK_SIGNBIT(y)) { |
| 99553 | return DUK_DOUBLE_INFINITY; |
| 99554 | } else { |
| 99555 | return -DUK_DOUBLE_INFINITY; |
| 99556 | } |
| 99557 | } else { |
| 99558 | /* +/- 0, NaN */ |
| 99559 | return DUK_DOUBLE_NAN; |
| 99560 | } |
| 99561 | } |
| 99562 | #endif |
| 99563 | |
| 99564 | return x / y; |
| 99565 | } |
| 99566 | |
| 99567 | /* Double and float byteorder changes. */ |
| 99568 | |
| 99569 | DUK_INTERNAL DUK_INLINE void duk_dblunion_host_to_little(duk_double_union *u) { |
| 99570 | #if defined(DUK_USE_DOUBLE_LE) |
| 99571 | /* HGFEDCBA -> HGFEDCBA */ |
| 99572 | DUK_UNREF(u); |
| 99573 | #elif defined(DUK_USE_DOUBLE_ME) |
| 99574 | duk_uint32_t a, b; |
| 99575 | |
| 99576 | /* DCBAHGFE -> HGFEDCBA */ |
| 99577 | a = u->ui[0]; |
| 99578 | b = u->ui[1]; |
| 99579 | u->ui[0] = b; |
| 99580 | u->ui[1] = a; |
| 99581 | #elif defined(DUK_USE_DOUBLE_BE) |
| 99582 | /* ABCDEFGH -> HGFEDCBA */ |
| 99583 | #if defined(DUK_USE_64BIT_OPS) |
| 99584 | u->ull[0] = DUK_BSWAP64(u->ull[0]); |
| 99585 | #else |
| 99586 | duk_uint32_t a, b; |
| 99587 | |
| 99588 | a = u->ui[0]; |
| 99589 | b = u->ui[1]; |
| 99590 | u->ui[0] = DUK_BSWAP32(b); |
| 99591 | u->ui[1] = DUK_BSWAP32(a); |
| 99592 | #endif |
| 99593 | #else |
| 99594 | #error internal error |
| 99595 | #endif |
| 99596 | } |
| 99597 | |
| 99598 | DUK_INTERNAL DUK_INLINE void duk_dblunion_little_to_host(duk_double_union *u) { |
| 99599 | duk_dblunion_host_to_little(u); |
| 99600 | } |
| 99601 | |
| 99602 | DUK_INTERNAL DUK_INLINE void duk_dblunion_host_to_big(duk_double_union *u) { |
| 99603 | #if defined(DUK_USE_DOUBLE_LE) |
| 99604 | /* HGFEDCBA -> ABCDEFGH */ |
| 99605 | #if defined(DUK_USE_64BIT_OPS) |
| 99606 | u->ull[0] = DUK_BSWAP64(u->ull[0]); |
| 99607 | #else |
| 99608 | duk_uint32_t a, b; |
| 99609 | |
| 99610 | a = u->ui[0]; |
| 99611 | b = u->ui[1]; |
| 99612 | u->ui[0] = DUK_BSWAP32(b); |
| 99613 | u->ui[1] = DUK_BSWAP32(a); |
| 99614 | #endif |
| 99615 | #elif defined(DUK_USE_DOUBLE_ME) |
| 99616 | duk_uint32_t a, b; |
| 99617 | |
| 99618 | /* DCBAHGFE -> ABCDEFGH */ |
| 99619 | a = u->ui[0]; |
| 99620 | b = u->ui[1]; |
| 99621 | u->ui[0] = DUK_BSWAP32(a); |
| 99622 | u->ui[1] = DUK_BSWAP32(b); |
| 99623 | #elif defined(DUK_USE_DOUBLE_BE) |
| 99624 | /* ABCDEFGH -> ABCDEFGH */ |
| 99625 | DUK_UNREF(u); |
| 99626 | #else |
| 99627 | #error internal error |
| 99628 | #endif |
| 99629 | } |
| 99630 | |
| 99631 | DUK_INTERNAL DUK_INLINE void duk_dblunion_big_to_host(duk_double_union *u) { |
| 99632 | duk_dblunion_host_to_big(u); |
| 99633 | } |
| 99634 | |
| 99635 | DUK_INTERNAL DUK_INLINE void duk_fltunion_host_to_big(duk_float_union *u) { |
| 99636 | #if defined(DUK_USE_DOUBLE_LE) || defined(DUK_USE_DOUBLE_ME) |
| 99637 | /* DCBA -> ABCD */ |
| 99638 | u->ui[0] = DUK_BSWAP32(u->ui[0]); |
| 99639 | #elif defined(DUK_USE_DOUBLE_BE) |
| 99640 | /* ABCD -> ABCD */ |
| 99641 | DUK_UNREF(u); |
| 99642 | #else |
| 99643 | #error internal error |
| 99644 | #endif |
| 99645 | } |
| 99646 | |
| 99647 | DUK_INTERNAL DUK_INLINE void duk_fltunion_big_to_host(duk_float_union *u) { |
| 99648 | duk_fltunion_host_to_big(u); |
| 99649 | } |
| 99650 | |
| 99651 | /* Comparison: ensures comparison operates on exactly correct types, avoiding |
| 99652 | * some floating point comparison pitfalls (e.g. atan2() assertions failed on |
| 99653 | * -m32 with direct comparison, even with explicit casts). |
| 99654 | */ |
| 99655 | #if defined(DUK_USE_GCC_PRAGMAS) |
| 99656 | #pragma GCC diagnostic push |
| 99657 | #pragma GCC diagnostic ignored "-Wfloat-equal" |
| 99658 | #elif defined(DUK_USE_CLANG_PRAGMAS) |
| 99659 | #pragma clang diagnostic push |
| 99660 | #pragma clang diagnostic ignored "-Wfloat-equal" |
| 99661 | #endif |
| 99662 | |
| 99663 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_bool_t duk_double_equals(duk_double_t x, duk_double_t y) { |
| 99664 | return x == y; |
| 99665 | } |
| 99666 | |
| 99667 | DUK_INTERNAL DUK_ALWAYS_INLINE duk_bool_t duk_float_equals(duk_float_t x, duk_float_t y) { |
| 99668 | return x == y; |
| 99669 | } |
| 99670 | #if defined(DUK_USE_GCC_PRAGMAS) |
| 99671 | #pragma GCC diagnostic pop |
| 99672 | #elif defined(DUK_USE_CLANG_PRAGMAS) |
| 99673 | #pragma clang diagnostic pop |
| 99674 | #endif |
| 99675 | #line 1 "duk_util_hashbytes.c" |
| 99676 | /* |
| 99677 | * Hash function duk_util_hashbytes(). |
| 99678 | * |
| 99679 | * Currently, 32-bit MurmurHash2. |
| 99680 | * |
| 99681 | * Don't rely on specific hash values; hash function may be endianness |
| 99682 | * dependent, for instance. |
| 99683 | */ |
| 99684 | |
| 99685 | /* #include duk_internal.h -> already included */ |
| 99686 | |
| 99687 | #if defined(DUK_USE_STRHASH_DENSE) |
| 99688 | /* 'magic' constants for Murmurhash2 */ |
| 99689 | #define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL) |
| 99690 | #define DUK__MAGIC_R 24 |
| 99691 | |
| 99692 | DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) { |
| 99693 | duk_uint32_t h = seed ^ ((duk_uint32_t) len); |
| 99694 | |
| 99695 | while (len >= 4) { |
| 99696 | /* Portability workaround is required for platforms without |
| 99697 | * unaligned access. The replacement code emulates little |
| 99698 | * endian access even on big endian architectures, which is |
| 99699 | * OK as long as it is consistent for a build. |
| 99700 | */ |
| 99701 | #if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS) |
| 99702 | duk_uint32_t k = *((const duk_uint32_t *) (const void *) data); |
| 99703 | #else |
| 99704 | duk_uint32_t k = ((duk_uint32_t) data[0]) | |
| 99705 | (((duk_uint32_t) data[1]) << 8) | |
| 99706 | (((duk_uint32_t) data[2]) << 16) | |
| 99707 | (((duk_uint32_t) data[3]) << 24); |
| 99708 | #endif |
| 99709 | |
| 99710 | k *= DUK__MAGIC_M; |
| 99711 | k ^= k >> DUK__MAGIC_R; |
| 99712 | k *= DUK__MAGIC_M; |
| 99713 | h *= DUK__MAGIC_M; |
| 99714 | h ^= k; |
| 99715 | data += 4; |
| 99716 | len -= 4; |
| 99717 | } |
| 99718 | |
| 99719 | switch (len) { |
| 99720 | case 3: h ^= data[2] << 16; |
| 99721 | case 2: h ^= data[1] << 8; |
| 99722 | case 1: h ^= data[0]; |
| 99723 | h *= DUK__MAGIC_M; |
| 99724 | } |
| 99725 | |
| 99726 | h ^= h >> 13; |
| 99727 | h *= DUK__MAGIC_M; |
| 99728 | h ^= h >> 15; |
| 99729 | |
| 99730 | return h; |
| 99731 | } |
| 99732 | #endif /* DUK_USE_STRHASH_DENSE */ |
| 99733 | |
| 99734 | /* automatic undefs */ |
| 99735 | #undef DUK__MAGIC_M |
| 99736 | #undef DUK__MAGIC_R |
| 99737 | #line 1 "duk_util_memory.c" |
| 99738 | /* |
| 99739 | * Memory utils. |
| 99740 | */ |
| 99741 | |
| 99742 | /* #include duk_internal.h -> already included */ |
| 99743 | |
| 99744 | #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR) |
| 99745 | DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) { |
| 99746 | DUK_ASSERT(s1 != NULL || len == 0U); |
| 99747 | DUK_ASSERT(s2 != NULL || len == 0U); |
| 99748 | return DUK_MEMCMP(s1, s2, (size_t) len); |
| 99749 | } |
| 99750 | |
| 99751 | DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) { |
| 99752 | DUK_ASSERT(s1 != NULL); |
| 99753 | DUK_ASSERT(s2 != NULL); |
| 99754 | return DUK_MEMCMP(s1, s2, (size_t) len); |
| 99755 | } |
| 99756 | #else /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ |
| 99757 | DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) { |
| 99758 | DUK_ASSERT(s1 != NULL || len == 0U); |
| 99759 | DUK_ASSERT(s2 != NULL || len == 0U); |
| 99760 | if (DUK_UNLIKELY(len == 0U)) { |
| 99761 | return 0; |
| 99762 | } |
| 99763 | DUK_ASSERT(s1 != NULL); |
| 99764 | DUK_ASSERT(s2 != NULL); |
| 99765 | return duk_memcmp(s1, s2, len); |
| 99766 | } |
| 99767 | |
| 99768 | DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) { |
| 99769 | DUK_ASSERT(s1 != NULL); |
| 99770 | DUK_ASSERT(s2 != NULL); |
| 99771 | return DUK_MEMCMP(s1, s2, (size_t) len); |
| 99772 | } |
| 99773 | #endif /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */ |
| 99774 | #line 1 "duk_util_tinyrandom.c" |
| 99775 | /* |
| 99776 | * A tiny random number generator used for Math.random() and other internals. |
| 99777 | * |
| 99778 | * Default algorithm is xoroshiro128+: http://xoroshiro.di.unimi.it/xoroshiro128plus.c |
| 99779 | * with SplitMix64 seed preparation: http://xorshift.di.unimi.it/splitmix64.c. |
| 99780 | * |
| 99781 | * Low memory targets and targets without 64-bit types use a slightly smaller |
| 99782 | * (but slower) algorithm by Adi Shamir: |
| 99783 | * http://www.woodmann.com/forum/archive/index.php/t-3100.html. |
| 99784 | * |
| 99785 | */ |
| 99786 | |
| 99787 | /* #include duk_internal.h -> already included */ |
| 99788 | |
| 99789 | #if !defined(DUK_USE_GET_RANDOM_DOUBLE) |
| 99790 | |
| 99791 | #if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS) |
| 99792 | #define DUK__RANDOM_SHAMIR3OP |
| 99793 | #else |
| 99794 | #define DUK__RANDOM_XOROSHIRO128PLUS |
| 99795 | #endif |
| 99796 | |
| 99797 | #if defined(DUK__RANDOM_SHAMIR3OP) |
| 99798 | #define DUK__UPDATE_RND(rnd) do { \ |
| 99799 | (rnd) += ((rnd) * (rnd)) | 0x05UL; \ |
| 99800 | (rnd) = ((rnd) & 0xffffffffUL); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \ |
| 99801 | } while (0) |
| 99802 | |
| 99803 | #define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */ |
| 99804 | |
| 99805 | DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) { |
| 99806 | DUK_UNREF(thr); /* Nothing now. */ |
| 99807 | } |
| 99808 | |
| 99809 | DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) { |
| 99810 | duk_double_t t; |
| 99811 | duk_small_int_t n; |
| 99812 | duk_uint32_t rnd; |
| 99813 | |
| 99814 | rnd = thr->heap->rnd_state; |
| 99815 | |
| 99816 | n = 53; /* enough to cover the whole mantissa */ |
| 99817 | t = 0.0; |
| 99818 | |
| 99819 | do { |
| 99820 | DUK__UPDATE_RND(rnd); |
| 99821 | t += DUK__RND_BIT(rnd); |
| 99822 | t /= 2.0; |
| 99823 | } while (--n); |
| 99824 | |
| 99825 | thr->heap->rnd_state = rnd; |
| 99826 | |
| 99827 | DUK_ASSERT(t >= (duk_double_t) 0.0); |
| 99828 | DUK_ASSERT(t < (duk_double_t) 1.0); |
| 99829 | |
| 99830 | return t; |
| 99831 | } |
| 99832 | #endif /* DUK__RANDOM_SHAMIR3OP */ |
| 99833 | |
| 99834 | #if defined(DUK__RANDOM_XOROSHIRO128PLUS) |
| 99835 | DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_splitmix64(duk_uint64_t *x) { |
| 99836 | duk_uint64_t z; |
| 99837 | z = (*x += DUK_U64_CONSTANT(0x9E3779B97F4A7C15)); |
| 99838 | z = (z ^ (z >> 30U)) * DUK_U64_CONSTANT(0xBF58476D1CE4E5B9); |
| 99839 | z = (z ^ (z >> 27U)) * DUK_U64_CONSTANT(0x94D049BB133111EB); |
| 99840 | return z ^ (z >> 31U); |
| 99841 | } |
| 99842 | |
| 99843 | DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_rotl(const duk_uint64_t x, duk_small_uint_t k) { |
| 99844 | return (x << k) | (x >> (64U - k)); |
| 99845 | } |
| 99846 | |
| 99847 | DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__xoroshiro128plus(duk_uint64_t *s) { |
| 99848 | duk_uint64_t s0; |
| 99849 | duk_uint64_t s1; |
| 99850 | duk_uint64_t res; |
| 99851 | |
| 99852 | s0 = s[0]; |
| 99853 | s1 = s[1]; |
| 99854 | res = s0 + s1; |
| 99855 | s1 ^= s0; |
| 99856 | s[0] = duk__rnd_rotl(s0, 55) ^ s1 ^ (s1 << 14U); |
| 99857 | s[1] = duk__rnd_rotl(s1, 36); |
| 99858 | |
| 99859 | return res; |
| 99860 | } |
| 99861 | |
| 99862 | DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) { |
| 99863 | duk_small_uint_t i; |
| 99864 | duk_uint64_t x; |
| 99865 | |
| 99866 | /* Mix both halves of the initial seed with SplitMix64. The intent |
| 99867 | * is to ensure that very similar raw seeds (which is usually the case |
| 99868 | * because current seed is Date.now()) result in different xoroshiro128+ |
| 99869 | * seeds. |
| 99870 | */ |
| 99871 | x = thr->heap->rnd_state[0]; /* Only [0] is used as input here. */ |
| 99872 | for (i = 0; i < 64; i++) { |
| 99873 | thr->heap->rnd_state[i & 0x01] = duk__rnd_splitmix64(&x); /* Keep last 2 values. */ |
| 99874 | } |
| 99875 | } |
| 99876 | |
| 99877 | DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) { |
| 99878 | duk_uint64_t v; |
| 99879 | duk_double_union du; |
| 99880 | |
| 99881 | /* For big and little endian the integer and IEEE double byte order |
| 99882 | * is the same so a direct assignment works. For mixed endian the |
| 99883 | * 32-bit parts must be swapped. |
| 99884 | */ |
| 99885 | v = (DUK_U64_CONSTANT(0x3ff) << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U); |
| 99886 | du.ull[0] = v; |
| 99887 | #if defined(DUK_USE_DOUBLE_ME) |
| 99888 | do { |
| 99889 | duk_uint32_t tmp; |
| 99890 | tmp = du.ui[0]; |
| 99891 | du.ui[0] = du.ui[1]; |
| 99892 | du.ui[1] = tmp; |
| 99893 | } while (0); |
| 99894 | #endif |
| 99895 | return du.d - 1.0; |
| 99896 | } |
| 99897 | #endif /* DUK__RANDOM_XOROSHIRO128PLUS */ |
| 99898 | |
| 99899 | #endif /* !DUK_USE_GET_RANDOM_DOUBLE */ |
| 99900 | |
| 99901 | /* automatic undefs */ |
| 99902 | #undef DUK__RANDOM_SHAMIR3OP |
| 99903 | #undef DUK__RANDOM_XOROSHIRO128PLUS |
| 99904 | #undef DUK__RND_BIT |
| 99905 | #undef DUK__UPDATE_RND |
| 99906 | |