Delete Duktape (#97)

This commit is contained in:
Justine Tunney 2021-03-08 13:17:52 -08:00
parent 0a61fe4ea0
commit 2a3037d4e8
157 changed files with 2 additions and 103725 deletions

View file

@ -131,7 +131,6 @@ include dsp/tty/tty.mk # ├──ONLINE RUNTIME
include libc/dns/dns.mk # │ You can communicate with the network
include libc/crypto/crypto.mk # │
include net/http/http.mk #─┘
include third_party/duktape/duktape.mk
include third_party/regex/regex.mk
include third_party/third_party.mk
include libc/testlib/testlib.mk

View file

@ -80,7 +80,6 @@ EXAMPLES_DEPS := \
o/$(MODE)/examples/examples.pkg: \
$(EXAMPLES_OBJS) \
$(THIRD_PARTY_DUKTAPE_A).pkg \
$(foreach x,$(EXAMPLES_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/examples/unbourne.o: \
@ -97,7 +96,6 @@ o/$(MODE)/examples/%.com.dbg: \
o/$(MODE)/examples/hellojs.com.dbg: \
$(EXAMPLES_DEPS) \
$(THIRD_PARTY_DUKTAPE) \
o/$(MODE)/examples/hellojs.o \
o/$(MODE)/examples/hello.js.zip.o \
o/$(MODE)/examples/examples.pkg \
@ -116,7 +114,6 @@ o/$(MODE)/examples/ispell.com.dbg: \
o/$(MODE)/examples/nesemu1.com.dbg: \
$(EXAMPLES_DEPS) \
$(THIRD_PARTY_DUKTAPE) \
o/$(MODE)/examples/nesemu1.o \
o/$(MODE)/usr/share/rom/mario.nes.zip.o \
o/$(MODE)/usr/share/rom/zelda.nes.zip.o \

View file

@ -1,2 +0,0 @@
console.log('Hello world!\n');
console.log('2+3=' + NativeAdd(2, 3) + '\n');

View file

@ -1,70 +0,0 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/sysv/consts/o.h"
#include "third_party/duktape/duktape.h"
STATIC_YOINK("zip_uri_support");
static duk_ret_t NativePrint(duk_context *ctx) {
duk_push_string(ctx, " ");
duk_insert(ctx, 0);
duk_join(ctx, duk_get_top(ctx) - 1);
fputs(duk_safe_to_string(ctx, -1), stdout);
return 0;
}
static duk_ret_t NativeAdd(duk_context *ctx) {
int i, n;
double r;
n = duk_get_top(ctx);
for (r = i = 0; i < n; i++) r += duk_to_number(ctx, i);
duk_push_number(ctx, r);
return 1;
}
int main(int argc, char *argv[]) {
int fd;
struct stat st;
const char *code;
duk_context *ctx;
showcrashreports();
ctx = duk_create_heap_default();
/* define NativeAdd() */
duk_push_c_function(ctx, NativeAdd, DUK_VARARGS);
duk_put_global_string(ctx, "NativeAdd");
/* define console.log() */
duk_push_global_object(ctx);
duk_push_c_function(ctx, NativePrint, DUK_VARARGS);
duk_push_string(ctx, "name");
duk_push_string(ctx, "log");
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
duk_set_magic(ctx, -1, 0);
duk_put_prop_string(ctx, -2, "log");
duk_put_global_string(ctx, "console");
CHECK_NE(-1, (fd = open("zip:examples/hello.js", O_RDONLY)));
CHECK_NE(-1, fstat(fd, &st));
CHECK_NOTNULL((code = _gc(calloc(1, st.st_size + 1))));
CHECK_EQ(st.st_size, read(fd, code, st.st_size));
CHECK_NE(-1, close(fd));
duk_eval_string(ctx, code);
duk_pop(ctx);
duk_destroy_heap(ctx);
return 0;
}

View file

@ -18,9 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Changes permissions on file, e.g.:

View file

@ -40,7 +40,7 @@ static int vdprintf_flush(struct VdprintfState *df, int n) {
return 0;
}
static int vdprintfputchar(int c, struct VdprintfState *df) {
static int vdprintf_putc(int c, struct VdprintfState *df) {
df->buf[df->n++ & (ARRAYLEN(df->buf) - 1)] = c & 0xff;
if ((df->n & (ARRAYLEN(df->buf) - 1))) {
return 0;
@ -58,7 +58,7 @@ int(vdprintf)(int fd, const char *fmt, va_list va) {
struct VdprintfState df;
df.n = 0;
df.fd = fd;
if (__fmt(vdprintfputchar, &df, fmt, va) == -1) return -1;
if (__fmt(vdprintf_putc, &df, fmt, va) == -1) return -1;
if (vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) == -1) return -1;
return df.n;
}

View file

@ -1,25 +0,0 @@
===============
Duktape license
===============
(http://opensource.org/licenses/MIT)
Copyright (c) 2013-2019 by Duktape authors (see AUTHORS.rst)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,110 +0,0 @@
===============
Duktape authors
===============
Copyright
=========
Duktape copyrights are held by its authors. Each author has a copyright
to their contribution, and agrees to irrevocably license the contribution
under the Duktape ``LICENSE.txt``.
Authors
=======
Please include an e-mail address, a link to your GitHub profile, or something
similar to allow your contribution to be identified accurately.
The following people have contributed code, website contents, or Wiki contents,
and agreed to irrevocably license their contributions under the Duktape
``LICENSE.txt`` (in order of appearance):
* Sami Vaarala <sami.vaarala@iki.fi>
* Niki Dobrev
* Andreas Öman <andreas@lonelycoder.com>
* László Langó <llango.u-szeged@partner.samsung.com>
* Legimet <legimet.calc@gmail.com>
* Karl Skomski <karl@skomski.com>
* Bruce Pascoe <fatcerberus1@gmail.com>
* René Hollander <rene@rene8888.at>
* Julien Hamaide (https://github.com/crazyjul)
* Sebastian Götte (https://github.com/jaseg)
* Tomasz Magulski (https://github.com/magul)
* \D. Bohdan (https://github.com/dbohdan)
* Ondřej Jirman (https://github.com/megous)
* Saúl Ibarra Corretgé <saghul@gmail.com>
* Jeremy HU <huxingyi@msn.com>
* Ole André Vadla Ravnås (https://github.com/oleavr)
* Harold Brenes (https://github.com/harold-b)
* Oliver Crow (https://github.com/ocrow)
* Jakub Chłapiński (https://github.com/jchlapinski)
* Brett Vickers (https://github.com/beevik)
* Dominik Okwieka (https://github.com/okitec)
* Remko Tronçon (https://el-tramo.be)
* Romero Malaquias (rbsm@ic.ufal.br)
* Michael Drake <michael.drake@codethink.co.uk>
* Steven Don (https://github.com/shdon)
* Simon Stone (https://github.com/sstone1)
* \J. McC. (https://github.com/jmhmccr)
* Jakub Nowakowski (https://github.com/jimvonmoon)
* Tommy Nguyen (https://github.com/tn0502)
* Fabrice Fontaine (https://github.com/ffontaine)
* Christopher Hiller (https://github.com/boneskull)
* Gonzalo Diethelm (https://github.com/gonzus)
* Michal Kasperek (https://github.com/michalkas)
* Andrew Janke (https://github.com/apjanke)
* Steve Fan (https://github.com/stevefan1999)
* Edward Betts (https://github.com/edwardbetts)
* Ozhan Duz (https://github.com/webfolderio)
* Akos Kiss (https://github.com/akosthekiss)
* TheBrokenRail (https://github.com/TheBrokenRail)
* Jesse Doyle (https://github.com/jessedoyle)
* Gero Kuehn (https://github.com/dc6jgk)
* James Swift (https://github.com/phraemer)
* Luis de Bethencourt (https://github.com/luisbg)
* Ian Whyman (https://github.com/v00d00)
Other contributions
===================
The following people have contributed something other than code (e.g. reported
bugs, provided ideas, etc; roughly in order of appearance):
* Greg Burns
* Anthony Rabine
* Carlos Costa
* Aurélien Bouilland
* Preet Desai (Pris Matic)
* judofyr (http://www.reddit.com/user/judofyr)
* Jason Woofenden
* Michał Przybyś
* Anthony Howe
* Conrad Pankoff
* Jim Schimpf
* Rajaran Gaunker (https://github.com/zimbabao)
* Andreas Öman
* Doug Sanden
* Josh Engebretson (https://github.com/JoshEngebretson)
* Remo Eichenberger (https://github.com/remoe)
* Mamod Mehyar (https://github.com/mamod)
* David Demelier (https://github.com/markand)
* Tim Caswell (https://github.com/creationix)
* Mitchell Blank Jr (https://github.com/mitchblank)
* https://github.com/yushli
* Seo Sanghyeon (https://github.com/sanxiyn)
* Han ChoongWoo (https://github.com/tunz)
* Joshua Peek (https://github.com/josh)
* Bruce E. Pascoe (https://github.com/fatcerberus)
* https://github.com/Kelledin
* https://github.com/sstruchtrup
* Michael Drake (https://github.com/tlsa)
* https://github.com/chris-y
* Laurent Zubiaur (https://github.com/lzubiaur)
* Neil Kolban (https://github.com/nkolban)
* Wilhelm Wanecek (https://github.com/wanecek)
* Andrew Janke (https://github.com/apjanke)
* Unamer (https://github.com/unamer)
* Karl Dahlke (eklhad@gmail.com)
If you are accidentally missing from this list, send me an e-mail
(``sami.vaarala@iki.fi``) and I'll fix the omission.

View file

@ -1,34 +0,0 @@
/*
* Default allocation functions.
*
* Assumes behavior such as malloc allowing zero size, yielding
* a NULL or a unique pointer which is a no-op for free.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
void *res;
DUK_UNREF(udata);
res = DUK_ANSI_MALLOC(size);
DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p",
(unsigned long) size, (void *) res));
return res;
}
DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) {
void *res;
DUK_UNREF(udata);
res = DUK_ANSI_REALLOC(ptr, newsize);
DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p",
(void *) ptr, (unsigned long) newsize, (void *) res));
return res;
}
DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr));
DUK_UNREF(udata);
DUK_ANSI_FREE(ptr);
}
#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */

View file

@ -1,73 +0,0 @@
/*
* Buffer
*/
#include "third_party/duktape/duk_internal.h"
DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) {
duk_hbuffer_dynamic *h;
DUK_ASSERT_API_ENTRY(thr);
h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
DUK_WO_NORETURN(return NULL;);
}
/* Maximum size check is handled by callee. */
duk_hbuffer_resize(thr, h, new_size);
return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
}
DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
duk_hbuffer_dynamic *h;
void *ptr;
duk_size_t sz;
DUK_ASSERT_API_ENTRY(thr);
h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
DUK_WO_NORETURN(return NULL;);
}
/* Forget the previous allocation, setting size to 0 and alloc to
* NULL. Caller is responsible for freeing the previous allocation.
* Getting the allocation and clearing it is done in the same API
* call to avoid any chance of a realloc.
*/
ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
if (out_size) {
*out_size = sz;
}
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
return ptr;
}
DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) {
duk_hbuffer_external *h;
DUK_ASSERT_API_ENTRY(thr);
h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx);
DUK_ASSERT(h != NULL);
if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
DUK_WO_NORETURN(return;);
}
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
}

View file

@ -1,760 +0,0 @@
/*
* Bytecode dump/load
*
* The bytecode load primitive is more important performance-wise than the
* dump primitive.
*
* Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
* memory safe for invalid arguments - caller beware! There's little point
* in trying to achieve memory safety unless bytecode instructions are also
* validated which is not easy to do with indirect register references etc.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
#define DUK__SER_MARKER 0xbf
#define DUK__SER_STRING 0x00
#define DUK__SER_NUMBER 0x01
#define DUK__BYTECODE_INITIAL_ALLOC 256
#define DUK__NO_FORMALS 0xffffffffUL
/*
* Dump/load helpers, xxx_raw() helpers do no buffer checks
*/
DUK_LOCAL const duk_uint8_t *duk__load_string_raw(duk_hthread *thr, const duk_uint8_t *p) {
duk_uint32_t len;
len = DUK_RAW_READINC_U32_BE(p);
duk_push_lstring(thr, (const char *) p, len);
p += len;
return p;
}
DUK_LOCAL const duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, const duk_uint8_t *p) {
duk_uint32_t len;
duk_uint8_t *buf;
len = DUK_RAW_READINC_U32_BE(p);
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);
DUK_ASSERT(buf != NULL);
duk_memcpy((void *) buf, (const void *) p, (size_t) len);
p += len;
return p;
}
DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
duk_size_t len;
duk_uint32_t tmp32;
DUK_ASSERT(h != NULL);
len = DUK_HSTRING_GET_BYTELEN(h);
DUK_ASSERT(len <= 0xffffffffUL); /* string limits */
tmp32 = (duk_uint32_t) len;
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
duk_memcpy((void *) p,
(const void *) DUK_HSTRING_GET_DATA(h),
len);
p += len;
return p;
}
DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) {
duk_size_t len;
duk_uint32_t tmp32;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(h != NULL);
DUK_UNREF(thr);
len = DUK_HBUFFER_GET_SIZE(h);
DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
tmp32 = (duk_uint32_t) len;
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
/* When len == 0, buffer data pointer may be NULL. */
duk_memcpy_unsafe((void *) p,
(const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
len);
p += len;
return p;
}
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) {
duk_hstring *h_str;
duk_tval *tv;
tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx);
if (tv != NULL && DUK_TVAL_IS_STRING(tv)) {
h_str = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h_str != NULL);
} else {
h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
DUK_ASSERT(h_str != NULL);
}
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
p = duk__dump_hstring_raw(p, h_str);
return p;
}
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) {
duk_tval *tv;
tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx);
if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) {
duk_hbuffer *h_buf;
h_buf = DUK_TVAL_GET_BUFFER(tv);
DUK_ASSERT(h_buf != NULL);
DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p);
p = duk__dump_hbuffer_raw(thr, p, h_buf);
} else {
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITEINC_U32_BE(p, 0);
}
return p;
}
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) {
duk_tval *tv;
duk_uint32_t val;
tv = duk_hobject_find_entry_tval_ptr_stridx(thr->heap, (duk_hobject *) func, stridx);
if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) {
val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
} else {
val = def_value;
}
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITEINC_U32_BE(p, val);
return p;
}
DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
duk_hobject *h;
h = duk_hobject_get_varmap(thr, (duk_hobject *) func);
if (h != NULL) {
duk_uint_fast32_t i;
/* We know _Varmap only has own properties so walk property
* table directly. We also know _Varmap is dense and all
* values are numbers; assert for these. GC and finalizers
* shouldn't affect _Varmap so side effects should be fine.
*/
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
duk_hstring *key;
duk_tval *tv_val;
duk_uint32_t val;
key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
DUK_ASSERT(key != NULL); /* _Varmap is dense */
DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i));
tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i);
DUK_ASSERT(tv_val != NULL);
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */
#if defined(DUK_USE_FASTINT)
DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val));
DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */
val = DUK_TVAL_GET_FASTINT_U32(tv_val);
#else
val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val);
#endif
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p);
p = duk__dump_hstring_raw(p, key);
DUK_RAW_WRITEINC_U32_BE(p, val);
}
}
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITEINC_U32_BE(p, 0); /* end of _Varmap */
return p;
}
DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
duk_harray *h;
h = duk_hobject_get_formals(thr, (duk_hobject *) func);
if (h != NULL) {
duk_uint32_t i;
/* Here we rely on _Formals being a dense array containing
* strings. This should be the case unless _Formals has been
* tweaked by the application (which we don't support right
* now).
*/
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */
DUK_RAW_WRITEINC_U32_BE(p, h->length);
for (i = 0; i < h->length; i++) {
duk_tval *tv_val;
duk_hstring *varname;
tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
DUK_ASSERT(tv_val != NULL);
DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
varname = DUK_TVAL_GET_STRING(tv_val);
DUK_ASSERT(varname != NULL);
DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p);
p = duk__dump_hstring_raw(p, varname);
}
} else {
DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
DUK_RAW_WRITEINC_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */
}
return p;
}
static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
duk_tval *tv, *tv_end;
duk_instr_t *ins, *ins_end;
duk_hobject **fn, **fn_end;
duk_hstring *h_str;
duk_uint32_t count_instr;
duk_uint32_t tmp32;
duk_uint16_t tmp16;
duk_double_t d;
DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
"consts=[%p,%p[ (%ld bytes, %ld items), "
"funcs=[%p,%p[ (%ld bytes, %ld items), "
"code=[%p,%p[ (%ld bytes, %ld items)",
(void *) func,
(void *) p,
(void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func),
(void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func),
(long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func),
(long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func),
(void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func),
(void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func),
(long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func),
(long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func),
(void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func),
(void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func),
(long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func),
(long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func)));
DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func);
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p);
/* Fixed header info. */
tmp32 = count_instr;
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func);
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func);
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
tmp16 = func->nregs;
DUK_RAW_WRITEINC_U16_BE(p, tmp16);
tmp16 = func->nargs;
DUK_RAW_WRITEINC_U16_BE(p, tmp16);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
tmp32 = func->start_line;
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
tmp32 = func->end_line;
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
#else
DUK_RAW_WRITEINC_U32_BE(p, 0);
DUK_RAW_WRITEINC_U32_BE(p, 0);
#endif
tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */
tmp32 &= ~(DUK_HOBJECT_FLAG_HAVE_FINALIZER); /* finalizer flag is lost */
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
/* Bytecode instructions: endian conversion needed unless
* platform is big endian.
*/
ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func);
ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
#if defined(DUK_USE_INTEGER_BE)
duk_memcpy_unsafe((void *) p, (const void *) ins, (size_t) (ins_end - ins));
p += (size_t) (ins_end - ins);
#else
while (ins != ins_end) {
tmp32 = (duk_uint32_t) (*ins);
DUK_RAW_WRITEINC_U32_BE(p, tmp32);
ins++;
}
#endif
/* Constants: variable size encoding. */
tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func);
tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func);
while (tv != tv_end) {
/* constants are strings or numbers now */
DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
DUK_TVAL_IS_NUMBER(tv));
if (DUK_TVAL_IS_STRING(tv)) {
h_str = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h_str != NULL);
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
*p++ = DUK__SER_STRING;
p = duk__dump_hstring_raw(p, h_str);
} else {
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p);
*p++ = DUK__SER_NUMBER;
d = DUK_TVAL_GET_NUMBER(tv);
DUK_RAW_WRITEINC_DOUBLE_BE(p, d);
}
tv++;
}
/* Inner functions recursively. */
fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func);
fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func);
while (fn != fn_end) {
/* XXX: This causes recursion up to inner function depth
* which is normally not an issue, e.g. mark-and-sweep uses
* a recursion limiter to avoid C stack issues. Avoiding
* this would mean some sort of a work list or just refusing
* to serialize deep functions.
*/
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn));
p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p);
fn++;
}
/* Lexenv and varenv are not dumped. */
/* Object extra properties.
*
* There are some difference between function templates and functions.
* For example, function templates don't have .length and nargs is
* normally used to instantiate the functions.
*/
p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
#if defined(DUK_USE_FUNC_NAME_PROPERTY)
p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
#endif
#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
#endif
#if defined(DUK_USE_PC2LINE)
p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
#endif
p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p));
return p;
}
/* Load a function from bytecode. The function object returned here must
* match what is created by duk_js_push_closure() with respect to its flags,
* properties, etc.
*
* NOTE: there are intentionally no input buffer length / bound checks.
* Adding them would be easy but wouldn't ensure memory safety as untrusted
* or broken bytecode is unsafe during execution unless the opcodes themselves
* are validated (which is quite complex, especially for indirect opcodes).
*/
#define DUK__ASSERT_LEFT(n) do { \
DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
} while (0)
static const duk_uint8_t *duk__load_func(duk_hthread *thr, const duk_uint8_t *p, const duk_uint8_t *p_end) {
duk_hcompfunc *h_fun;
duk_hbuffer *h_data;
duk_size_t data_size;
duk_uint32_t count_instr, count_const, count_funcs;
duk_uint32_t n;
duk_uint32_t tmp32;
duk_small_uint_t const_type;
duk_uint8_t *fun_data;
duk_uint8_t *q;
duk_idx_t idx_base;
duk_tval *tv1;
duk_uarridx_t arr_idx;
duk_uarridx_t arr_limit;
duk_hobject *func_env;
duk_bool_t need_pop;
/* XXX: There's some overlap with duk_js_closure() here, but
* seems difficult to share code. Ensure that the final function
* looks the same as created by duk_js_closure().
*/
DUK_ASSERT(thr != NULL);
DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
DUK__ASSERT_LEFT(3 * 4);
count_instr = DUK_RAW_READINC_U32_BE(p);
count_const = DUK_RAW_READINC_U32_BE(p);
count_funcs = DUK_RAW_READINC_U32_BE(p);
data_size = sizeof(duk_tval) * count_const +
sizeof(duk_hobject *) * count_funcs +
sizeof(duk_instr_t) * count_instr;
DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
(long) count_instr, (long) count_const,
(long) count_const, (long) data_size));
/* Value stack is used to ensure reachability of constants and
* inner functions being loaded. Require enough space to handle
* large functions correctly.
*/
duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs));
idx_base = duk_get_top(thr);
/* Push function object, init flags etc. This must match
* duk_js_push_closure() quite carefully.
*/
h_fun = duk_push_hcompfunc(thr);
DUK_ASSERT(h_fun != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun));
DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL);
DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL);
DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
h_fun->nregs = DUK_RAW_READINC_U16_BE(p);
h_fun->nargs = DUK_RAW_READINC_U16_BE(p);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
h_fun->start_line = DUK_RAW_READINC_U32_BE(p);
h_fun->end_line = DUK_RAW_READINC_U32_BE(p);
#else
p += 8; /* skip line info */
#endif
/* duk_hcompfunc flags; quite version specific */
tmp32 = DUK_RAW_READINC_U32_BE(p);
DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */
/* standard prototype (no need to set here, already set) */
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
#if 0
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
#endif
/* assert just a few critical flags */
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj));
DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_IS_PROXY(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
/* Create function 'data' buffer but don't attach it yet. */
fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size);
DUK_ASSERT(fun_data != NULL);
/* Load bytecode instructions. */
DUK_ASSERT(sizeof(duk_instr_t) == 4);
DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
#if defined(DUK_USE_INTEGER_BE)
q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
duk_memcpy((void *) q,
(const void *) p,
sizeof(duk_instr_t) * count_instr);
p += sizeof(duk_instr_t) * count_instr;
#else
q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
for (n = count_instr; n > 0; n--) {
*((duk_instr_t *) (void *) q) = DUK_RAW_READINC_U32_BE(p);
q += sizeof(duk_instr_t);
}
#endif
/* Load constants onto value stack but don't yet copy to buffer. */
for (n = count_const; n > 0; n--) {
DUK__ASSERT_LEFT(1);
const_type = DUK_RAW_READINC_U8(p);
switch (const_type) {
case DUK__SER_STRING: {
p = duk__load_string_raw(thr, p);
break;
}
case DUK__SER_NUMBER: {
/* Important to do a fastint check so that constants are
* properly read back as fastints.
*/
duk_tval tv_tmp;
duk_double_t val;
DUK__ASSERT_LEFT(8);
val = DUK_RAW_READINC_DOUBLE_BE(p);
DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val);
duk_push_tval(thr, &tv_tmp);
break;
}
default: {
goto format_error;
}
}
}
/* Load inner functions to value stack, but don't yet copy to buffer. */
for (n = count_funcs; n > 0; n--) {
p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
}
/* With constants and inner functions on value stack, we can now
* atomically finish the function 'data' buffer, bump refcounts,
* etc.
*
* Here we take advantage of the value stack being just a duk_tval
* array: we can just memcpy() the constants as long as we incref
* them afterwards.
*/
h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1);
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data);
DUK_HBUFFER_INCREF(thr, h_data);
tv1 = duk_get_tval(thr, idx_base + 2); /* may be NULL if no constants or inner funcs */
DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
q = fun_data;
duk_memcpy_unsafe((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
for (n = count_const; n > 0; n--) {
DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
q += sizeof(duk_tval);
}
tv1 += count_const;
DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
for (n = count_funcs; n > 0; n--) {
duk_hobject *h_obj;
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
h_obj = DUK_TVAL_GET_OBJECT(tv1);
DUK_ASSERT(h_obj != NULL);
tv1++;
DUK_HOBJECT_INCREF(thr, h_obj);
*((duk_hobject **) (void *) q) = h_obj;
q += sizeof(duk_hobject *);
}
DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
/* The function object is now reachable and refcounts are fine,
* so we can pop off all the temporaries.
*/
DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(thr, idx_base)));
duk_set_top(thr, idx_base + 1);
/* Setup function properties. */
tmp32 = DUK_RAW_READINC_U32_BE(p);
duk_push_u32(thr, tmp32);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
#if defined(DUK_USE_FUNC_NAME_PROPERTY)
p = duk__load_string_raw(thr, p); /* -> [ func funcname ] */
func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
DUK_ASSERT(func_env != NULL);
need_pop = 0;
if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
/* Original function instance/template had NAMEBINDING.
* Must create a lexical environment on loading to allow
* recursive functions like 'function foo() { foo(); }'.
*/
duk_hdecenv *new_env;
new_env = duk_hdecenv_alloc(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
DUK_ASSERT(new_env->thread == NULL); /* Closed. */
DUK_ASSERT(new_env->varmap == NULL);
DUK_ASSERT(new_env->regbase_byteoff == 0);
DUK_HDECENV_ASSERT_VALID(new_env);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env);
DUK_HOBJECT_INCREF(thr, func_env);
func_env = (duk_hobject *) new_env;
duk_push_hobject(thr, (duk_hobject *) new_env);
duk_dup_m2(thr); /* -> [ func funcname env funcname ] */
duk_dup(thr, idx_base); /* -> [ func funcname env funcname func ] */
duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */
}
DUK_ASSERT(func_env != NULL);
DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env);
DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env);
DUK_HOBJECT_INCREF(thr, func_env);
DUK_HOBJECT_INCREF(thr, func_env);
if (need_pop) {
duk_pop(thr);
}
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
#endif /* DUK_USE_FUNC_NAME_PROPERTY */
#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
p = duk__load_string_raw(thr, p);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */
if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) {
/* Restore empty external .prototype only for constructable
* functions. The prototype object should inherit from
* Object.prototype.
*/
duk_push_object(thr);
DUK_ASSERT(!duk_is_bare_object(thr, -1));
duk_dup_m2(thr);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
duk_compact_m1(thr);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
}
#if defined(DUK_USE_PC2LINE)
p = duk__load_buffer_raw(thr, p);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
#endif /* DUK_USE_PC2LINE */
duk_push_bare_object(thr); /* _Varmap */
for (;;) {
/* XXX: awkward */
p = duk__load_string_raw(thr, p);
if (duk_get_length(thr, -1) == 0) {
duk_pop(thr);
break;
}
tmp32 = DUK_RAW_READINC_U32_BE(p);
duk_push_u32(thr, tmp32);
duk_put_prop(thr, -3);
}
duk_compact_m1(thr);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
/* _Formals may have been missing in the original function, which is
* handled using a marker length.
*/
arr_limit = DUK_RAW_READINC_U32_BE(p);
if (arr_limit != DUK__NO_FORMALS) {
duk_push_bare_array(thr); /* _Formals */
for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
p = duk__load_string_raw(thr, p);
duk_put_prop_index(thr, -2, arr_idx);
}
duk_compact_m1(thr);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
} else {
DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
}
/* Return with final function pushed on stack top. */
DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(thr, -1)));
DUK_ASSERT_TOP(thr, idx_base + 1);
return p;
format_error:
return NULL;
}
DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
duk_hcompfunc *func;
duk_bufwriter_ctx bw_ctx_alloc;
duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
duk_uint8_t *p;
DUK_ASSERT_API_ENTRY(thr);
/* Bound functions don't have all properties so we'd either need to
* lookup the non-bound target function or reject bound functions.
* For now, bound functions are rejected with TypeError.
*/
func = duk_require_hcompfunc(thr, -1);
DUK_ASSERT(func != NULL);
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj));
/* Estimating the result size beforehand would be costly, so
* start with a reasonable size and extend as needed.
*/
DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
p = DUK_BW_GET_PTR(thr, bw_ctx);
*p++ = DUK__SER_MARKER;
p = duk__dump_func(thr, func, bw_ctx, p);
DUK_BW_SET_PTR(thr, bw_ctx, p);
DUK_BW_COMPACT(thr, bw_ctx);
DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(thr, -1)));
duk_remove_m2(thr); /* [ ... func buf ] -> [ ... buf ] */
}
DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
const duk_uint8_t *p_buf, *p, *p_end;
duk_size_t sz;
DUK_ASSERT_API_ENTRY(thr);
p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz);
DUK_ASSERT(p_buf != NULL);
/* The caller is responsible for being sure that bytecode being loaded
* is valid and trusted. Invalid bytecode can cause memory unsafe
* behavior directly during loading or later during bytecode execution
* (instruction validation would be quite complex to implement).
*
* This signature check is the only sanity check for detecting
* accidental invalid inputs. The initial byte ensures no ordinary
* string or Symbol will be accepted by accident.
*/
p = p_buf;
p_end = p_buf + sz;
if (sz < 1 || p[0] != DUK__SER_MARKER) {
goto format_error;
}
p++;
p = duk__load_func(thr, p, p_end);
if (p == NULL) {
goto format_error;
}
duk_remove_m2(thr); /* [ ... buf func ] -> [ ... func ] */
return;
format_error:
DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE);
DUK_WO_NORETURN(return;);
}
#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */

View file

@ -1,516 +0,0 @@
/*
* Calls.
*
* Protected variants should avoid ever throwing an error. Must be careful
* to catch errors related to value stack manipulation and property lookup,
* not just the call itself.
*
* The only exception is when arguments are insane, e.g. nargs/nrets are out
* of bounds; in such cases an error is thrown for two reasons. First, we
* can't always respect the value stack input/output guarantees in such cases
* so the caller would end up with the value stack in an unexpected state.
* Second, an attempt to create an error might itself fail (although this
* could be avoided by pushing a preallocated object/string or a primitive
* value).
*/
#include "third_party/duktape/duk_internal.h"
/*
* Helpers
*/
struct duk__pcall_prop_args {
duk_idx_t obj_idx;
duk_idx_t nargs;
duk_small_uint_t call_flags;
};
typedef struct duk__pcall_prop_args duk__pcall_prop_args;
struct duk__pcall_method_args {
duk_idx_t nargs;
duk_small_uint_t call_flags;
};
typedef struct duk__pcall_method_args duk__pcall_method_args;
struct duk__pcall_args {
duk_idx_t nargs;
duk_small_uint_t call_flags;
};
typedef struct duk__pcall_args duk__pcall_args;
/* Compute and validate idx_func for a certain 'nargs' and 'other'
* parameter count (1 or 2, depending on whether 'this' binding is
* present).
*/
DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
duk_idx_t idx_func;
/* XXX: byte arithmetic? */
DUK_ASSERT(other >= 0);
idx_func = duk_get_top(thr) - nargs - other;
if (DUK_UNLIKELY((idx_func | nargs) < 0)) { /* idx_func < 0 || nargs < 0; OR sign bits */
DUK_ERROR_TYPE_INVALID_ARGS(thr);
DUK_WO_NORETURN(return 0;);
}
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
return idx_func;
}
/* Compute idx_func, assume index will be valid. This is a valid assumption
* for protected calls: nargs < 0 is checked explicitly and duk_safe_call()
* validates the argument count.
*/
DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
duk_idx_t idx_func;
/* XXX: byte arithmetic? */
DUK_ASSERT(nargs >= 0);
DUK_ASSERT(other >= 0);
idx_func = duk_get_top(thr) - nargs - other;
DUK_ASSERT(idx_func >= 0);
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
return idx_func;
}
/* Prepare value stack for a method call through an object property.
* May currently throw an error e.g. when getting the property.
*/
DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
DUK_CTX_ASSERT_VALID(thr);
DUK_ASSERT(nargs >= 0);
DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld",
(long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr)));
/* [... key arg1 ... argN] */
/* duplicate key */
duk_dup(thr, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
(void) duk_get_prop(thr, normalized_obj_idx);
DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(thr, -1)));
#if defined(DUK_USE_VERBOSE_ERRORS)
if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) {
duk_tval *tv_base;
duk_tval *tv_key;
/* tv_targ is passed on stack top (at index -1). */
tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx);
tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2);
DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top);
DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top);
duk_call_setup_propcall_error(thr, tv_base, tv_key);
}
#endif
/* [... key arg1 ... argN func] */
duk_replace(thr, -nargs - 2);
/* [... func arg1 ... argN] */
duk_dup(thr, normalized_obj_idx);
duk_insert(thr, -nargs - 1);
/* [... func this arg1 ... argN] */
}
DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
DUK_ASSERT_API_ENTRY(thr);
idx_func = duk__call_get_idx_func(thr, nargs, 1);
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
duk_insert_undefined(thr, idx_func + 1);
call_flags = 0; /* not protected, respect reclimit, not constructor */
duk_handle_call_unprotected(thr, idx_func, call_flags);
}
DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) {
duk_small_uint_t call_flags;
duk_idx_t idx_func;
DUK_ASSERT_API_ENTRY(thr);
idx_func = duk__call_get_idx_func(thr, nargs, 2);
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
call_flags = 0; /* not protected, respect reclimit, not constructor */
duk_handle_call_unprotected(thr, idx_func, call_flags);
}
DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
/*
* XXX: if duk_handle_call() took values through indices, this could be
* made much more sensible. However, duk_handle_call() needs to fudge
* the 'this' and 'func' values to handle bound functions, which is now
* done "in-place", so this is not a trivial change.
*/
DUK_ASSERT_API_ENTRY(thr);
obj_idx = duk_require_normalize_index(thr, obj_idx); /* make absolute */
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
DUK_WO_NORETURN(return;);
}
duk__call_prop_prep_stack(thr, obj_idx, nargs);
duk_call_method(thr, nargs);
}
DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) {
duk__pcall_args *args;
duk_idx_t idx_func;
duk_int_t ret;
DUK_CTX_ASSERT_VALID(thr);
DUK_ASSERT(udata != NULL);
args = (duk__pcall_args *) udata;
idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1);
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
duk_insert_undefined(thr, idx_func + 1);
ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
DUK_ASSERT(ret == 0);
DUK_UNREF(ret);
return 1;
}
DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) {
duk__pcall_args args;
DUK_ASSERT_API_ENTRY(thr);
args.nargs = nargs;
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
args.call_flags = 0;
return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
}
DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) {
duk__pcall_method_args *args;
duk_idx_t idx_func;
duk_int_t ret;
DUK_CTX_ASSERT_VALID(thr);
DUK_ASSERT(udata != NULL);
args = (duk__pcall_method_args *) udata;
idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2);
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
DUK_ASSERT(ret == 0);
DUK_UNREF(ret);
return 1;
}
DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) {
duk__pcall_method_args args;
DUK_ASSERT_API_ENTRY(thr);
args.nargs = nargs;
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
args.call_flags = call_flags;
return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/);
}
DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) {
DUK_ASSERT_API_ENTRY(thr);
return duk_pcall_method_flags(thr, nargs, 0);
}
DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) {
duk__pcall_prop_args *args;
duk_idx_t obj_idx;
duk_int_t ret;
DUK_CTX_ASSERT_VALID(thr);
DUK_ASSERT(udata != NULL);
args = (duk__pcall_prop_args *) udata;
obj_idx = duk_require_normalize_index(thr, args->obj_idx); /* make absolute */
duk__call_prop_prep_stack(thr, obj_idx, args->nargs);
ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags);
DUK_ASSERT(ret == 0);
DUK_UNREF(ret);
return 1;
}
DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
duk__pcall_prop_args args;
DUK_ASSERT_API_ENTRY(thr);
args.obj_idx = obj_idx;
args.nargs = nargs;
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
args.call_flags = 0;
return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
}
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) {
duk_int_t rc;
DUK_ASSERT_API_ENTRY(thr);
/* nargs condition; fail if: top - bottom < nargs
* <=> top < bottom + nargs
* nrets condition; fail if: end - (top - nargs) < nrets
* <=> end - top + nargs < nrets
* <=> end + nargs < top + nrets
*/
/* XXX: check for any reserve? */
if (DUK_UNLIKELY((nargs | nrets) < 0 || /* nargs < 0 || nrets < 0; OR sign bits */
thr->valstack_top < thr->valstack_bottom + nargs || /* nargs too large compared to top */
thr->valstack_end + nargs < thr->valstack_top + nrets)) { /* nrets too large compared to reserve */
DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: "
"nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), "
"end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)",
(long) nargs,
(long) nrets,
(long) (thr->valstack_top - thr->valstack),
(long) (thr->valstack_bottom - thr->valstack),
(long) nargs,
(long) (thr->valstack_end - thr->valstack),
(long) nargs,
(long) (thr->valstack_top - thr->valstack),
(long) nrets));
DUK_ERROR_TYPE_INVALID_ARGS(thr);
DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
rc = duk_handle_safe_call(thr, /* thread */
func, /* func */
udata, /* udata */
nargs, /* num_stack_args */
nrets); /* num_stack_res */
return rc;
}
DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) {
duk_idx_t idx_func;
DUK_ASSERT_API_ENTRY(thr);
idx_func = duk__call_get_idx_func(thr, nargs, 1);
DUK_ASSERT(duk_is_valid_index(thr, idx_func));
duk_push_object(thr); /* default instance; internal proto updated by call handling */
duk_insert(thr, idx_func + 1);
duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT);
}
DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) {
duk_idx_t nargs;
DUK_ASSERT(udata != NULL);
nargs = *((duk_idx_t *) udata);
duk_new(thr, nargs);
return 1;
}
DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) {
duk_int_t rc;
DUK_ASSERT_API_ENTRY(thr);
/* For now, just use duk_safe_call() to wrap duk_new(). We can't
* simply use a protected duk_handle_call() because pushing the
* default instance might throw.
*/
if (DUK_UNLIKELY(nargs < 0)) {
DUK_ERROR_TYPE_INVALID_ARGS(thr);
DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
}
rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
return rc;
}
DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) {
duk_activation *act;
DUK_ASSERT_API_ENTRY(thr);
act = thr->callstack_curr;
if (act != NULL) {
return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
}
return 0;
}
DUK_EXTERNAL void duk_require_constructor_call(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
if (!duk_is_constructor_call(thr)) {
DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY);
DUK_WO_NORETURN(return;);
}
}
DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) {
duk_activation *act;
/* For user code this could just return 1 (strict) always
* because all Duktape/C functions are considered strict,
* and strict is also the default when nothing is running.
* However, Duktape may call this function internally when
* the current activation is an ECMAScript function, so
* this cannot be replaced by a 'return 1' without fixing
* the internal call sites.
*/
DUK_ASSERT_API_ENTRY(thr);
act = thr->callstack_curr;
if (act != NULL) {
return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
} else {
/* Strict by default. */
return 1;
}
}
/*
* Duktape/C function magic
*/
DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) {
duk_activation *act;
duk_hobject *func;
DUK_ASSERT_API_ENTRY(thr);
act = thr->callstack_curr;
if (act) {
func = DUK_ACT_GET_FUNC(act);
if (!func) {
duk_tval *tv = &act->tv_func;
duk_small_uint_t lf_flags;
lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
}
DUK_ASSERT(func != NULL);
if (DUK_HOBJECT_IS_NATFUNC(func)) {
duk_hnatfunc *nf = (duk_hnatfunc *) func;
return (duk_int_t) nf->magic;
}
}
return 0;
}
DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_hobject *h;
DUK_ASSERT_API_ENTRY(thr);
tv = duk_require_tval(thr, idx);
if (DUK_TVAL_IS_OBJECT(tv)) {
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
if (!DUK_HOBJECT_HAS_NATFUNC(h)) {
goto type_error;
}
return (duk_int_t) ((duk_hnatfunc *) h)->magic;
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
}
/* fall through */
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
DUK_WO_NORETURN(return 0;);
}
DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) {
duk_hnatfunc *nf;
DUK_ASSERT_API_ENTRY(thr);
nf = duk_require_hnatfunc(thr, idx);
DUK_ASSERT(nf != NULL);
nf->magic = (duk_int16_t) magic;
}
/*
* Misc helpers
*/
/* Resolve a bound function on value stack top to a non-bound target
* (leave other values as is).
*/
DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
duk_tval *tv;
DUK_HTHREAD_ASSERT_VALID(thr);
tv = DUK_GET_TVAL_NEGIDX(thr, -1);
if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h;
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
duk_push_tval(thr, &((duk_hboundfunc *) (void *) h)->target);
duk_replace(thr, -2);
#if 0
DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
DUK_TVAL_INCREF(thr, tv);
DUK_HOBJECT_DECREF_NORZ(thr, h);
#endif
/* Rely on Function.prototype.bind() on never creating a bound
* function whose target is not proper. This is now safe
* because the target is not even an internal property but a
* struct member.
*/
DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1));
}
}
/* Lightfuncs cannot be bound but are always callable and
* constructable.
*/
}

View file

@ -1,926 +0,0 @@
/*
* Encoding and decoding basic formats: hex, base64.
*
* These are in-place operations which may allow an optimized implementation.
*
* Base-64: https://tools.ietf.org/html/rfc4648#section-4
*/
#include "third_party/duktape/duk_internal.h"
/*
* Misc helpers
*/
/* Shared handling for encode/decode argument. Fast path handling for
* buffer and string values because they're the most common. In particular,
* avoid creating a temporary string or buffer when possible. Return value
* is guaranteed to be non-NULL, even for zero length input.
*/
DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
const void *def_ptr = (const void *) out_len; /* Any non-NULL pointer will do. */
const void *ptr;
duk_bool_t isbuffer;
DUK_ASSERT(out_len != NULL);
DUK_ASSERT(def_ptr != NULL);
DUK_ASSERT(duk_is_valid_index(thr, idx)); /* checked by caller */
ptr = (const void *) duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer);
if (isbuffer) {
DUK_ASSERT(ptr != NULL || *out_len == 0U);
if (DUK_UNLIKELY(ptr == NULL)) {
ptr = def_ptr;
}
DUK_ASSERT(ptr != NULL);
} else {
/* For strings a non-NULL pointer is always guaranteed because
* at least a NUL will be present.
*/
ptr = (const void *) duk_to_lstring(thr, idx, out_len);
DUK_ASSERT(ptr != NULL);
}
DUK_ASSERT(ptr != NULL);
return (const duk_uint8_t *) ptr;
}
/*
* Base64
*/
#if defined(DUK_USE_BASE64_SUPPORT)
/* Bytes emitted for number of padding characters in range [0,4]. */
DUK_LOCAL const duk_int8_t duk__base64_decode_nequal_step[5] = {
3, /* #### -> 24 bits, emit 3 bytes */
2, /* ###= -> 18 bits, emit 2 bytes */
1, /* ##== -> 12 bits, emit 1 byte */
-1, /* #=== -> 6 bits, error */
0, /* ==== -> 0 bits, emit 0 bytes */
};
#if defined(DUK_USE_BASE64_FASTPATH)
DUK_LOCAL const duk_uint8_t duk__base64_enctab_fast[64] = {
0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U, /* A...P */
0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, 0x59U, 0x5aU, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U, /* Q...f */
0x67U, 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU, 0x6fU, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U, /* g...v */
0x77U, 0x78U, 0x79U, 0x7aU, 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x2bU, 0x2fU /* w.../ */
};
#endif /* DUK_USE_BASE64_FASTPATH */
#if defined(DUK_USE_BASE64_FASTPATH)
/* Decode table for one byte of input:
* -1 = allowed whitespace
* -2 = padding
* -3 = error
* 0...63 decoded bytes
*/
DUK_LOCAL const duk_int8_t duk__base64_dectab_fast[256] = {
-3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3, /* 0x00...0x0f */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x10...0x1f */
-1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 62, -3, -3, -3, 63, /* 0x20...0x2f */
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -3, -3, -3, -2, -3, -3, /* 0x30...0x3f */
-3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -3, -3, -3, -3, -3, /* 0x50...0x5f */
-3, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -3, -3, -3, -3, -3, /* 0x70...0x7f */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x80...0x8f */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0x90...0x9f */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xa0...0xaf */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xb0...0xbf */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xc0...0xcf */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xd0...0xdf */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /* 0xe0...0xef */
-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3 /* 0xf0...0xff */
};
#endif /* DUK_USE_BASE64_FASTPATH */
#if defined(DUK_USE_BASE64_FASTPATH)
DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_3(const duk_uint8_t *src, duk_uint8_t *dst) {
duk_uint_t t;
t = (duk_uint_t) src[0];
t = (t << 8) + (duk_uint_t) src[1];
t = (t << 8) + (duk_uint_t) src[2];
dst[0] = duk__base64_enctab_fast[t >> 18];
dst[1] = duk__base64_enctab_fast[(t >> 12) & 0x3fU];
dst[2] = duk__base64_enctab_fast[(t >> 6) & 0x3fU];
dst[3] = duk__base64_enctab_fast[t & 0x3fU];
#if 0
/* Tested: not faster on x64, most likely due to aliasing between
* output and input index computation.
*/
/* aaaaaabb bbbbcccc ccdddddd */
dst[0] = duk__base64_enctab_fast[(src[0] >> 2) & 0x3fU];
dst[1] = duk__base64_enctab_fast[((src[0] << 4) & 0x30U) | ((src[1] >> 4) & 0x0fU)];
dst[2] = duk__base64_enctab_fast[((src[1] << 2) & 0x3fU) | ((src[2] >> 6) & 0x03U)];
dst[3] = duk__base64_enctab_fast[src[2] & 0x3fU];
#endif
}
DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_2(const duk_uint8_t *src, duk_uint8_t *dst) {
duk_uint_t t;
t = (duk_uint_t) src[0];
t = (t << 8) + (duk_uint_t) src[1];
dst[0] = duk__base64_enctab_fast[t >> 10]; /* XXXXXX-- -------- */
dst[1] = duk__base64_enctab_fast[(t >> 4) & 0x3fU]; /* ------XX XXXX---- */
dst[2] = duk__base64_enctab_fast[(t << 2) & 0x3fU]; /* -------- ----XXXX */
dst[3] = DUK_ASC_EQUALS;
}
DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_1(const duk_uint8_t *src, duk_uint8_t *dst) {
duk_uint_t t;
t = (duk_uint_t) src[0];
dst[0] = duk__base64_enctab_fast[t >> 2]; /* XXXXXX-- */
dst[1] = duk__base64_enctab_fast[(t << 4) & 0x3fU]; /* ------XX */
dst[2] = DUK_ASC_EQUALS;
dst[3] = DUK_ASC_EQUALS;
}
DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
duk_size_t n;
const duk_uint8_t *p;
duk_uint8_t *q;
n = srclen;
p = src;
q = dst;
if (n >= 16U) {
/* Fast path, unrolled by 4, allows interleaving. Process
* 12-byte input chunks which encode to 16-char output chunks.
* Only enter when at least one block is emitted (avoids div+mul
* for short inputs too).
*/
const duk_uint8_t *p_end_fast;
p_end_fast = p + ((n / 12U) * 12U);
DUK_ASSERT(p_end_fast >= p + 12);
do {
duk__base64_encode_fast_3(p, q);
duk__base64_encode_fast_3(p + 3, q + 4);
duk__base64_encode_fast_3(p + 6, q + 8);
duk__base64_encode_fast_3(p + 9, q + 12);
p += 12;
q += 16;
} while (DUK_LIKELY(p != p_end_fast));
DUK_ASSERT(src + srclen >= p);
n = (duk_size_t) (src + srclen - p);
DUK_ASSERT(n < 12U);
}
/* Remainder. */
while (n >= 3U) {
duk__base64_encode_fast_3(p, q);
p += 3;
q += 4;
n -= 3U;
}
DUK_ASSERT(n == 0U || n == 1U || n == 2U);
if (n == 1U) {
duk__base64_encode_fast_1(p, q);
#if 0 /* Unnecessary. */
p += 1;
q += 4;
n -= 1U;
#endif
} else if (n == 2U) {
duk__base64_encode_fast_2(p, q);
#if 0 /* Unnecessary. */
p += 2;
q += 4;
n -= 2U;
#endif
} else {
DUK_ASSERT(n == 0U); /* nothing to do */
;
}
}
#else /* DUK_USE_BASE64_FASTPATH */
DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
duk_small_uint_t i, npad;
duk_uint_t t, x, y;
const duk_uint8_t *p;
const duk_uint8_t *p_end;
duk_uint8_t *q;
p = src;
p_end = src + srclen;
q = dst;
npad = 0U;
while (p < p_end) {
/* Read 3 bytes into 't', padded by zero. */
t = 0;
for (i = 0; i < 3; i++) {
t = t << 8;
if (p < p_end) {
t += (duk_uint_t) (*p++);
} else {
/* This only happens on the last loop and we're
* guaranteed to exit on the next loop.
*/
npad++;
}
}
DUK_ASSERT(npad <= 2U);
/* Emit 4 encoded characters. If npad > 0, some of the
* chars will be incorrect (zero bits) but we fix up the
* padding after the loop. A straightforward 64-byte
* lookup would be faster and cleaner, but this is shorter.
*/
for (i = 0; i < 4; i++) {
x = ((t >> 18) & 0x3fU);
t = t << 6;
if (x <= 51U) {
if (x <= 25) {
y = x + DUK_ASC_UC_A;
} else {
y = x - 26 + DUK_ASC_LC_A;
}
} else {
if (x <= 61U) {
y = x - 52 + DUK_ASC_0;
} else if (x == 62) {
y = DUK_ASC_PLUS;
} else {
DUK_ASSERT(x == 63);
y = DUK_ASC_SLASH;
}
}
*q++ = (duk_uint8_t) y;
}
}
/* Handle padding by rewriting 0-2 bogus characters at the end.
*
* Missing bytes npad base64 example
* 0 0 ####
* 1 1 ###=
* 2 2 ##==
*/
DUK_ASSERT(npad <= 2U);
while (npad > 0U) {
*(q - npad) = DUK_ASC_EQUALS;
npad--;
}
}
#endif /* DUK_USE_BASE64_FASTPATH */
#if defined(DUK_USE_BASE64_FASTPATH)
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) {
duk_int_t x;
duk_uint_t t;
duk_small_uint_t n_equal;
duk_int8_t step;
const duk_uint8_t *p;
const duk_uint8_t *p_end;
const duk_uint8_t *p_end_safe;
duk_uint8_t *q;
DUK_ASSERT(src != NULL); /* Required by pointer arithmetic below, which fails for NULL. */
p = src;
p_end = src + srclen;
p_end_safe = p_end - 8; /* If 'src <= src_end_safe', safe to read 8 bytes. */
q = dst;
/* Alternate between a fast path which processes clean groups with no
* padding or whitespace, and a slow path which processes one arbitrary
* group and then re-enters the fast path. This handles e.g. base64
* with newlines reasonably well because the majority of a line is in
* the fast path.
*/
for (;;) {
/* Fast path, on each loop handle two 4-char input groups.
* If both are clean, emit 6 bytes and continue. If first
* is clean, emit 3 bytes and drop out; otherwise emit
* nothing and drop out. This approach could be extended to
* more groups per loop, but for inputs with e.g. periodic
* newlines (which are common) it might not be an improvement.
*/
while (DUK_LIKELY(p <= p_end_safe)) {
duk_int_t t1, t2;
/* The lookup byte is intentionally sign extended to
* (at least) 32 bits and then ORed. This ensures
* that is at least 1 byte is negative, the highest
* bit of the accumulator will be set at the end and
* we don't need to check every byte.
*
* Read all input bytes first before writing output
* bytes to minimize aliasing.
*/
DUK_DDD(DUK_DDDPRINT("fast loop: p=%p, p_end_safe=%p, p_end=%p",
(const void *) p, (const void *) p_end_safe, (const void *) p_end));
t1 = (duk_int_t) duk__base64_dectab_fast[p[0]];
t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[1]];
t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[2]];
t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[3]];
t2 = (duk_int_t) duk__base64_dectab_fast[p[4]];
t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[5]];
t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[6]];
t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[7]];
q[0] = (duk_uint8_t) (((duk_uint_t) t1 >> 16) & 0xffU);
q[1] = (duk_uint8_t) (((duk_uint_t) t1 >> 8) & 0xffU);
q[2] = (duk_uint8_t) ((duk_uint_t) t1 & 0xffU);
q[3] = (duk_uint8_t) (((duk_uint_t) t2 >> 16) & 0xffU);
q[4] = (duk_uint8_t) (((duk_uint_t) t2 >> 8) & 0xffU);
q[5] = (duk_uint8_t) ((duk_uint_t) t2 & 0xffU);
/* Optimistic check using one branch. */
if (DUK_LIKELY((t1 | t2) >= 0)) {
p += 8;
q += 6;
} else if (t1 >= 0) {
DUK_DDD(DUK_DDDPRINT("fast loop first group was clean, second was not, process one slow path group"));
DUK_ASSERT(t2 < 0);
p += 4;
q += 3;
break;
} else {
DUK_DDD(DUK_DDDPRINT("fast loop first group was not clean, second does not matter, process one slow path group"));
DUK_ASSERT(t1 < 0);
break;
}
} /* fast path */
/* Slow path step 1: try to scan a 4-character encoded group,
* end-of-input, or start-of-padding. We exit with:
* 1. n_chars == 4: full group, no padding, no end-of-input.
* 2. n_chars < 4: partial group (may also be 0), encountered
* padding or end of input.
*
* The accumulator is initialized to 1; this allows us to detect
* a full group by comparing >= 0x1000000 without an extra
* counter variable.
*/
t = 1UL;
for (;;) {
DUK_DDD(DUK_DDDPRINT("slow loop: p=%p, p_end=%p, t=%lu",
(const void *) p, (const void *) p_end, (unsigned long) t));
if (DUK_LIKELY(p < p_end)) {
x = duk__base64_dectab_fast[*p++];
if (DUK_LIKELY(x >= 0)) {
DUK_ASSERT(x >= 0 && x <= 63);
t = (t << 6) + (duk_uint_t) x;
if (t >= 0x1000000UL) {
break;
}
} else if (x == -1) {
continue; /* allowed ascii whitespace */
} else if (x == -2) {
p--;
break; /* start of padding */
} else {
DUK_ASSERT(x == -3);
goto decode_error;
}
} else {
break; /* end of input */
}
} /* slow path step 1 */
/* Complete the padding by simulating pad characters,
* regardless of actual input padding chars.
*/
n_equal = 0;
while (t < 0x1000000UL) {
t = (t << 6) + 0U;
n_equal++;
}
/* Slow path step 2: deal with full/partial group, padding,
* etc. Note that for num chars in [0,3] we intentionally emit
* 3 bytes but don't step forward that much, buffer space is
* guaranteed in setup.
*
* num chars:
* 0 #### no output (= step 0)
* 1 #=== reject, 6 bits of data
* 2 ##== 12 bits of data, output 1 byte (= step 1)
* 3 ###= 18 bits of data, output 2 bytes (= step 2)
* 4 #### 24 bits of data, output 3 bytes (= step 3)
*/
q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
q[2] = (duk_uint8_t) (t & 0xffU);
DUK_ASSERT(n_equal <= 4);
step = duk__base64_decode_nequal_step[n_equal];
if (DUK_UNLIKELY(step < 0)) {
goto decode_error;
}
q += step;
/* Slow path step 3: read and ignore padding and whitespace
* until (a) next non-padding and non-whitespace character
* after which we resume the fast path, or (b) end of input.
* This allows us to accept missing, partial, full, and extra
* padding cases uniformly. We also support concatenated
* base-64 documents because we resume scanning afterwards.
*
* Note that to support concatenated documents well, the '='
* padding found inside the input must also allow for 'extra'
* padding. For example, 'Zm===' decodes to 'f' and has one
* extra padding char. So, 'Zm===Zm' should decode 'ff', even
* though the standard break-up would be 'Zm==' + '=Zm' which
* doesn't make sense.
*
* We also accept prepended padding like '==Zm9', because it
* is equivalent to an empty document with extra padding ('==')
* followed by a valid document.
*/
for (;;) {
if (DUK_UNLIKELY(p >= p_end)) {
goto done;
}
x = duk__base64_dectab_fast[*p++];
if (x == -1 || x == -2) {
; /* padding or whitespace, keep eating */
} else {
p--;
break; /* backtrack and go back to fast path, even for -1 */
}
} /* slow path step 3 */
} /* outer fast+slow path loop */
done:
DUK_DDD(DUK_DDDPRINT("done; p=%p, p_end=%p",
(const void *) p, (const void *) p_end));
DUK_ASSERT(p == p_end);
*out_dst_final = q;
return 1;
decode_error:
return 0;
}
#else /* DUK_USE_BASE64_FASTPATH */
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) {
duk_uint_t t, x;
duk_int_t y;
duk_int8_t step;
const duk_uint8_t *p;
const duk_uint8_t *p_end;
duk_uint8_t *q;
/* 0x09, 0x0a, or 0x0d */
duk_uint32_t mask_white = (1U << 9) | (1U << 10) | (1U << 13);
/* 't' tracks progress of the decoded group:
*
* t == 1 no valid chars yet
* t >= 0x40 1x6 = 6 bits shifted in
* t >= 0x1000 2x6 = 12 bits shifted in
* t >= 0x40000 3x6 = 18 bits shifted in
* t >= 0x1000000 4x6 = 24 bits shifted in
*
* By initializing t=1 there's no need for a separate counter for
* the number of characters found so far.
*/
p = src;
p_end = src + srclen;
q = dst;
t = 1UL;
for (;;) {
duk_small_uint_t n_equal;
DUK_ASSERT(t >= 1U);
if (p >= p_end) {
/* End of input: if input exists, treat like
* start of padding, finish the block, then
* re-enter here to see we're done.
*/
if (t == 1U) {
break;
} else {
goto simulate_padding;
}
}
x = *p++;
if (x >= 0x41U) {
/* Valid: a-z and A-Z. */
DUK_ASSERT(x >= 0x41U && x <= 0xffU);
if (x >= 0x61U && x <= 0x7aU) {
y = (duk_int_t) x - 0x61 + 26;
} else if (x <= 0x5aU) {
y = (duk_int_t) x - 0x41;
} else {
goto decode_error;
}
} else if (x >= 0x30U) {
/* Valid: 0-9 and =. */
DUK_ASSERT(x >= 0x30U && x <= 0x40U);
if (x <= 0x39U) {
y = (duk_int_t) x - 0x30 + 52;
} else if (x == 0x3dU) {
/* Skip padding and whitespace unless we're in the
* middle of a block. Otherwise complete group by
* simulating shifting in the correct padding.
*/
if (t == 1U) {
continue;
}
goto simulate_padding;
} else {
goto decode_error;
}
} else if (x >= 0x20U) {
/* Valid: +, /, and 0x20 whitespace. */
DUK_ASSERT(x >= 0x20U && x <= 0x2fU);
if (x == 0x2bU) {
y = 62;
} else if (x == 0x2fU) {
y = 63;
} else if (x == 0x20U) {
continue;
} else {
goto decode_error;
}
} else {
/* Valid: whitespace. */
duk_uint32_t m;
DUK_ASSERT(x < 0x20U); /* 0x00 to 0x1f */
m = (1U << x);
if (mask_white & m) {
/* Allow basic ASCII whitespace. */
continue;
} else {
goto decode_error;
}
}
DUK_ASSERT(y >= 0 && y <= 63);
t = (t << 6) + (duk_uint_t) y;
if (t < 0x1000000UL) {
continue;
}
/* fall through; no padding will be added */
simulate_padding:
n_equal = 0;
while (t < 0x1000000UL) {
t = (t << 6) + 0U;
n_equal++;
}
/* Output 3 bytes from 't' and advance as needed. */
q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
q[2] = (duk_uint8_t) (t & 0xffU);
DUK_ASSERT(n_equal <= 4U);
step = duk__base64_decode_nequal_step[n_equal];
if (step < 0) {
goto decode_error;
}
q += step;
/* Re-enter loop. The actual padding characters are skipped
* by the main loop. This handles cases like missing, partial,
* full, and extra padding, and allows parsing of concatenated
* documents (with extra padding) like: Zm===Zm. Also extra
* prepended padding is accepted: ===Zm9v.
*/
t = 1U;
}
DUK_ASSERT(t == 1UL);
*out_dst_final = q;
return 1;
decode_error:
return 0;
}
#endif /* DUK_USE_BASE64_FASTPATH */
DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
duk_uint8_t *dst;
const char *ret;
DUK_ASSERT_API_ENTRY(thr);
idx = duk_require_normalize_index(thr, idx);
src = duk__prep_codec_arg(thr, idx, &srclen);
DUK_ASSERT(src != NULL);
/* Compute exact output length. Computation must not wrap; this
* limit works for 32-bit size_t:
* >>> srclen = 3221225469
* >>> '%x' % ((srclen + 2) / 3 * 4)
* 'fffffffc'
*/
if (srclen > 3221225469UL) {
goto type_error;
}
dstlen = (srclen + 2U) / 3U * 4U;
dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen);
duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
duk_replace(thr, idx);
return ret;
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED);
DUK_WO_NORETURN(return NULL;);
}
DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *src;
duk_size_t srclen;
duk_size_t dstlen;
duk_uint8_t *dst;
duk_uint8_t *dst_final;
DUK_ASSERT_API_ENTRY(thr);
idx = duk_require_normalize_index(thr, idx);
src = duk__prep_codec_arg(thr, idx, &srclen);
DUK_ASSERT(src != NULL);
/* Round up and add safety margin. Avoid addition before division to
* avoid possibility of wrapping. Margin includes +3 for rounding up,
* and +3 for one extra group: the decoder may emit and then backtrack
* a full group (3 bytes) from zero-sized input for technical reasons.
* Similarly, 'xx' may ecause 1+3 = bytes to be emitted and then
* backtracked.
*/
dstlen = (srclen / 4) * 3 + 6; /* upper limit, assuming no whitespace etc */
dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen);
/* Note: for dstlen=0, dst may be NULL */
if (!duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final)) {
goto type_error;
}
/* XXX: convert to fixed buffer? */
(void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst));
duk_replace(thr, idx);
return;
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED);
DUK_WO_NORETURN(return;);
}
#else /* DUK_USE_BASE64_SUPPORT */
DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return NULL;);
}
DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_BASE64_SUPPORT */
/*
* Hex
*/
#if defined(DUK_USE_HEX_SUPPORT)
DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
duk_uint8_t *buf;
const char *ret;
#if defined(DUK_USE_HEX_FASTPATH)
duk_size_t len_safe;
duk_uint16_t *p16;
#endif
DUK_ASSERT_API_ENTRY(thr);
idx = duk_require_normalize_index(thr, idx);
inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL);
/* Fixed buffer, no zeroing because we'll fill all the data. */
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */
p16 = (duk_uint16_t *) (void *) buf;
len_safe = len & ~0x03U;
for (i = 0; i < len_safe; i += 4) {
p16[0] = duk_hex_enctab[inp[i]];
p16[1] = duk_hex_enctab[inp[i + 1]];
p16[2] = duk_hex_enctab[inp[i + 2]];
p16[3] = duk_hex_enctab[inp[i + 3]];
p16 += 4;
}
for (; i < len; i++) {
*p16++ = duk_hex_enctab[inp[i]];
}
#else /* DUK_USE_HEX_FASTPATH */
for (i = 0; i < len; i++) {
duk_small_uint_t t;
t = (duk_small_uint_t) inp[i];
buf[i*2 + 0] = duk_lc_digits[t >> 4];
buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
}
#endif /* DUK_USE_HEX_FASTPATH */
/* XXX: Using a string return value forces a string intern which is
* not always necessary. As a rough performance measure, hex encode
* time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s
* without string coercion. Change to returning a buffer and let the
* caller coerce to string if necessary?
*/
ret = duk_buffer_to_string(thr, -1); /* Safe, result is ASCII. */
duk_replace(thr, idx);
return ret;
}
DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
const duk_uint8_t *inp;
duk_size_t len;
duk_size_t i;
duk_int_t t;
duk_uint8_t *buf;
#if defined(DUK_USE_HEX_FASTPATH)
duk_int_t chk;
duk_uint8_t *p;
duk_size_t len_safe;
#endif
DUK_ASSERT_API_ENTRY(thr);
idx = duk_require_normalize_index(thr, idx);
inp = duk__prep_codec_arg(thr, idx, &len);
DUK_ASSERT(inp != NULL);
if (len & 0x01) {
goto type_error;
}
/* Fixed buffer, no zeroing because we'll fill all the data. */
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2);
DUK_ASSERT(buf != NULL);
#if defined(DUK_USE_HEX_FASTPATH)
p = buf;
len_safe = len & ~0x07U;
for (i = 0; i < len_safe; i += 8) {
t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
((duk_int_t) duk_hex_dectab[inp[i + 1]]);
chk = t;
p[0] = (duk_uint8_t) t;
t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
((duk_int_t) duk_hex_dectab[inp[i + 3]]);
chk |= t;
p[1] = (duk_uint8_t) t;
t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
((duk_int_t) duk_hex_dectab[inp[i + 5]]);
chk |= t;
p[2] = (duk_uint8_t) t;
t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
((duk_int_t) duk_hex_dectab[inp[i + 7]]);
chk |= t;
p[3] = (duk_uint8_t) t;
p += 4;
/* Check if any lookup above had a negative result. */
if (DUK_UNLIKELY(chk < 0)) {
goto type_error;
}
}
for (; i < len; i += 2) {
/* First cast to duk_int_t to sign extend, second cast to
* duk_uint_t to avoid signed left shift, and final cast to
* duk_int_t result type.
*/
t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
if (DUK_UNLIKELY(t < 0)) {
goto type_error;
}
*p++ = (duk_uint8_t) t;
}
#else /* DUK_USE_HEX_FASTPATH */
for (i = 0; i < len; i += 2) {
/* For invalid characters the value -1 gets extended to
* at least 16 bits. If either nybble is invalid, the
* resulting 't' will be < 0.
*/
t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
if (DUK_UNLIKELY(t < 0)) {
goto type_error;
}
buf[i >> 1] = (duk_uint8_t) t;
}
#endif /* DUK_USE_HEX_FASTPATH */
duk_replace(thr, idx);
return;
type_error:
DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED);
DUK_WO_NORETURN(return;);
}
#else /* DUK_USE_HEX_SUPPORT */
DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return NULL;);
}
DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_HEX_SUPPORT */
/*
* JSON
*/
#if defined(DUK_USE_JSON_SUPPORT)
DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
const char *ret;
DUK_ASSERT_API_ENTRY(thr);
#if defined(DUK_USE_ASSERTIONS)
top_at_entry = duk_get_top(thr);
#endif
idx = duk_require_normalize_index(thr, idx);
duk_bi_json_stringify_helper(thr,
idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_replacer*/,
DUK_INVALID_INDEX /*idx_space*/,
0 /*flags*/);
DUK_ASSERT(duk_is_string(thr, -1));
duk_replace(thr, idx);
ret = duk_get_string(thr, idx);
DUK_ASSERT(duk_get_top(thr) == top_at_entry);
return ret;
}
DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t top_at_entry;
#endif
DUK_ASSERT_API_ENTRY(thr);
#if defined(DUK_USE_ASSERTIONS)
top_at_entry = duk_get_top(thr);
#endif
idx = duk_require_normalize_index(thr, idx);
duk_bi_json_parse_helper(thr,
idx /*idx_value*/,
DUK_INVALID_INDEX /*idx_reviver*/,
0 /*flags*/);
duk_replace(thr, idx);
DUK_ASSERT(duk_get_top(thr) == top_at_entry);
}
#else /* DUK_USE_JSON_SUPPORT */
DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return NULL;);
}
DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(idx);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_JSON_SUPPORT */

View file

@ -1,172 +0,0 @@
/*
* Compilation and evaluation
*/
#include "third_party/duktape/duk_internal.h"
typedef struct duk__compile_raw_args duk__compile_raw_args;
struct duk__compile_raw_args {
duk_size_t src_length; /* should be first on 64-bit platforms */
const duk_uint8_t *src_buffer;
duk_uint_t flags;
};
/* Eval is just a wrapper now. */
DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk_int_t rc;
DUK_ASSERT_API_ENTRY(thr);
/* Note: strictness is *not* inherited from the current Duktape/C.
* This would be confusing because the current strictness state
* depends on whether we're running inside a Duktape/C activation
* (= strict mode) or outside of any activation (= non-strict mode).
* See tests/api/test-eval-strictness.c for more discussion.
*/
/* [ ... source? filename? ] (depends on flags) */
rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */
/* [ ... closure/error ] */
if (rc != DUK_EXEC_SUCCESS) {
rc = DUK_EXEC_ERROR;
goto got_rc;
}
duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */
if (flags & DUK_COMPILE_SAFE) {
rc = duk_pcall_method(thr, 0);
} else {
duk_call_method(thr, 0);
rc = DUK_EXEC_SUCCESS;
}
/* [ ... result/error ] */
got_rc:
if (flags & DUK_COMPILE_NORESULT) {
duk_pop(thr);
}
return rc;
}
/* Helper which can be called both directly and with duk_safe_call(). */
DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
duk__compile_raw_args *comp_args;
duk_uint_t flags;
duk_hcompfunc *h_templ;
DUK_CTX_ASSERT_VALID(thr);
DUK_ASSERT(udata != NULL);
/* Note: strictness is not inherited from the current Duktape/C
* context. Otherwise it would not be possible to compile
* non-strict code inside a Duktape/C activation (which is
* always strict now). See tests/api/test-eval-strictness.c
* for discussion.
*/
/* [ ... source? filename? ] (depends on flags) */
comp_args = (duk__compile_raw_args *) udata;
flags = comp_args->flags;
if (flags & DUK_COMPILE_NOFILENAME) {
/* Automatic filename: 'eval' or 'input'. */
duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
}
/* [ ... source? filename ] */
if (!comp_args->src_buffer) {
duk_hstring *h_sourcecode;
h_sourcecode = duk_get_hstring(thr, -2);
if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
(h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
DUK_WO_NORETURN(return 0;);
}
DUK_ASSERT(h_sourcecode != NULL);
comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
}
DUK_ASSERT(comp_args->src_buffer != NULL);
if (flags & DUK_COMPILE_FUNCTION) {
flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR;
}
/* [ ... source? filename ] */
duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags);
/* [ ... source? func_template ] */
if (flags & DUK_COMPILE_NOSOURCE) {
;
} else {
duk_remove_m2(thr);
}
/* [ ... func_template ] */
h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1);
duk_js_push_closure(thr,
h_templ,
thr->builtins[DUK_BIDX_GLOBAL_ENV],
thr->builtins[DUK_BIDX_GLOBAL_ENV],
1 /*add_auto_proto*/);
duk_remove_m2(thr); /* -> [ ... closure ] */
/* [ ... closure ] */
return 1;
}
DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk__compile_raw_args comp_args_alloc;
duk__compile_raw_args *comp_args = &comp_args_alloc;
DUK_ASSERT_API_ENTRY(thr);
if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
/* String length is computed here to avoid multiple evaluation
* of a macro argument in the calling side.
*/
src_length = DUK_STRLEN(src_buffer);
}
comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
comp_args->src_length = src_length;
comp_args->flags = flags;
/* [ ... source? filename? ] (depends on flags) */
if (flags & DUK_COMPILE_SAFE) {
duk_int_t rc;
duk_int_t nargs;
duk_int_t nrets = 1;
/* Arguments can be: [ source? filename? &comp_args] so that
* nargs is 1 to 3. Call site encodes the correct nargs count
* directly into flags.
*/
nargs = flags & 0x07;
DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets);
/* [ ... closure ] */
return rc;
}
(void) duk__do_compile(thr, (void *) comp_args);
/* [ ... closure ] */
return DUK_EXEC_SUCCESS;
}

View file

@ -1,261 +0,0 @@
/*
* Debugging related API calls
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_JSON_SUPPORT)
DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
duk_idx_t idx;
duk_idx_t top;
DUK_ASSERT_API_ENTRY(thr);
/* We don't duk_require_stack() here now, but rely on the caller having
* enough space.
*/
top = duk_get_top(thr);
duk_push_bare_array(thr);
for (idx = 0; idx < top; idx++) {
duk_dup(thr, idx);
duk_put_prop_index(thr, -2, (duk_uarridx_t) idx);
}
/* XXX: conversion errors should not propagate outwards.
* Perhaps values need to be coerced individually?
*/
duk_bi_json_stringify_helper(thr,
duk_get_top_index(thr), /*idx_value*/
DUK_INVALID_INDEX, /*idx_replacer*/
DUK_INVALID_INDEX, /*idx_space*/
DUK_JSON_FLAG_EXT_CUSTOM |
DUK_JSON_FLAG_ASCII_ONLY |
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
duk_push_sprintf(thr, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(thr, -1));
duk_replace(thr, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
duk_pop(thr);
DUK_ASSERT(duk_is_string(thr, -1));
}
#else /* DUK_USE_JSON_SUPPORT */
DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_JSON_SUPPORT */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
duk_debug_read_function read_cb,
duk_debug_write_function write_cb,
duk_debug_peek_function peek_cb,
duk_debug_read_flush_function read_flush_cb,
duk_debug_write_flush_function write_flush_cb,
duk_debug_request_function request_cb,
duk_debug_detached_function detached_cb,
void *udata) {
duk_heap *heap;
const char *str;
duk_size_t len;
/* XXX: should there be an error or an automatic detach if
* already attached?
*/
DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(read_cb != NULL);
DUK_ASSERT(write_cb != NULL);
/* Other callbacks are optional. */
heap = thr->heap;
heap->dbg_read_cb = read_cb;
heap->dbg_write_cb = write_cb;
heap->dbg_peek_cb = peek_cb;
heap->dbg_read_flush_cb = read_flush_cb;
heap->dbg_write_flush_cb = write_flush_cb;
heap->dbg_request_cb = request_cb;
heap->dbg_detached_cb = detached_cb;
heap->dbg_udata = udata;
heap->dbg_have_next_byte = 0;
/* Start in paused state. */
heap->dbg_processing = 0;
heap->dbg_state_dirty = 0;
heap->dbg_force_restart = 0;
heap->dbg_pause_flags = 0;
heap->dbg_pause_act = NULL;
heap->dbg_pause_startline = 0;
heap->dbg_exec_counter = 0;
heap->dbg_last_counter = 0;
heap->dbg_last_time = 0.0;
duk_debug_set_paused(heap); /* XXX: overlap with fields above */
/* Send version identification and flush right afterwards. Note that
* we must write raw, unframed bytes here.
*/
duk_push_sprintf(thr, "%ld %ld %s %s\n",
(long) DUK_DEBUG_PROTOCOL_VERSION,
(long) DUK_VERSION,
(const char *) DUK_GIT_DESCRIBE,
(const char *) DUK_USE_TARGET_INFO);
str = duk_get_lstring(thr, -1, &len);
DUK_ASSERT(str != NULL);
duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
duk_debug_write_flush(thr);
duk_pop(thr);
}
DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
/* Can be called multiple times with no harm. */
duk_debug_do_detach(thr->heap);
}
DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
duk_bool_t processed_messages;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
if (!duk_debug_is_attached(thr->heap)) {
return;
}
if (thr->callstack_curr != NULL || thr->heap->dbg_processing) {
/* Calling duk_debugger_cooperate() while Duktape is being
* called into is not supported. This is not a 100% check
* but prevents any damage in most cases.
*/
return;
}
processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
DUK_UNREF(processed_messages);
}
DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
duk_idx_t idx;
duk_bool_t ret = 0;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
top = duk_get_top(thr);
if (top < nvalues) {
DUK_ERROR_RANGE(thr, "not enough stack values for notify");
DUK_WO_NORETURN(return 0;);
}
if (duk_debug_is_attached(thr->heap)) {
duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
for (idx = top - nvalues; idx < top; idx++) {
duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx);
duk_debug_write_tval(thr, tv);
}
duk_debug_write_eom(thr);
/* Return non-zero (true) if we have a good reason to believe
* the notify was delivered; if we're still attached at least
* a transport error was not indicated by the transport write
* callback. This is not a 100% guarantee of course.
*/
if (duk_debug_is_attached(thr->heap)) {
ret = 1;
}
}
duk_pop_n(thr, nvalues);
return ret;
}
DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
/* Treat like a debugger statement: ignore when not attached. */
if (duk_debug_is_attached(thr->heap)) {
if (duk_debug_is_paused(thr->heap)) {
DUK_D(DUK_DPRINT("duk_debugger_pause() called when already paused; ignoring"));
} else {
duk_debug_set_paused(thr->heap);
/* Pause on the next opcode executed. This is always safe to do even
* inside the debugger message loop: the interrupt counter will be reset
* to its proper value when the message loop exits.
*/
thr->interrupt_init = 1;
thr->interrupt_counter = 0;
}
}
}
#else /* DUK_USE_DEBUGGER_SUPPORT */
DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
duk_debug_read_function read_cb,
duk_debug_write_function write_cb,
duk_debug_peek_function peek_cb,
duk_debug_read_flush_function read_flush_cb,
duk_debug_write_flush_function write_flush_cb,
duk_debug_request_function request_cb,
duk_debug_detached_function detached_cb,
void *udata) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(read_cb);
DUK_UNREF(write_cb);
DUK_UNREF(peek_cb);
DUK_UNREF(read_flush_cb);
DUK_UNREF(write_flush_cb);
DUK_UNREF(request_cb);
DUK_UNREF(detached_cb);
DUK_UNREF(udata);
DUK_ERROR_TYPE(thr, "no debugger support");
DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_ERROR_TYPE(thr, "no debugger support");
DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
/* nop */
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(thr);
}
DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
duk_idx_t top;
DUK_ASSERT_API_ENTRY(thr);
top = duk_get_top(thr);
if (top < nvalues) {
DUK_ERROR_RANGE_INVALID_COUNT(thr);
DUK_WO_NORETURN(return 0;);
}
/* No debugger support, just pop values. */
duk_pop_n(thr, nvalues);
return 0;
}
DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
/* Treat like debugger statement: nop */
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(thr);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */

View file

@ -1,205 +0,0 @@
/*
* Heap creation and destruction
*/
#include "third_party/duktape/duk_internal.h"
typedef struct duk_internal_thread_state duk_internal_thread_state;
struct duk_internal_thread_state {
duk_ljstate lj;
duk_bool_t creating_error;
duk_hthread *curr_thread;
duk_int_t call_recursion_depth;
};
DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func,
duk_realloc_function realloc_func,
duk_free_function free_func,
void *heap_udata,
duk_fatal_function fatal_handler) {
duk_heap *heap = NULL;
duk_hthread *thr;
/* Assume that either all memory funcs are NULL or non-NULL, mixed
* cases will now be unsafe.
*/
/* XXX: just assert non-NULL values here and make caller arguments
* do the defaulting to the default implementations (smaller code)?
*/
if (!alloc_func) {
DUK_ASSERT(realloc_func == NULL);
DUK_ASSERT(free_func == NULL);
#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
alloc_func = duk_default_alloc_function;
realloc_func = duk_default_realloc_function;
free_func = duk_default_free_function;
#else
DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
return NULL;
#endif
} else {
DUK_ASSERT(realloc_func != NULL);
DUK_ASSERT(free_func != NULL);
}
if (!fatal_handler) {
fatal_handler = duk_default_fatal_handler;
}
DUK_ASSERT(alloc_func != NULL);
DUK_ASSERT(realloc_func != NULL);
DUK_ASSERT(free_func != NULL);
DUK_ASSERT(fatal_handler != NULL);
heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
if (!heap) {
return NULL;
}
thr = heap->heap_thread;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
return thr;
}
DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) {
duk_heap *heap;
if (!thr) {
return;
}
DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
duk_heap_free(heap);
}
DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) {
duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
duk_heap *heap;
duk_ljstate *lj;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
/* Currently not supported when called from within a finalizer.
* If that is done, the finalizer will remain running indefinitely,
* preventing other finalizers from executing. The assert is a bit
* wider, checking that it would be OK to run pending finalizers.
*/
DUK_ASSERT(thr->heap->pf_prevent_count == 0);
/* Currently not supported to duk_suspend() from an errCreate()
* call.
*/
DUK_ASSERT(thr->heap->creating_error == 0);
heap = thr->heap;
lj = &heap->lj;
duk_push_tval(thr, &lj->value1);
duk_push_tval(thr, &lj->value2);
/* XXX: creating_error == 0 is asserted above, so no need to store. */
duk_memcpy((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
snapshot->creating_error = heap->creating_error;
snapshot->curr_thread = heap->curr_thread;
snapshot->call_recursion_depth = heap->call_recursion_depth;
lj->jmpbuf_ptr = NULL;
lj->type = DUK_LJ_TYPE_UNKNOWN;
DUK_TVAL_SET_UNDEFINED(&lj->value1);
DUK_TVAL_SET_UNDEFINED(&lj->value2);
heap->creating_error = 0;
heap->curr_thread = NULL;
heap->call_recursion_depth = 0;
}
DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
duk_heap *heap;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(state != NULL); /* unvalidated */
/* Shouldn't be necessary if duk_suspend() is called before
* duk_resume(), but assert in case API sequence is incorrect.
*/
DUK_ASSERT(thr->heap->pf_prevent_count == 0);
DUK_ASSERT(thr->heap->creating_error == 0);
heap = thr->heap;
duk_memcpy((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
heap->creating_error = snapshot->creating_error;
heap->curr_thread = snapshot->curr_thread;
heap->call_recursion_depth = snapshot->call_recursion_depth;
duk_pop_2(thr);
}
/* XXX: better place for this */
DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) {
duk_hobject *h_glob;
duk_hobject *h_prev_glob;
duk_hobjenv *h_env;
duk_hobject *h_prev_env;
DUK_ASSERT_API_ENTRY(thr);
DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(thr, -1)));
h_glob = duk_require_hobject(thr, -1);
DUK_ASSERT(h_glob != NULL);
/*
* Replace global object.
*/
h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
DUK_UNREF(h_prev_glob);
thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
DUK_HOBJECT_INCREF(thr, h_glob);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
/*
* Replace lexical environment for global scope
*
* Create a new object environment for the global lexical scope.
* We can't just reset the _Target property of the current one,
* because the lexical scope is shared by other threads with the
* same (initial) built-ins.
*/
h_env = duk_hobjenv_alloc(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
DUK_ASSERT(h_env != NULL);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_env) == NULL);
DUK_ASSERT(h_env->target == NULL);
DUK_ASSERT(h_glob != NULL);
h_env->target = h_glob;
DUK_HOBJECT_INCREF(thr, h_glob);
DUK_ASSERT(h_env->has_this == 0);
/* [ ... new_glob ] */
h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
thr->builtins[DUK_BIDX_GLOBAL_ENV] = (duk_hobject *) h_env;
DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_env);
DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
DUK_UNREF(h_env); /* without refcounts */
DUK_UNREF(h_prev_env);
/* [ ... new_glob ] */
duk_pop(thr);
/* [ ... ] */
}

View file

@ -1,229 +0,0 @@
/*
* Inspection
*/
#include "third_party/duktape/duk_internal.h"
/* For footprint efficient multiple value setting: arrays are much better than
* varargs, format string with parsing is often better than string pointer arrays.
*/
DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) {
duk_int_t val;
const char *p;
const char *p_curr;
duk_size_t len;
for (p = fmt;;) {
len = DUK_STRLEN(p);
p_curr = p;
p += len + 1;
if (len == 0) {
/* Double NUL (= empty key) terminates. */
break;
}
val = *vals++;
if (val >= 0) {
/* Negative values are markers to skip key. */
duk_push_string(thr, p_curr);
duk_push_int(thr, val);
duk_put_prop(thr, -3);
}
}
}
/* Raw helper to extract internal information / statistics about a value.
* The return value is an object with properties that are version specific.
* The properties must not expose anything that would lead to security
* issues (e.g. exposing compiled function 'data' buffer might be an issue).
* Currently only counts and sizes and such are given so there shouldn't
* be security implications.
*/
#define DUK__IDX_TYPE 0
#define DUK__IDX_ITAG 1
#define DUK__IDX_REFC 2
#define DUK__IDX_HBYTES 3
#define DUK__IDX_CLASS 4
#define DUK__IDX_PBYTES 5
#define DUK__IDX_ESIZE 6
#define DUK__IDX_ENEXT 7
#define DUK__IDX_ASIZE 8
#define DUK__IDX_HSIZE 9
#define DUK__IDX_BCBYTES 10
#define DUK__IDX_DBYTES 11
#define DUK__IDX_TSTATE 12
#define DUK__IDX_VARIANT 13
DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
duk_tval *tv;
duk_heaphdr *h;
/* The temporary values should be in an array rather than individual
* variables which (in practice) ensures that the compiler won't map
* them to registers and emit a lot of unnecessary shuffling code.
*/
duk_int_t vals[14];
DUK_ASSERT_API_ENTRY(thr);
/* Assume two's complement and set everything to -1. */
duk_memset((void *) &vals, (int) 0xff, sizeof(vals));
DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */
tv = duk_get_tval_or_unused(thr, idx);
h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL);
vals[DUK__IDX_TYPE] = duk_get_type_tval(tv);
vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv);
duk_push_bare_object(thr); /* Invalidates 'tv'. */
tv = NULL;
if (h == NULL) {
goto finish;
}
duk_push_pointer(thr, (void *) h);
duk_put_prop_literal(thr, -2, "hptr");
#if 0
/* Covers a lot of information, e.g. buffer and string variants. */
duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
duk_put_prop_literal(thr, -2, "hflags");
#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h);
#endif
vals[DUK__IDX_VARIANT] = 0;
/* Heaphdr size and additional allocation size, followed by
* type specific stuff (with varying value count).
*/
switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
case DUK_HTYPE_STRING: {
duk_hstring *h_str = (duk_hstring *) h;
vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1);
#if defined(DUK_USE_HSTRING_EXTDATA)
if (DUK_HSTRING_HAS_EXTDATA(h_str)) {
vals[DUK__IDX_VARIANT] = 1;
}
#endif
break;
}
case DUK_HTYPE_OBJECT: {
duk_hobject *h_obj = (duk_hobject *) h;
/* XXX: variants here are maybe pointless; class is enough? */
if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
vals[DUK__IDX_HBYTES] = sizeof(duk_harray);
} else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc);
} else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc);
} else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
vals[DUK__IDX_HBYTES] = sizeof(duk_hthread);
vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state;
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
} else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj);
/* XXX: some size information */
#endif
} else {
vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject);
}
vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj);
vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj);
vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj);
vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj);
vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj);
/* Note: e_next indicates the number of gc-reachable entries
* in the entry part, and also indicates the index where the
* next new property would be inserted. It does *not* indicate
* the number of non-NULL keys present in the object. That
* value could be counted separately but requires a pass through
* the key list.
*/
if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj);
vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0);
}
break;
}
case DUK_HTYPE_BUFFER: {
duk_hbuffer *h_buf = (duk_hbuffer *) h;
if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */
vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external));
} else {
/* When alloc_size == 0 the second allocation may not
* actually exist.
*/
vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */
vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic));
}
vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf));
} else {
DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */
vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
}
break;
}
}
finish:
duk__inspect_multiple_uint(thr,
"type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00"
"pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00"
"bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00",
(duk_int_t *) &vals);
}
DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) {
duk_activation *act;
duk_uint_fast32_t pc;
duk_uint_fast32_t line;
DUK_ASSERT_API_ENTRY(thr);
/* -1 = top callstack entry
* -2 = caller of level -1
* etc
*/
act = duk_hthread_get_activation_for_level(thr, level);
if (act == NULL) {
duk_push_undefined(thr);
return;
}
duk_push_bare_object(thr);
/* Relevant PC is just before current one because PC is
* post-incremented. This should match what error augment
* code does.
*/
pc = duk_hthread_get_act_prev_pc(thr, act);
duk_push_tval(thr, &act->tv_func);
duk_push_uint(thr, (duk_uint_t) pc);
duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC);
#if defined(DUK_USE_PC2LINE)
line = duk_hobject_pc2line_query(thr, -1, pc);
#else
line = 0;
#endif
duk_push_uint(thr, (duk_uint_t) line);
duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER);
duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION);
/* Providing access to e.g. act->lex_env would be dangerous: these
* internal structures must never be accessible to the application.
* Duktape relies on them having consistent data, and this consistency
* is only asserted for, not checked for.
*/
}

View file

@ -1,386 +0,0 @@
/*
* Internal API calls which have (stack and other) semantics similar
* to the public API.
*/
#if !defined(DUK_API_INTERNAL_H_INCLUDED)
#define DUK_API_INTERNAL_H_INCLUDED
/* Inline macro helpers. */
#if defined(DUK_USE_PREFER_SIZE)
#define DUK_INLINE_PERF
#define DUK_ALWAYS_INLINE_PERF
#define DUK_NOINLINE_PERF
#else
#define DUK_INLINE_PERF DUK_INLINE
#define DUK_ALWAYS_INLINE_PERF DUK_ALWAYS_INLINE
#define DUK_NOINLINE_PERF DUK_NOINLINE
#endif
/* Inline macro helpers, for bytecode executor. */
#if defined(DUK_USE_EXEC_PREFER_SIZE)
#define DUK_EXEC_INLINE_PERF
#define DUK_EXEC_ALWAYS_INLINE_PERF
#define DUK_EXEC_NOINLINE_PERF
#else
#define DUK_EXEC_INLINE_PERF DUK_INLINE
#define DUK_EXEC_ALWAYS_INLINE_PERF DUK_ALWAYS_INLINE
#define DUK_EXEC_NOINLINE_PERF DUK_NOINLINE
#endif
/* duk_push_sprintf constants */
#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
* blamed as source of error for error fileName / lineNumber.
*/
#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
/* Current convention is to use duk_size_t for value stack sizes and global indices,
* and duk_idx_t for local frame indices.
*/
DUK_INTERNAL_DECL void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes);
DUK_INTERNAL_DECL duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes);
DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug);
DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count);
DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count);
DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start);
DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr);
/* duk_dup_m1() would be same as duk_dup_top() */
DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv);
DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv);
#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx);
#endif
DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv);
/* Push the current 'this' binding; throw TypeError if binding is not object
* coercible (CheckObjectCoercible).
*/
DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr);
/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr);
DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i);
/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
* make sure there's an active callstack entry. Note that the returned pointer
* is unstable with regards to side effects.
*/
DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr);
/* XXX: add fastint support? */
#define duk_push_u64(thr,val) \
duk_push_number((thr), (duk_double_t) (val))
#define duk_push_i64(thr,val) \
duk_push_number((thr), (duk_double_t) (val))
/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
#define duk_push_u32(thr,val) \
duk_push_uint((thr), (duk_uint_t) (val))
#define duk_push_i32(thr,val) \
duk_push_int((thr), (duk_int_t) (val))
/* sometimes stack and array indices need to go on the stack */
#define duk_push_idx(thr,val) \
duk_push_int((thr), (duk_int_t) (val))
#define duk_push_uarridx(thr,val) \
duk_push_uint((thr), (duk_uint_t) (val))
#define duk_push_size_t(thr,val) \
duk_push_uint((thr), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_bool_t duk_is_bare_object(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx);
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);
DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
#define duk_require_hobject_promote_lfunc(thr,idx) \
duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
#define duk_get_hobject_promote_lfunc(thr,idx) \
duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
#if 0 /*unused*/
DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx);
#endif
DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr);
DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr);
DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr);
DUK_INTERNAL_DECL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr);
#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx);
#endif
DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects);
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 */
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);
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);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx);
#endif
DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len);
DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h);
DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx);
DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h);
DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h);
#define duk_push_hthread(thr,h) \
duk_push_hobject((thr), (duk_hobject *) (h))
#define duk_push_hnatfunc(thr,h) \
duk_push_hobject((thr), (duk_hobject *) (h))
DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx);
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);
DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr);
DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with
* duk_push_hobject() etc which don't create a new value.
*/
DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr);
DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size);
DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size);
DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz);
DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags);
DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv);
#if 0 /* not used yet */
DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h);
#endif
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
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);
#endif
DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len);
DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len);
DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv);
DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv);
/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short
* enough to be packed into a single 32-bit integer argument. Argument limits
* vary per call; typically 16 bits are assigned to the signed value stack index
* and the stridx. In practice these work well for footprint with constant
* arguments and such call sites are also easiest to verify to be correct.
*/
DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */
DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
#define duk_get_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
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); /* [] -> [] */
DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop(duk_hthread *thr, duk_idx_t obj_idx);
DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx);
DUK_INTERNAL_DECL duk_bool_t duk_xget_owndataprop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
#define duk_xget_owndataprop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
duk_xget_owndataprop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */
DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
#define duk_put_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
#if 0 /* Too few call sites to be useful. */
DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
#endif
#define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
duk_del_prop_stridx((thr), (obj_idx), (stridx))
DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
#if 0 /* Too few call sites to be useful. */
DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
(DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
#endif
#define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
duk_has_prop_stridx((thr), (obj_idx), (stridx))
DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */
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] -> [] */
/* XXX: Because stridx and desc_flags have a limited range, this call could
* always pack stridx and desc_flags into a single argument.
*/
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] -> [] */
DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
#define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \
(DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \
DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \
duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
#define duk_xdef_prop_wec(thr,obj_idx) \
duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
#define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \
duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
#define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \
duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
#define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \
duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
#if 0 /*unused*/
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); /* [] -> [] */
#endif
DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
DUK_INTERNAL_DECL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx);
DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count);
DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx);
#if 0
DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr);
#endif
DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h);
DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr);
DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top);
DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count);
DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count);
DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze);
DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx);
DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr);
DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
#if defined(DUK_USE_SYMBOL_BUILTIN)
DUK_INTERNAL_DECL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint);
#endif
DUK_INTERNAL_DECL void duk_clear_prototype(duk_hthread *thr, duk_idx_t idx);
/* Raw internal valstack access macros: access is unsafe so call site
* must have a guarantee that the index is valid. When that is the case,
* using these macro results in faster and smaller code than duk_get_tval().
* Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
*/
#define DUK_ASSERT_VALID_NEGIDX(thr,idx) \
(DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
#define DUK_ASSERT_VALID_POSIDX(thr,idx) \
(DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
#define DUK_GET_TVAL_NEGIDX(thr,idx) \
(DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx))
#define DUK_GET_TVAL_POSIDX(thr,idx) \
(DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx))
#define DUK_GET_HOBJECT_NEGIDX(thr,idx) \
(DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx)))
#define DUK_GET_HOBJECT_POSIDX(thr,idx) \
(DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx)))
#define DUK_GET_THIS_TVAL_PTR(thr) \
(DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
(thr)->valstack_bottom - 1)
DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr);
DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr);
DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
#endif /* DUK_API_INTERNAL_H_INCLUDED */

View file

@ -1,80 +0,0 @@
/*
* Memory calls.
*/
#include "third_party/duktape/duk_internal.h"
DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) {
DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC_RAW(thr->heap, size);
}
DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_FREE_RAW(thr->heap, ptr);
}
DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) {
DUK_ASSERT_API_ENTRY(thr);
return DUK_REALLOC_RAW(thr->heap, ptr, size);
}
DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) {
DUK_ASSERT_API_ENTRY(thr);
return DUK_ALLOC(thr->heap, size);
}
DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_FREE_CHECKED(thr, ptr);
}
DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) {
DUK_ASSERT_API_ENTRY(thr);
/*
* Note: since this is an exposed API call, there should be
* no way a mark-and-sweep could have a side effect on the
* memory allocation behind 'ptr'; the pointer should never
* be something that Duktape wants to change.
*
* Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
* have the storage location here anyway).
*/
return DUK_REALLOC(thr->heap, ptr, size);
}
DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) {
duk_heap *heap;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(out_funcs != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
heap = thr->heap;
out_funcs->alloc_func = heap->alloc_func;
out_funcs->realloc_func = heap->realloc_func;
out_funcs->free_func = heap->free_func;
out_funcs->udata = heap->heap_udata;
}
DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) {
duk_heap *heap;
duk_small_uint_t ms_flags;
DUK_ASSERT_API_ENTRY(thr);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */
ms_flags = (duk_small_uint_t) flags;
duk_heap_mark_and_sweep(heap, ms_flags);
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +0,0 @@
/*
* Random numbers
*/
#include "third_party/duktape/duk_internal.h"
DUK_EXTERNAL duk_double_t duk_random(duk_hthread *thr) {
return (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr);
}

File diff suppressed because it is too large Load diff

View file

@ -1,378 +0,0 @@
/*
* String manipulation
*/
#include "third_party/duktape/duk_internal.h"
DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) {
duk_uint_t count;
duk_uint_t i;
duk_size_t idx;
duk_size_t len;
duk_hstring *h;
duk_uint8_t *buf;
DUK_CTX_ASSERT_VALID(thr);
if (DUK_UNLIKELY(count_in <= 0)) {
if (count_in < 0) {
DUK_ERROR_RANGE_INVALID_COUNT(thr);
DUK_WO_NORETURN(return;);
}
DUK_ASSERT(count_in == 0);
duk_push_hstring_empty(thr);
return;
}
count = (duk_uint_t) count_in;
if (is_join) {
duk_size_t t1, t2, limit;
h = duk_to_hstring(thr, -((duk_idx_t) count) - 1);
DUK_ASSERT(h != NULL);
/* A bit tricky overflow test, see doc/code-issues.rst. */
t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
t2 = (duk_size_t) (count - 1);
limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
/* Combined size of separators already overflows. */
goto error_overflow;
}
len = (duk_size_t) (t1 * t2);
} else {
len = (duk_size_t) 0;
}
for (i = count; i >= 1; i--) {
duk_size_t new_len;
h = duk_to_hstring(thr, -((duk_idx_t) i));
new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
/* Impose a string maximum length, need to handle overflow
* correctly.
*/
if (new_len < len || /* wrapped */
new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) {
goto error_overflow;
}
len = new_len;
}
DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
(unsigned long) count, (unsigned long) len));
/* Use stack allocated buffer to ensure reachability in errors
* (e.g. intern error).
*/
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
DUK_ASSERT(buf != NULL);
/* [ ... (sep) str1 str2 ... strN buf ] */
idx = 0;
for (i = count; i >= 1; i--) {
if (is_join && i != count) {
h = duk_require_hstring(thr, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
h = duk_require_hstring(thr, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
idx += DUK_HSTRING_GET_BYTELEN(h);
}
DUK_ASSERT(idx == len);
/* [ ... (sep) str1 str2 ... strN buf ] */
/* Get rid of the strings early to minimize memory use before intern. */
if (is_join) {
duk_replace(thr, -((duk_idx_t) count) - 2); /* overwrite sep */
duk_pop_n(thr, (duk_idx_t) count);
} else {
duk_replace(thr, -((duk_idx_t) count) - 1); /* overwrite str1 */
duk_pop_n(thr, (duk_idx_t) (count - 1));
}
/* [ ... buf ] */
(void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
/* [ ... res ] */
return;
error_overflow:
DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
DUK_WO_NORETURN(return;);
}
DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) {
DUK_ASSERT_API_ENTRY(thr);
duk__concat_and_join_helper(thr, count, 0 /*is_join*/);
}
#if defined(DUK_USE_PREFER_SIZE)
DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
duk_concat(thr, 2);
}
#else /* DUK_USE_PREFER_SIZE */
DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
duk_hstring *h1;
duk_hstring *h2;
duk_uint8_t *buf;
duk_size_t len1;
duk_size_t len2;
duk_size_t len;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(duk_get_top(thr) >= 2); /* Trusted caller. */
h1 = duk_to_hstring(thr, -2);
h2 = duk_to_hstring(thr, -1);
len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
len = len1 + len2;
if (DUK_UNLIKELY(len < len1 || /* wrapped */
len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) {
goto error_overflow;
}
buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
DUK_ASSERT(buf != NULL);
duk_memcpy((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
duk_memcpy((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
(void) duk_buffer_to_string(thr, -1); /* Safe if inputs are safe. */
/* [ ... str1 str2 buf ] */
duk_replace(thr, -3);
duk_pop_unsafe(thr);
return;
error_overflow:
DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
DUK_WO_NORETURN(return;);
}
#endif /* DUK_USE_PREFER_SIZE */
DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) {
DUK_ASSERT_API_ENTRY(thr);
duk__concat_and_join_helper(thr, count, 1 /*is_join*/);
}
/* XXX: could map/decode be unified with duk_unicode_support.c code?
* Case conversion needs also the character surroundings though.
*/
DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
duk_hstring *h_input;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
DUK_ASSERT_API_ENTRY(thr);
h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start;
for (;;) {
if (p >= p_end) {
break;
}
cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
callback(udata, cp);
}
}
DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) {
duk_hstring *h_input;
duk_bufwriter_ctx bw_alloc;
duk_bufwriter_ctx *bw;
const duk_uint8_t *p, *p_start, *p_end;
duk_codepoint_t cp;
DUK_ASSERT_API_ENTRY(thr);
idx = duk_normalize_index(thr, idx);
h_input = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h_input != NULL);
bw = &bw_alloc;
DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
p = p_start;
for (;;) {
/* XXX: could write output in chunks with fewer ensure calls,
* but relative benefit would be small here.
*/
if (p >= p_end) {
break;
}
cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
cp = callback(udata, cp);
DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
}
DUK_BW_COMPACT(thr, bw);
(void) duk_buffer_to_string(thr, -1); /* Safe, extended UTF-8 encoded. */
duk_replace(thr, idx);
}
DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
duk_hstring *h;
duk_hstring *res;
duk_size_t start_byte_offset;
duk_size_t end_byte_offset;
duk_size_t charlen;
DUK_ASSERT_API_ENTRY(thr);
idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
charlen = DUK_HSTRING_GET_CHARLEN(h);
if (end_offset >= charlen) {
end_offset = charlen;
}
if (start_offset > end_offset) {
start_offset = end_offset;
}
DUK_ASSERT_DISABLE(start_offset >= 0);
DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
DUK_ASSERT_DISABLE(end_offset >= 0);
DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
/* Guaranteed by string limits. */
DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset);
end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
DUK_ASSERT(end_byte_offset >= start_byte_offset);
DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */
/* No size check is necessary. */
res = duk_heap_strtable_intern_checked(thr,
DUK_HSTRING_GET_DATA(h) + start_byte_offset,
(duk_uint32_t) (end_byte_offset - start_byte_offset));
duk_push_hstring(thr, res);
duk_replace(thr, idx);
}
/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
* forwards with a callback to process codepoints?
*/
DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) {
duk_hstring *h;
const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
duk_codepoint_t cp;
DUK_ASSERT_API_ENTRY(thr);
idx = duk_require_normalize_index(thr, idx); /* Accept symbols. */
h = duk_require_hstring(thr, idx);
DUK_ASSERT(h != NULL);
p_start = DUK_HSTRING_GET_DATA(h);
p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
p = p_start;
while (p < p_end) {
p_tmp1 = p;
cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
break;
}
p = p_tmp1;
}
q_start = p;
if (p == p_end) {
/* Entire string is whitespace. */
q_end = p;
goto scan_done;
}
p = p_end;
while (p > p_start) {
p_tmp1 = p;
while (p > p_start) {
p--;
if (((*p) & 0xc0) != 0x80) {
break;
}
}
p_tmp2 = p;
cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
p = p_tmp1;
break;
}
}
q_end = p;
scan_done:
/* This may happen when forward and backward scanning disagree
* (possible for non-extended-UTF-8 strings).
*/
if (q_end < q_start) {
q_end = q_start;
}
DUK_ASSERT(q_start >= p_start && q_start <= p_end);
DUK_ASSERT(q_end >= p_start && q_end <= p_end);
DUK_ASSERT(q_end >= q_start);
DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
(const void *) p_start, (const void *) p_end,
(const void *) q_start, (const void *) q_end));
if (q_start == p_start && q_end == p_end) {
DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
return;
}
duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start));
duk_replace(thr, idx);
}
DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) {
duk_hstring *h;
duk_ucodepoint_t cp;
DUK_ASSERT_API_ENTRY(thr);
/* XXX: Share code with String.prototype.charCodeAt? Main difference
* is handling of clamped offsets.
*/
h = duk_require_hstring(thr, idx); /* Accept symbols. */
DUK_ASSERT(h != NULL);
DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */
if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
return 0;
}
DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */
cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/);
return (duk_codepoint_t) cp;
}

View file

@ -1,110 +0,0 @@
/*
* Date/time.
*/
#include "third_party/duktape/duk_internal.h"
DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
/* ECMAScript time, with millisecond fractions. Exposed via
* duk_get_now() for example.
*/
DUK_UNREF(thr);
return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
}
DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) {
/* ECMAScript time without millisecond fractions. Exposed via
* the Date built-in which doesn't allow fractions.
*/
DUK_UNREF(thr);
return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr));
}
DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) {
DUK_UNREF(thr);
#if defined(DUK_USE_GET_MONOTONIC_TIME)
return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr);
#else
return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
#endif
}
DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(thr);
/* This API intentionally allows millisecond fractions. */
return duk_time_get_ecmascript_time(thr);
}
#if 0 /* XXX: worth exposing? */
DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) {
DUK_ASSERT_API_ENTRY(thr);
DUK_UNREF(thr);
return duk_time_get_monotonic_time(thr);
}
#endif
DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) {
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_uint_t flags;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(comp != NULL); /* XXX: or check? */
DUK_UNREF(thr);
/* Convert as one-based, but change month to zero-based to match the
* ECMAScript Date built-in behavior 1:1.
*/
flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
/* XXX: sub-millisecond accuracy for the API */
DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0);
comp->year = dparts[DUK_DATE_IDX_YEAR];
comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0;
comp->day = dparts[DUK_DATE_IDX_DAY];
comp->hours = dparts[DUK_DATE_IDX_HOUR];
comp->minutes = dparts[DUK_DATE_IDX_MINUTE];
comp->seconds = dparts[DUK_DATE_IDX_SECOND];
comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND];
comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY];
}
DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) {
duk_double_t d;
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
duk_uint_t flags;
DUK_ASSERT_API_ENTRY(thr);
DUK_ASSERT(comp != NULL); /* XXX: or check? */
DUK_UNREF(thr);
/* Match Date constructor behavior (with UTC time). Month is given
* as zero-based. Day-of-month is given as one-based so normalize
* it to zero-based as the internal conversion helpers expects all
* components to be zero-based.
*/
flags = 0;
/* XXX: expensive conversion; use array format in API instead, or unify
* time provider and time API to use same struct?
*/
dparts[DUK_DATE_IDX_YEAR] = comp->year;
dparts[DUK_DATE_IDX_MONTH] = comp->month;
dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0;
dparts[DUK_DATE_IDX_HOUR] = comp->hours;
dparts[DUK_DATE_IDX_MINUTE] = comp->minutes;
dparts[DUK_DATE_IDX_SECOND] = comp->seconds;
dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds;
dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */
d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
return d;
}

File diff suppressed because it is too large Load diff

View file

@ -1,69 +0,0 @@
/*
* Boolean built-ins
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_BOOLEAN_BUILTIN)
/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
* the primitive value to stack top, and optionally coerces with ToString().
*/
DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) {
duk_tval *tv;
duk_hobject *h;
duk_small_int_t coerce_tostring = duk_get_current_magic(thr);
/* XXX: there is room to use a shared helper here, many built-ins
* check the 'this' type, and if it's an object, check its class,
* then get its internal value, etc.
*/
duk_push_this(thr);
tv = duk_get_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_BOOLEAN(tv)) {
goto type_ok;
} else if (DUK_TVAL_IS_OBJECT(tv)) {
h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
DUK_ASSERT(duk_is_boolean(thr, -1));
goto type_ok;
}
}
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
/* never here */
type_ok:
if (coerce_tostring) {
duk_to_string(thr, -1);
}
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) {
duk_hobject *h_this;
duk_to_boolean(thr, 0);
if (duk_is_constructor_call(thr)) {
/* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
duk_push_this(thr);
h_this = duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
duk_dup_0(thr); /* -> [ val obj val ] */
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
} /* unbalanced stack */
return 1;
}
#endif /* DUK_USE_BOOLEAN_BUILTIN */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,325 +0,0 @@
/*
* Unix-like Date providers
*
* Generally useful Unix / POSIX / ANSI Date providers.
*/
#include "third_party/duktape/duk_internal.h"
/* The necessary #includes are in place in duk_config.h. */
/* Buffer sizes for some UNIX calls. Larger than strictly necessary
* to avoid Valgrind errors.
*/
#define DUK__STRPTIME_BUF_SIZE 64
#define DUK__STRFTIME_BUF_SIZE 64
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
/* Get current ECMAScript time (= UNIX/Posix time, but in milliseconds). */
DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) {
struct timeval tv;
duk_double_t d;
if (gettimeofday(&tv, NULL) != 0) {
DUK_D(DUK_DPRINT("gettimeofday() failed"));
return 0.0;
}
/* As of Duktape 2.2.0 allow fractions. */
d = ((duk_double_t) tv.tv_sec) * 1000.0 +
((duk_double_t) tv.tv_usec) / 1000.0;
return d;
}
#endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
#if defined(DUK_USE_DATE_NOW_TIME)
/* Not a very good provider: only full seconds are available. */
DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) {
time_t t;
t = time(NULL);
if (t == (time_t) -1) {
DUK_D(DUK_DPRINT("time() failed"));
return 0.0;
}
return ((duk_double_t) t) * 1000.0;
}
#endif /* DUK_USE_DATE_NOW_TIME */
#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S)
/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
time_t t, t1, t2;
duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
struct tm tms[2];
#if defined(DUK_USE_DATE_TZO_GMTIME)
struct tm *tm_ptr;
#endif
/* For NaN/inf, the return value doesn't matter. */
if (!DUK_ISFINITE(d)) {
return 0;
}
/* If not within ECMAScript range, some integer time calculations
* won't work correctly (and some asserts will fail), so bail out
* if so. This fixes test-bug-date-insane-setyear.js. There is
* a +/- 24h leeway in this range check to avoid a test262 corner
* case documented in test-bug-date-timeval-edges.js.
*/
if (!duk_bi_date_timeval_in_leeway_range(d)) {
DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows"));
return 0;
}
/*
* This is a bit tricky to implement portably. The result depends
* on the timestamp (specifically, DST depends on the timestamp).
* If e.g. UNIX APIs are used, they'll have portability issues with
* very small and very large years.
*
* Current approach:
*
* - Stay within portable UNIX limits by using equivalent year mapping.
* Avoid year 1970 and 2038 as some conversions start to fail, at
* least on some platforms. Avoiding 1970 means that there are
* currently DST discrepancies for 1970.
*
* - Create a UTC and local time breakdowns from 't'. Then create
* a time_t using gmtime() and localtime() and compute the time
* difference between the two.
*
* Equivalent year mapping (E5 Section 15.9.1.8):
*
* If the host environment provides functionality for determining
* daylight saving time, the implementation of ECMAScript is free
* to map the year in question to an equivalent year (same
* leap-year-ness and same starting week day for the year) for which
* the host environment provides daylight saving time information.
* The only restriction is that all equivalent years should produce
* the same result.
*
* This approach is quite reasonable but not entirely correct, e.g.
* the specification also states (E5 Section 15.9.1.8):
*
* The implementation of ECMAScript should not try to determine
* whether the exact time was subject to daylight saving time, but
* just whether daylight saving time would have been in effect if
* the _current daylight saving time algorithm_ had been used at the
* time. This avoids complications such as taking into account the
* years that the locale observed daylight saving time year round.
*
* Since we rely on the platform APIs for conversions between local
* time and UTC, we can't guarantee the above. Rather, if the platform
* has historical DST rules they will be applied. This seems to be the
* general preferred direction in ECMAScript standardization (or at least
* implementations) anyway, and even the equivalent year mapping should
* be disabled if the platform is known to handle DST properly for the
* full ECMAScript range.
*
* The following has useful discussion and links:
*
* https://bugzilla.mozilla.org/show_bug.cgi?id=351066
*/
duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/);
DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038);
d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */
t = (time_t) (d / 1000.0);
DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
duk_memzero((void *) tms, sizeof(struct tm) * 2);
#if defined(DUK_USE_DATE_TZO_GMTIME_R)
(void) gmtime_r(&t, &tms[0]);
(void) localtime_r(&t, &tms[1]);
#elif defined(DUK_USE_DATE_TZO_GMTIME_S)
(void) gmtime_s(&t, &tms[0]);
(void) localtime_s(&t, &tms[1]);
#elif defined(DUK_USE_DATE_TZO_GMTIME)
tm_ptr = gmtime(&t);
duk_memcpy((void *) &tms[0], tm_ptr, sizeof(struct tm));
tm_ptr = localtime(&t);
duk_memcpy((void *) &tms[1], tm_ptr, sizeof(struct tm));
#else
#error internal error
#endif
DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
"wday:%ld,yday:%ld,isdst:%ld}",
(long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour,
(long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year,
(long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst));
DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
"wday:%ld,yday:%ld,isdst:%ld}",
(long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour,
(long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
(long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
/* tm_isdst is both an input and an output to mktime(), use 0 to
* avoid DST handling in mktime():
* - https://github.com/svaarala/duktape/issues/406
* - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
*/
tms[0].tm_isdst = 0;
tms[1].tm_isdst = 0;
t1 = mktime(&tms[0]); /* UTC */
t2 = mktime(&tms[1]); /* local */
if (t1 == (time_t) -1 || t2 == (time_t) -1) {
/* This check used to be for (t < 0) but on some platforms
* time_t is unsigned and apparently the proper way to detect
* an mktime() error return is the cast above. See e.g.:
* http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
*/
goto mktime_error;
}
DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
/* Compute final offset in seconds, positive if local time ahead of
* UTC (returned value is UTC-to-local offset).
*
* difftime() returns a double, so coercion to int generates quite
* a lot of code. Direct subtraction is not portable, however.
* XXX: allow direct subtraction on known platforms.
*/
#if 0
return (duk_int_t) (t2 - t1);
#endif
return (duk_int_t) difftime(t2, t1);
mktime_error:
/* XXX: return something more useful, so that caller can throw? */
DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
return 0;
}
#endif /* DUK_USE_DATE_TZO_GMTIME */
#if defined(DUK_USE_DATE_PRS_STRPTIME)
DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) {
struct tm tm;
time_t t;
char buf[DUK__STRPTIME_BUF_SIZE];
/* Copy to buffer with slack to avoid Valgrind gripes from strptime. */
DUK_ASSERT(str != NULL);
duk_memzero(buf, sizeof(buf)); /* valgrind whine without this */
DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
buf[sizeof(buf) - 1] = (char) 0;
DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
duk_memzero(&tm, sizeof(tm));
if (strptime((const char *) buf, "%c", &tm) != NULL) {
DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
"wday:%ld,yday:%ld,isdst:%ld}",
(long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour,
(long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year,
(long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst));
tm.tm_isdst = -1; /* negative: dst info not available */
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
duk_push_number(thr, ((duk_double_t) t) * 1000.0);
return 1;
}
}
return 0;
}
#endif /* DUK_USE_DATE_PRS_STRPTIME */
#if defined(DUK_USE_DATE_PRS_GETDATE)
DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) {
struct tm tm;
duk_small_int_t rc;
time_t t;
/* For this to work, DATEMSK must be set, so this is not very
* convenient for an embeddable interpreter.
*/
duk_memzero(&tm, sizeof(struct tm));
rc = (duk_small_int_t) getdate_r(str, &tm);
DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
if (rc == 0) {
t = mktime(&tm);
DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
if (t >= 0) {
duk_push_number(thr, (duk_double_t) t);
return 1;
}
}
return 0;
}
#endif /* DUK_USE_DATE_PRS_GETDATE */
#if defined(DUK_USE_DATE_FMT_STRFTIME)
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) {
char buf[DUK__STRFTIME_BUF_SIZE];
struct tm tm;
const char *fmt;
DUK_UNREF(tzoffset);
/* If the platform doesn't support the entire ECMAScript range, we need
* to return 0 so that the caller can fall back to the default formatter.
*
* For now, assume that if time_t is 8 bytes or more, the whole ECMAScript
* range is supported. For smaller time_t values (4 bytes in practice),
* assumes that the signed 32-bit range is supported.
*
* XXX: detect this more correctly per platform. The size of time_t is
* probably not an accurate guarantee of strftime() supporting or not
* supporting a large time range (the full ECMAScript range).
*/
if (sizeof(time_t) < 8 &&
(parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
/* be paranoid for 32-bit time values (even avoiding negative ones) */
return 0;
}
duk_memzero(&tm, sizeof(tm));
tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */
tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */
tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
tm.tm_isdst = 0;
duk_memzero(buf, sizeof(buf));
if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
fmt = "%c";
} else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
fmt = "%x";
} else {
DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
fmt = "%X";
}
(void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
duk_push_string(thr, buf);
return 1;
}
#endif /* DUK_USE_DATE_FMT_STRFTIME */
#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0;
} else {
DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed"));
return 0.0;
}
}
#endif

View file

@ -1,193 +0,0 @@
/*
* Windows Date providers
*
* Platform specific links:
*
* - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
*/
#include "third_party/duktape/duk_internal.h"
/* The necessary #includes are in place in duk_config.h. */
#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
/* Shared Windows helpers. */
DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
FILETIME ft;
if (SystemTimeToFileTime(st, &ft) == 0) {
DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
res->QuadPart = 0;
} else {
res->LowPart = ft.dwLowDateTime;
res->HighPart = ft.dwHighDateTime;
}
}
#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
res->LowPart = ft->dwLowDateTime;
res->HighPart = ft->dwHighDateTime;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS_SUBMS */
DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
duk_memzero((void *) st, sizeof(*st));
st->wYear = 1970;
st->wMonth = 1;
st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
st->wDay = 1;
DUK_ASSERT(st->wHour == 0);
DUK_ASSERT(st->wMinute == 0);
DUK_ASSERT(st->wSecond == 0);
DUK_ASSERT(st->wMilliseconds == 0);
}
#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
#if defined(DUK_USE_DATE_NOW_WINDOWS)
DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) {
/* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
*/
SYSTEMTIME st1, st2;
ULARGE_INTEGER tmp1, tmp2;
GetSystemTime(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
duk__set_systime_jan1970(&st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
/* Difference is in 100ns units, convert to milliseconds, keeping
* fractions since Duktape 2.2.0. This is only theoretical because
* SYSTEMTIME is limited to milliseconds.
*/
return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */
#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) {
/* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime()
* for more accuracy.
*/
FILETIME ft1;
SYSTEMTIME st2;
ULARGE_INTEGER tmp1, tmp2;
GetSystemTimePreciseAsFileTime(&ft1);
duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1);
duk__set_systime_jan1970(&st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
/* Difference is in 100ns units, convert to milliseconds, keeping
* fractions since Duktape 2.2.0.
*/
return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS)
DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
SYSTEMTIME st3;
ULARGE_INTEGER tmp1;
ULARGE_INTEGER tmp2;
ULARGE_INTEGER tmp3;
FILETIME ft1;
/* XXX: handling of timestamps outside Windows supported range.
* How does Windows deal with dates before 1600? Does windows
* support all ECMAScript years (like -200000 and +200000)?
* Should equivalent year mapping be used here too? If so, use
* a shared helper (currently integrated into timeval-to-parts).
*/
/* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
*/
duk__set_systime_jan1970(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */
ft1.dwLowDateTime = tmp2.LowPart;
ft1.dwHighDateTime = tmp2.HighPart;
if (FileTimeToSystemTime((const FILETIME *) &ft1, &st2) == 0) {
DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
return 0;
}
if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
return 0;
}
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
/* Positive if local time ahead of UTC. */
return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
FILETIME ft1;
FILETIME ft2;
ULARGE_INTEGER tmp1;
ULARGE_INTEGER tmp2;
/* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
* but without accounting for daylight savings time. Use this on
* Windows platforms (like Durango) that don't support the
* SystemTimeToTzSpecificLocalTime() call.
*/
/* current time not needed for this computation */
DUK_UNREF(d);
duk__set_systime_jan1970(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
ft1.dwLowDateTime = tmp1.LowPart;
ft1.dwHighDateTime = tmp1.HighPart;
if (FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2) == 0) {
DUK_D(DUK_DPRINT("FileTimeToLocalFileTime() failed, return tzoffset 0"));
return 0;
}
if (FileTimeToSystemTime((const FILETIME *) &ft2, &st2) == 0) {
DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
return 0;
}
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */
#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
LARGE_INTEGER count, freq;
/* There are legacy issues with QueryPerformanceCounter():
* - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward
* - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
*
* We avoid these by enabling QPC by default only for Vista or later.
*/
if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) {
/* XXX: QueryPerformanceFrequency() can be cached */
return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0;
} else {
/* MSDN: "On systems that run Windows XP or later, the function
* will always succeed and will thus never return zero."
* Provide minimal error path just in case user enables this
* feature in pre-XP Windows.
*/
return 0.0;
}
}
#endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */

View file

@ -1,158 +0,0 @@
/*
* Duktape built-ins
*
* Size optimization note: it might seem that vararg multipurpose functions
* like fin(), enc(), and dec() are not very size optimal, but using a single
* user-visible ECMAScript function saves a lot of run-time footprint; each
* Function instance takes >100 bytes. Using a shared native helper and a
* 'magic' value won't save much if there are multiple Function instances
* anyway.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_DUKTAPE_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) {
duk_inspect_value(thr, -1);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) {
duk_int_t level;
level = duk_to_int(thr, 0);
duk_inspect_callstack_entry(thr, level);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) {
duk_small_uint_t flags;
flags = (duk_small_uint_t) duk_get_uint(thr, 0);
duk_heap_mark_and_sweep(thr->heap, flags);
/* XXX: Not sure what the best return value would be in the API.
* Return true for now.
*/
duk_push_true(thr);
return 1;
}
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) {
(void) duk_require_hobject(thr, 0);
if (duk_get_top(thr) >= 2) {
/* Set: currently a finalizer is disabled by setting it to
* undefined; this does not remove the property at the moment.
* The value could be type checked to be either a function
* or something else; if something else, the property could
* be deleted. Must use duk_set_finalizer() to keep
* DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync.
*/
duk_set_top(thr, 2);
duk_set_finalizer(thr, 0);
return 0;
} else {
/* Get. */
DUK_ASSERT(duk_get_top(thr) == 1);
duk_get_finalizer(thr, 0);
return 1;
}
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) {
duk_hstring *h_str;
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons. */
duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
duk_set_top(thr, 2);
duk_hex_encode(thr, 1);
DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
duk_set_top(thr, 2);
duk_base64_encode(thr, 1);
DUK_ASSERT_TOP(thr, 2);
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
DUK_JSON_FLAG_EXT_CUSTOM |
DUK_JSON_FLAG_ASCII_ONLY |
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
#endif
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
duk_bi_json_stringify_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
3 /*idx_space*/,
DUK_JSON_FLAG_EXT_COMPATIBLE |
DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
#endif
} else {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) {
duk_hstring *h_str;
/* Vararg function: must be careful to check/require arguments.
* The JSON helpers accept invalid indices and treat them like
* non-existent optional parameters.
*/
h_str = duk_require_hstring(thr, 0); /* Could reject symbols, but no point: won't match comparisons */
duk_require_valid_index(thr, 1);
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
duk_set_top(thr, 2);
duk_hex_decode(thr, 1);
DUK_ASSERT_TOP(thr, 2);
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
duk_set_top(thr, 2);
duk_base64_decode(thr, 1);
DUK_ASSERT_TOP(thr, 2);
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
#endif
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
duk_bi_json_parse_helper(thr,
1 /*idx_value*/,
2 /*idx_replacer*/,
DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
#endif
} else {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
return 1;
}
/*
* Compact an object
*/
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) {
DUK_ASSERT_TOP(thr, 1);
duk_compact(thr, 0);
return 1; /* return the argument object */
}
#endif /* DUK_USE_DUKTAPE_BUILTIN */

View file

@ -1,533 +0,0 @@
/*
* WHATWG Encoding API built-ins
*
* API specification: https://encoding.spec.whatwg.org/#api
* Web IDL: https://www.w3.org/TR/WebIDL/
*/
#include "third_party/duktape/duk_internal.h"
/*
* Data structures for encoding/decoding
*/
typedef struct {
duk_uint8_t *out; /* where to write next byte(s) */
duk_codepoint_t lead; /* lead surrogate */
} duk__encode_context;
typedef struct {
/* UTF-8 decoding state */
duk_codepoint_t codepoint; /* built up incrementally */
duk_uint8_t upper; /* max value of next byte (decode error otherwise) */
duk_uint8_t lower; /* min value of next byte (ditto) */
duk_uint8_t needed; /* how many more bytes we need */
duk_uint8_t bom_handled; /* BOM seen or no longer expected */
/* Decoder configuration */
duk_uint8_t fatal;
duk_uint8_t ignore_bom;
} duk__decode_context;
/* The signed duk_codepoint_t type is used to signal a decoded codepoint
* (>= 0) or various other states using negative values.
*/
#define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */
#define DUK__CP_ERROR (-2) /* decoding error */
#define DUK__CP_RETRY (-3) /* decoding error; retry last byte */
/*
* Raw helpers for encoding/decoding
*/
/* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */
DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) {
*ptr++ = 0xef;
*ptr++ = 0xbf;
*ptr++ = 0xbd;
return ptr;
}
DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) {
/* (Re)init the decoding state of 'dec_ctx' but leave decoder
* configuration fields untouched.
*/
dec_ctx->codepoint = 0x0000L;
dec_ctx->upper = 0xbf;
dec_ctx->lower = 0x80;
dec_ctx->needed = 0;
dec_ctx->bom_handled = 0;
}
DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) {
/*
* UTF-8 algorithm based on the Encoding specification:
* https://encoding.spec.whatwg.org/#utf-8-decoder
*
* Two main states: decoding initial byte vs. decoding continuation
* bytes. Shortest length encoding is validated by restricting the
* allowed range of first continuation byte using 'lower' and 'upper'.
*/
if (dec_ctx->needed == 0) {
/* process initial byte */
if (x <= 0x7f) {
/* U+0000-U+007F, 1 byte (ASCII) */
return (duk_codepoint_t) x;
} else if (x >= 0xc2 && x <= 0xdf) {
/* U+0080-U+07FF, 2 bytes */
dec_ctx->needed = 1;
dec_ctx->codepoint = x & 0x1f;
DUK_ASSERT(dec_ctx->lower == 0x80);
DUK_ASSERT(dec_ctx->upper == 0xbf);
return DUK__CP_CONTINUE;
} else if (x >= 0xe0 && x <= 0xef) {
/* U+0800-U+FFFF, 3 bytes */
if (x == 0xe0) {
dec_ctx->lower = 0xa0;
DUK_ASSERT(dec_ctx->upper == 0xbf);
} else if (x == 0xed) {
DUK_ASSERT(dec_ctx->lower == 0x80);
dec_ctx->upper = 0x9f;
}
dec_ctx->needed = 2;
dec_ctx->codepoint = x & 0x0f;
return DUK__CP_CONTINUE;
} else if (x >= 0xf0 && x <= 0xf4) {
/* U+010000-U+10FFFF, 4 bytes */
if (x == 0xf0) {
dec_ctx->lower = 0x90;
DUK_ASSERT(dec_ctx->upper == 0xbf);
} else if (x == 0xf4) {
DUK_ASSERT(dec_ctx->lower == 0x80);
dec_ctx->upper = 0x8f;
}
dec_ctx->needed = 3;
dec_ctx->codepoint = x & 0x07;
return DUK__CP_CONTINUE;
} else {
/* not a legal initial byte */
return DUK__CP_ERROR;
}
} else {
/* process continuation byte */
if (x >= dec_ctx->lower && x <= dec_ctx->upper) {
dec_ctx->lower = 0x80;
dec_ctx->upper = 0xbf;
dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f);
if (--dec_ctx->needed > 0) {
/* need more bytes */
return DUK__CP_CONTINUE;
} else {
/* got a codepoint */
duk_codepoint_t ret;
DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */
ret = dec_ctx->codepoint;
dec_ctx->codepoint = 0x0000L;
dec_ctx->needed = 0;
return ret;
}
} else {
/* We just encountered an illegal UTF-8 continuation byte. This might
* be the initial byte of the next character; if we return a plain
* error status and the decoder is in replacement mode, the character
* will be masked. We still need to alert the caller to the error
* though.
*/
dec_ctx->codepoint = 0x0000L;
dec_ctx->needed = 0;
dec_ctx->lower = 0x80;
dec_ctx->upper = 0xbf;
return DUK__CP_RETRY;
}
}
}
#if defined(DUK_USE_ENCODING_BUILTINS)
DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
duk__encode_context *enc_ctx;
DUK_ASSERT(codepoint >= 0);
enc_ctx = (duk__encode_context *) udata;
DUK_ASSERT(enc_ctx != NULL);
#if !defined(DUK_USE_PREFER_SIZE)
if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) {
/* Fast path for ASCII. */
*enc_ctx->out++ = (duk_uint8_t) codepoint;
return;
}
#endif
if (DUK_UNLIKELY(codepoint > 0x10ffffL)) {
/* cannot legally encode in UTF-8 */
codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
} else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) {
if (codepoint <= 0xdbffL) {
/* high surrogate */
duk_codepoint_t prev_lead = enc_ctx->lead;
enc_ctx->lead = codepoint;
if (prev_lead == 0x0000L) {
/* high surrogate, no output */
return;
} else {
/* consecutive high surrogates, consider first one unpaired */
codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
}
} else {
/* low surrogate */
if (enc_ctx->lead != 0x0000L) {
codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L));
enc_ctx->lead = 0x0000L;
} else {
/* unpaired low surrogate */
DUK_ASSERT(enc_ctx->lead == 0x0000L);
codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
}
}
} else {
if (enc_ctx->lead != 0x0000L) {
/* unpaired high surrogate: emit replacement character and the input codepoint */
enc_ctx->lead = 0x0000L;
enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out);
}
}
/* Codepoint may be original input, a decoded surrogate pair, or may
* have been replaced with U+FFFD.
*/
enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out);
}
#endif /* DUK_USE_ENCODING_BUILTINS */
/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8
* decoder.
*/
DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) {
const duk_uint8_t *input;
duk_size_t len = 0;
duk_size_t len_tmp;
duk_bool_t stream = 0;
duk_codepoint_t codepoint;
duk_uint8_t *output;
const duk_uint8_t *in;
duk_uint8_t *out;
DUK_ASSERT(dec_ctx != NULL);
/* Careful with input buffer pointer: any side effects involving
* code execution (e.g. getters, coercion calls, and finalizers)
* may cause a resize and invalidate a pointer we've read. This
* is why the pointer is actually looked up at the last minute.
* Argument validation must still happen first to match WHATWG
* required side effect order.
*/
if (duk_is_undefined(thr, 0)) {
duk_push_fixed_buffer_nozero(thr, 0);
duk_replace(thr, 0);
}
(void) duk_require_buffer_data(thr, 0, &len); /* Need 'len', avoid pointer. */
if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_NULL |
DUK_TYPE_MASK_NONE)) {
/* Use defaults, treat missing value like undefined. */
} else {
duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_NULL |
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER |
DUK_TYPE_MASK_OBJECT);
if (duk_get_prop_literal(thr, 1, "stream")) {
stream = duk_to_boolean(thr, -1);
}
}
/* Allowance is 3*len in the general case because all bytes may potentially
* become U+FFFD. If the first byte completes a non-BMP codepoint it will
* decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to
* compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because
* the 4->6 expansion is well under the 3x allowance.
*
* XXX: As with TextEncoder, need a better buffer allocation strategy here.
*/
if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
DUK_WO_NORETURN(return 0;);
}
output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len)); /* used parts will be always manually written over */
input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp);
DUK_ASSERT(input != NULL || len == 0);
if (DUK_UNLIKELY(len != len_tmp)) {
/* Very unlikely but possible: source buffer was resized by
* a side effect when fixed buffer was pushed. Output buffer
* may not be large enough to hold output, so just fail if
* length has changed.
*/
DUK_D(DUK_DPRINT("input buffer resized by side effect, fail"));
goto fail_type;
}
/* From this point onwards it's critical that no side effect occur
* which may disturb 'input': finalizer execution, property accesses,
* active coercions, etc. Even an allocation related mark-and-sweep
* may affect the pointer because it may trigger a pending finalizer.
*/
in = input;
out = output;
while (in < input + len) {
codepoint = duk__utf8_decode_next(dec_ctx, *in++);
if (codepoint < 0) {
if (codepoint == DUK__CP_CONTINUE) {
continue;
}
/* Decoding error with or without retry. */
DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY);
if (codepoint == DUK__CP_RETRY) {
--in; /* retry last byte */
}
/* replacement mode: replace with U+FFFD */
codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
if (dec_ctx->fatal) {
/* fatal mode: throw a TypeError */
goto fail_type;
}
/* Continue with 'codepoint', Unicode replacement. */
}
DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL);
if (!dec_ctx->bom_handled) {
dec_ctx->bom_handled = 1;
if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) {
continue;
}
}
out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out);
DUK_ASSERT(out <= output + (3 + (3 * len)));
}
if (!stream) {
if (dec_ctx->needed != 0) {
/* truncated sequence at end of buffer */
if (dec_ctx->fatal) {
goto fail_type;
} else {
out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out);
DUK_ASSERT(out <= output + (3 + (3 * len)));
}
}
duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */
}
/* Output buffer is fixed and thus stable even if there had been
* side effects (which there shouldn't be).
*/
duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output));
return 1;
fail_type:
DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED);
DUK_WO_NORETURN(return 0;);
}
/*
* Built-in bindings
*/
#if defined(DUK_USE_ENCODING_BUILTINS)
DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) {
/* TextEncoder currently requires no persistent state, so the constructor
* does nothing on purpose.
*/
duk_require_constructor_call(thr);
return 0;
}
DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) {
duk_push_literal(thr, "utf-8");
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
duk__encode_context enc_ctx;
duk_size_t len;
duk_size_t final_len;
duk_uint8_t *output;
DUK_ASSERT_TOP(thr, 1);
if (duk_is_undefined(thr, 0)) {
len = 0;
} else {
duk_hstring *h_input;
h_input = duk_to_hstring(thr, 0);
DUK_ASSERT(h_input != NULL);
len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
DUK_WO_NORETURN(return 0;);
}
}
/* Allowance is 3*len because all bytes can potentially be replaced with
* U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8.
* Rely on dynamic buffer data pointer stability: no other code has
* access to the data pointer.
*
* XXX: The buffer allocation strategy used here is rather inefficient.
* Maybe switch to a chunk-based strategy, or preprocess the string to
* figure out the space needed ahead of time?
*/
DUK_ASSERT(3 * len >= len);
output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len);
if (len > 0) {
DUK_ASSERT(duk_is_string(thr, 0)); /* True if len > 0. */
/* XXX: duk_decode_string() is used to process the input
* string. For standard ECMAScript strings, represented
* internally as CESU-8, this is fine. However, behavior
* beyond CESU-8 is not very strict: codepoints using an
* extended form of UTF-8 are also accepted, and invalid
* codepoint sequences (which are allowed in Duktape strings)
* are not handled as well as they could (e.g. invalid
* continuation bytes may mask following codepoints).
* This is how ECMAScript code would also see such strings.
* Maybe replace duk_decode_string() with an explicit strict
* CESU-8 decoder here?
*/
enc_ctx.lead = 0x0000L;
enc_ctx.out = output;
duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx);
if (enc_ctx.lead != 0x0000L) {
/* unpaired high surrogate at end of string */
enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out);
DUK_ASSERT(enc_ctx.out <= output + (3 * len));
}
/* The output buffer is usually very much oversized, so shrink it to
* actually needed size. Pointer stability assumed up to this point.
*/
DUK_ASSERT_TOP(thr, 2);
DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL));
final_len = (duk_size_t) (enc_ctx.out - output);
duk_resize_buffer(thr, -1, final_len);
/* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */
} else {
final_len = 0;
}
/* Standard WHATWG output is a Uint8Array. Here the Uint8Array will
* be backed by a dynamic buffer which differs from e.g. Uint8Arrays
* created as 'new Uint8Array(N)'. ECMAScript code won't see the
* difference but C code will. When bufferobjects are not supported,
* returns a plain dynamic buffer.
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
#endif
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
duk__decode_context *dec_ctx;
duk_bool_t fatal = 0;
duk_bool_t ignore_bom = 0;
DUK_ASSERT_TOP(thr, 2);
duk_require_constructor_call(thr);
if (!duk_is_undefined(thr, 0)) {
/* XXX: For now ignore 'label' (encoding identifier). */
duk_to_string(thr, 0);
}
if (!duk_is_null_or_undefined(thr, 1)) {
if (duk_get_prop_literal(thr, 1, "fatal")) {
fatal = duk_to_boolean(thr, -1);
}
if (duk_get_prop_literal(thr, 1, "ignoreBOM")) {
ignore_bom = duk_to_boolean(thr, -1);
}
}
duk_push_this(thr);
/* The decode context is not assumed to be zeroed; all fields are
* initialized explicitly.
*/
dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context));
dec_ctx->fatal = (duk_uint8_t) fatal;
dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom;
duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */
duk_put_prop_literal(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
return 0;
}
/* Get TextDecoder context from 'this'; leaves garbage on stack. */
DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) {
duk__decode_context *dec_ctx;
duk_push_this(thr);
duk_get_prop_literal(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL);
DUK_ASSERT(dec_ctx != NULL);
return dec_ctx;
}
DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) {
duk__decode_context *dec_ctx;
duk_int_t magic;
dec_ctx = duk__get_textdecoder_context(thr);
magic = duk_get_current_magic(thr);
switch (magic) {
case 0:
/* Encoding is now fixed, so _Context lookup is only needed to
* validate the 'this' binding (TypeError if not TextDecoder-like).
*/
duk_push_literal(thr, "utf-8");
break;
case 1:
duk_push_boolean(thr, dec_ctx->fatal);
break;
default:
duk_push_boolean(thr, dec_ctx->ignore_bom);
break;
}
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) {
duk__decode_context *dec_ctx;
dec_ctx = duk__get_textdecoder_context(thr);
return duk__decode_helper(thr, dec_ctx);
}
#endif /* DUK_USE_ENCODING_BUILTINS */
/*
* Internal helper for Node.js Buffer
*/
/* Internal helper used for Node.js Buffer .toString(). Value stack convention
* is currently odd: it mimics TextDecoder .decode() so that argument must be at
* index 0, and decode options (not present for Buffer) at index 1. Return value
* is a Duktape/C function return value.
*/
DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) {
duk__decode_context dec_ctx;
dec_ctx.fatal = 0; /* use replacement chars */
dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */
duk__utf8_decode_init(&dec_ctx);
return duk__decode_helper(thr, &dec_ctx);
}

View file

@ -1,387 +0,0 @@
/*
* Error built-ins
*/
#include "third_party/duktape/duk_internal.h"
DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) {
/* Behavior for constructor and non-constructor call is
* the same except for augmenting the created error. When
* called as a constructor, the caller (duk_new()) will handle
* augmentation; when called as normal function, we need to do
* it here.
*/
duk_small_int_t bidx_prototype = duk_get_current_magic(thr);
/* same for both error and each subclass like TypeError */
duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
(void) duk_push_object_helper(thr, flags_and_class, bidx_prototype);
/* If message is undefined, the own property 'message' is not set at
* all to save property space. An empty message is inherited anyway.
*/
if (!duk_is_undefined(thr, 0)) {
duk_to_string(thr, 0);
duk_dup_0(thr); /* [ message error message ] */
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
}
/* Augment the error if called as a normal function. __FILE__ and __LINE__
* are not desirable in this case.
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
if (!duk_is_constructor_call(thr)) {
duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE);
}
#endif
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
/* XXX: optimize with more direct internal access */
duk_push_this(thr);
(void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
/* [ ... this ] */
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
if (duk_is_undefined(thr, -1)) {
duk_pop(thr);
duk_push_literal(thr, "Error");
} else {
duk_to_string(thr, -1);
}
/* [ ... this name ] */
/* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
* accident or are they actually needed? The first ToString()
* could conceivably return 'undefined'.
*/
duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
if (duk_is_undefined(thr, -1)) {
duk_pop(thr);
duk_push_hstring_empty(thr);
} else {
duk_to_string(thr, -1);
}
/* [ ... this name message ] */
if (duk_get_length(thr, -2) == 0) {
/* name is empty -> return message */
return 1;
}
if (duk_get_length(thr, -1) == 0) {
/* message is empty -> return name */
duk_pop(thr);
return 1;
}
duk_push_literal(thr, ": ");
duk_insert(thr, -2); /* ... name ': ' message */
duk_concat(thr, 3);
return 1;
}
#if defined(DUK_USE_TRACEBACKS)
/*
* Traceback handling
*
* The unified helper decodes the traceback and produces various requested
* outputs. It should be optimized for size, and may leave garbage on stack,
* only the topmost return value matters. For instance, traceback separator
* and decoded strings are pushed even when looking for filename only.
*
* NOTE: although _Tracedata is an internal property, user code can currently
* write to the array (or replace it with something other than an array).
* The code below must tolerate arbitrary _Tracedata. It can throw errors
* etc, but cannot cause a segfault or memory unsafe behavior.
*/
/* constants arbitrary, chosen for small loads */
#define DUK__OUTPUT_TYPE_TRACEBACK (-1)
#define DUK__OUTPUT_TYPE_FILENAME 0
#define DUK__OUTPUT_TYPE_LINENUMBER 1
DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) {
duk_idx_t idx_td;
duk_small_int_t i; /* traceback depth fits into 16 bits */
duk_small_int_t t; /* stack type fits into 16 bits */
duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */
const char *str_tailcall = " tailcall";
const char *str_strict = " strict";
const char *str_construct = " construct";
const char *str_prevyield = " preventsyield";
const char *str_directeval = " directeval";
const char *str_empty = "";
DUK_ASSERT_TOP(thr, 0); /* fixed arg count */
duk_push_this(thr);
duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA);
idx_td = duk_get_top_index(thr);
duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE);
duk_push_this(thr);
/* [ ... this tracedata sep this ] */
/* XXX: skip null filename? */
if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) {
/* Current tracedata contains 2 entries per callstack entry. */
for (i = 0; ; i += 2) {
duk_int_t pc;
duk_uint_t line;
duk_uint_t flags;
duk_double_t d;
const char *funcname;
const char *filename;
duk_hobject *h_func;
duk_hstring *h_name;
duk_require_stack(thr, 5);
duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i);
duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1));
d = duk_to_number_m1(thr);
pc = duk_double_to_int_t(DUK_FMOD(d, DUK_DOUBLE_2TO32));
flags = duk_double_to_uint_t(DUK_FLOOR(d / DUK_DOUBLE_2TO32));
t = (duk_small_int_t) duk_get_type(thr, -2);
if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
/*
* ECMAScript/native function call or lightfunc call
*/
count_func++;
/* [ ... v1(func) v2(pc+flags) ] */
/* These may be systematically omitted by Duktape
* with certain config options, but allow user to
* set them on a case-by-case basis.
*/
duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME);
#if defined(DUK_USE_PC2LINE)
line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc);
#else
line = 0;
#endif
/* [ ... v1 v2 name filename ] */
/* When looking for .fileName/.lineNumber, blame first
* function which has a .fileName.
*/
if (duk_is_string_notsymbol(thr, -1)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
duk_push_uint(thr, line);
return 1;
}
}
/* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
/* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
h_name = duk_get_hstring_notsymbol(thr, -2); /* may be NULL */
funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
"[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
filename = duk_get_string_notsymbol(thr, -1);
filename = filename ? filename : "";
DUK_ASSERT(funcname != NULL);
DUK_ASSERT(filename != NULL);
h_func = duk_get_hobject(thr, -4); /* NULL for lightfunc */
if (h_func == NULL) {
duk_push_sprintf(thr, "at %s light%s%s%s%s%s",
(const char *) funcname,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
} else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
} else {
duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s",
(const char *) funcname,
(const char *) filename,
(unsigned long) line,
(const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
(const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
}
duk_replace(thr, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
duk_pop_3(thr); /* -> [ ... str ] */
} else if (t == DUK_TYPE_STRING) {
const char *str_file;
/*
* __FILE__ / __LINE__ entry, here 'pc' is line number directly.
* Sometimes __FILE__ / __LINE__ is reported as the source for
* the error (fileName, lineNumber), sometimes not.
*/
/* [ ... v1(filename) v2(line+flags) ] */
/* When looking for .fileName/.lineNumber, blame compilation
* or C call site unless flagged not to do so.
*/
if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
duk_pop(thr);
return 1;
} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
duk_push_int(thr, pc);
return 1;
}
}
/* Tracedata is trusted but avoid any risk of using a NULL
* for %s format because it has undefined behavior. Symbols
* don't need to be explicitly rejected as they pose no memory
* safety issues.
*/
str_file = (const char *) duk_get_string(thr, -2);
duk_push_sprintf(thr, "at [anon] (%s:%ld) internal",
(const char *) (str_file ? str_file : "null"), (long) pc);
duk_replace(thr, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
duk_pop(thr); /* -> [ ... str ] */
} else {
/* unknown, ignore */
duk_pop_2(thr);
break;
}
}
if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
/* Possibly truncated; there is no explicit truncation
* marker so this is the best we can do.
*/
duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS);
}
}
/* [ ... this tracedata sep this str1 ... strN ] */
if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
return 0;
} else {
/* The 'this' after 'sep' will get ToString() coerced by
* duk_join() automatically. We don't want to do that
* coercion when providing .fileName or .lineNumber (GH-254).
*/
duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/);
return 1;
}
}
/* XXX: Output type could be encoded into native function 'magic' value to
* save space. For setters the stridx could be encoded into 'magic'.
*/
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER);
}
#else /* DUK_USE_TRACEBACKS */
/*
* Traceback handling when tracebacks disabled.
*
* The fileName / lineNumber stubs are now necessary because built-in
* data will include the accessor properties in Error.prototype. If those
* are removed for builds without tracebacks, these can also be removed.
* 'stack' should still be present and produce a ToString() equivalent:
* this is useful for user code which prints a stacktrace and expects to
* see something useful. A normal stacktrace also begins with a ToString()
* of the error so this makes sense.
*/
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
/* XXX: remove this native function and map 'stack' accessor
* to the toString() implementation directly.
*/
return duk_bi_error_prototype_to_string(thr);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
DUK_UNREF(thr);
return 0;
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
DUK_UNREF(thr);
return 0;
}
#endif /* DUK_USE_TRACEBACKS */
DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, duk_small_uint_t stridx_key) {
/* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
* user code called Object.defineProperty() to create an overriding
* own property. This allows user code to overwrite .fileName etc
* intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
* See https://github.com/svaarala/duktape/issues/387.
*/
DUK_ASSERT_TOP(thr, 1); /* fixed arg count: value */
duk_push_this(thr);
duk_push_hstring_stridx(thr, stridx_key);
duk_dup_0(thr);
/* [ ... obj key value ] */
DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
duk_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1)));
duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
return 0;
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_hthread *thr) {
return duk__error_setter_helper(thr, DUK_STRIDX_STACK);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_hthread *thr) {
return duk__error_setter_helper(thr, DUK_STRIDX_FILE_NAME);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) {
return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER);
}

View file

@ -1,453 +0,0 @@
/*
* Function built-ins
*/
#include "third_party/duktape/duk_internal.h"
/* Needed even when Function built-in is disabled. */
DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) {
/* ignore arguments, return undefined (E5 Section 15.3.4) */
DUK_UNREF(thr);
return 0;
}
#if defined(DUK_USE_FUNCTION_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
duk_hstring *h_sourcecode;
duk_idx_t nargs;
duk_idx_t i;
duk_small_uint_t comp_flags;
duk_hcompfunc *func;
duk_hobject *outer_lex_env;
duk_hobject *outer_var_env;
/* normal and constructor calls have identical semantics */
nargs = duk_get_top(thr);
for (i = 0; i < nargs; i++) {
duk_to_string(thr, i); /* Rejects Symbols during coercion. */
}
if (nargs == 0) {
duk_push_hstring_empty(thr);
duk_push_hstring_empty(thr);
} else if (nargs == 1) {
/* XXX: cover this with the generic >1 case? */
duk_push_hstring_empty(thr);
} else {
duk_insert(thr, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
duk_push_literal(thr, ",");
duk_insert(thr, 1);
duk_join(thr, nargs - 1);
}
/* [ body formals ], formals is comma separated list that needs to be parsed */
DUK_ASSERT_TOP(thr, 2);
/* XXX: this placeholder is not always correct, but use for now.
* It will fail in corner cases; see test-dev-func-cons-args.js.
*/
duk_push_literal(thr, "function(");
duk_dup_1(thr);
duk_push_literal(thr, "){");
duk_dup_0(thr);
duk_push_literal(thr, "\n}"); /* Newline is important to handle trailing // comment. */
duk_concat(thr, 5);
/* [ body formals source ] */
DUK_ASSERT_TOP(thr, 3);
/* strictness is not inherited, intentional */
comp_flags = DUK_COMPILE_FUNCEXPR;
duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
h_sourcecode = duk_require_hstring(thr, -2); /* no symbol check needed; -2 is concat'd code */
duk_js_compile(thr,
(const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
(duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
comp_flags);
/* Force .name to 'anonymous' (ES2015). */
duk_push_literal(thr, "anonymous");
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func));
/* [ body formals source template ] */
/* only outer_lex_env matters, as functions always get a new
* variable declaration environment.
*/
outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
/* [ body formals source template closure ] */
return 1;
}
#endif /* DUK_USE_FUNCTION_BUILTIN */
#if defined(DUK_USE_FUNCTION_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
/*
* E5 Section 15.3.4.2 places few requirements on the output of
* this function: the result is implementation dependent, must
* follow FunctionDeclaration syntax (in particular, must have a
* name even for anonymous functions or functions with empty name).
* The output does NOT need to compile into anything useful.
*
* E6 Section 19.2.3.5 changes the requirements completely: the
* result must either eval() to a functionally equivalent object
* OR eval() to a SyntaxError.
*
* We opt for the SyntaxError approach for now, with a syntax that
* mimics V8's native function syntax:
*
* 'function cos() { [native code] }'
*
* but extended with [ecmascript code], [bound code], and
* [lightfunc code].
*/
duk_push_this(thr);
tv = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
const char *func_name;
/* Function name: missing/undefined is mapped to empty string,
* otherwise coerce to string. No handling for invalid identifier
* characters or e.g. '{' in the function name. This doesn't
* really matter as long as a SyntaxError results. Technically
* if the name contained a suitable prefix followed by '//' it
* might cause the result to parse without error.
*/
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
if (duk_is_undefined(thr, -1)) {
func_name = "";
} else {
func_name = duk_to_string(thr, -1);
DUK_ASSERT(func_name != NULL);
}
if (DUK_HOBJECT_IS_COMPFUNC(obj)) {
duk_push_sprintf(thr, "function %s() { [ecmascript code] }", (const char *) func_name);
} else if (DUK_HOBJECT_IS_NATFUNC(obj)) {
duk_push_sprintf(thr, "function %s() { [native code] }", (const char *) func_name);
} else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) {
duk_push_sprintf(thr, "function %s() { [bound code] }", (const char *) func_name);
} else {
goto type_error;
}
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
duk_push_lightfunc_tostring(thr, tv);
} else {
goto type_error;
}
return 1;
type_error:
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
#endif
/* Always present because the native function pointer is needed in call
* handling.
*/
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) {
/* .call() is dealt with in call handling by simulating its
* effects so this function is actually never called.
*/
DUK_UNREF(thr);
return DUK_RET_TYPE_ERROR;
}
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) {
/* Like .call(), never actually called. */
DUK_UNREF(thr);
return DUK_RET_TYPE_ERROR;
}
DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) {
/* Like .call(), never actually called. */
DUK_UNREF(thr);
return DUK_RET_TYPE_ERROR;
}
DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) {
/* Like .call(), never actually called. */
DUK_UNREF(thr);
return DUK_RET_TYPE_ERROR;
}
#if defined(DUK_USE_FUNCTION_BUILTIN)
/* Create a bound function which points to a target function which may
* be bound or non-bound. If the target is bound, the argument lists
* and 'this' binding of the functions are merged and the resulting
* function points directly to the non-bound target.
*/
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
duk_hboundfunc *h_bound;
duk_idx_t nargs; /* bound args, not counting 'this' binding */
duk_idx_t bound_nargs;
duk_int_t bound_len;
duk_tval *tv_prevbound;
duk_idx_t n_prevbound;
duk_tval *tv_res;
duk_tval *tv_tmp;
/* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */
/* Vararg function, careful arg handling, e.g. thisArg may not
* be present.
*/
nargs = duk_get_top(thr) - 1; /* actual args, not counting 'this' binding */
if (nargs < 0) {
nargs++;
duk_push_undefined(thr);
}
DUK_ASSERT(nargs >= 0);
/* Limit 'nargs' for bound functions to guarantee arithmetic
* below will never wrap.
*/
if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
DUK_DCERROR_RANGE_INVALID_COUNT(thr);
}
duk_push_this(thr);
duk_require_callable(thr, -1);
/* [ thisArg arg1 ... argN func ] (thisArg+args == nargs+1 total) */
DUK_ASSERT_TOP(thr, nargs + 2);
/* Create bound function object. */
h_bound = duk_push_hboundfunc(thr);
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target));
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding));
DUK_ASSERT(h_bound->args == NULL);
DUK_ASSERT(h_bound->nargs == 0);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL);
/* [ thisArg arg1 ... argN func boundFunc ] */
/* If the target is a bound function, argument lists must be
* merged. The 'this' binding closest to the target function
* wins because in call handling the 'this' gets replaced over
* and over again until we call the non-bound function.
*/
tv_prevbound = NULL;
n_prevbound = 0;
tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0);
DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp);
tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2);
DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp);
if (DUK_TVAL_IS_OBJECT(tv_tmp)) {
duk_hobject *h_target;
duk_hobject *bound_proto;
h_target = DUK_TVAL_GET_OBJECT(tv_tmp);
DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target));
/* Internal prototype must be copied from the target.
* For lightfuncs Function.prototype is used and is already
* in place.
*/
bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target);
DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
/* The 'strict' flag is copied to get the special [[Get]] of E5.1
* Section 15.3.5.4 to apply when a 'caller' value is a strict bound
* function. Not sure if this is correct, because the specification
* is a bit ambiguous on this point but it would make sense.
*/
/* Strictness is inherited from target. */
if (DUK_HOBJECT_HAS_STRICT(h_target)) {
DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
}
if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) {
duk_hboundfunc *h_boundtarget;
h_boundtarget = (duk_hboundfunc *) (void *) h_target;
/* The final function should always be non-bound, unless
* there's a bug in the internals. Assert for it.
*/
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) ||
(DUK_TVAL_IS_OBJECT(&h_boundtarget->target) &&
DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) &&
!DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target))));
DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target);
DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding);
tv_prevbound = h_boundtarget->args;
n_prevbound = h_boundtarget->nargs;
}
} else {
/* Lightfuncs are always strict. */
duk_hobject *bound_proto;
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
}
DUK_TVAL_INCREF(thr, &h_bound->target); /* old values undefined, no decref needed */
DUK_TVAL_INCREF(thr, &h_bound->this_binding);
bound_nargs = n_prevbound + nargs;
if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
DUK_DCERROR_RANGE_INVALID_COUNT(thr);
}
tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval));
DUK_ASSERT(tv_res != NULL || bound_nargs == 0);
DUK_ASSERT(h_bound->args == NULL);
DUK_ASSERT(h_bound->nargs == 0);
h_bound->args = tv_res;
h_bound->nargs = bound_nargs;
DUK_ASSERT(n_prevbound >= 0);
duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound);
DUK_ASSERT(nargs >= 0);
duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs);
/* [ thisArg arg1 ... argN func boundFunc ] */
/* Bound function 'length' property is interesting.
* For lightfuncs, simply read the virtual property.
*/
duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH);
bound_len = duk_get_int(thr, -1); /* ES2015: no coercion */
if (bound_len < nargs) {
bound_len = 0;
} else {
bound_len -= nargs;
}
if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) {
bound_len = (duk_int_t) DUK_UINT32_MAX;
}
duk_pop(thr);
DUK_ASSERT(bound_len >= 0);
tv_tmp = thr->valstack_top++;
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp));
DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp));
DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len); /* in-place update, fastint */
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */
/* XXX: could these be virtual? */
/* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */
duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER);
duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS);
/* Function name and fileName (non-standard). */
duk_push_literal(thr, "bound "); /* ES2015 19.2.3.2. */
duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME);
if (!duk_is_string_notsymbol(thr, -1)) {
/* ES2015 has requirement to check that .name of target is a string
* (also must check for Symbol); if not, targetName should be the
* empty string. ES2015 19.2.3.2.
*/
duk_pop(thr);
duk_push_hstring_empty(thr);
}
duk_concat(thr, 2);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
#endif
DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
return 1;
}
#endif /* DUK_USE_FUNCTION_BUILTIN */
/* %NativeFunctionPrototype% .length getter. */
DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) {
duk_tval *tv;
duk_hnatfunc *h;
duk_int16_t func_nargs;
tv = duk_get_borrowed_this_tval(thr);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
goto fail_type;
}
func_nargs = h->nargs;
duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
duk_small_uint_t lf_flags;
duk_small_uint_t lf_len;
lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
duk_push_uint(thr, lf_len);
} else {
goto fail_type;
}
return 1;
fail_type:
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* %NativeFunctionPrototype% .name getter. */
DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) {
duk_tval *tv;
duk_hnatfunc *h;
tv = duk_get_borrowed_this_tval(thr);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_OBJECT(tv)) {
h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
goto fail_type;
}
#if 0
duk_push_hnatfunc_name(thr, h);
#endif
duk_push_hstring_empty(thr);
} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
duk_push_lightfunc_name(thr, tv);
} else {
goto fail_type;
}
return 1;
fail_type:
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
#if defined(DUK_USE_SYMBOL_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_hasinstance(duk_hthread *thr) {
/* This binding: RHS, stack index 0: LHS. */
duk_bool_t ret;
ret = duk_js_instanceof_ordinary(thr, DUK_GET_TVAL_POSIDX(thr, 0), DUK_GET_THIS_TVAL_PTR(thr));
duk_push_boolean(thr, ret);
return 1;
}
#endif /* DUK_USE_SYMBOL_BUILTIN */

View file

@ -1,785 +0,0 @@
/*
* Global object built-ins
*/
#include "third_party/duktape/duk_internal.h"
/*
* Encoding/decoding helpers
*/
/* XXX: Could add fast path (for each transform callback) with direct byte
* lookups (no shifting) and no explicit check for x < 0x80 before table
* lookup.
*/
/* Macros for creating and checking bitmasks for character encoding.
* Bit number is a bit counterintuitive, but minimizes code size.
*/
#define DUK__MKBITS(a, b, c, d, e, f, g, h) \
((duk_uint8_t)(((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7)))
#define DUK__CHECK_BITMASK(table, cp) ((table)[(cp) >> 3] & (1u << ((cp)&0x07)))
/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
};
/* E5.1 Section 15.1.3.4: uriUnescaped */
DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1),
DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
};
/* E5.1 Section 15.1.3.1: uriReserved + '#' */
DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0),
DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
};
/* E5.1 Section 15.1.3.2: empty */
DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
};
#if defined(DUK_USE_SECTION_B)
/* E5.1 Section B.2.2, step 7. */
DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),
DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),
DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */
};
#endif /* DUK_USE_SECTION_B */
typedef struct {
duk_hthread *thr;
duk_hstring *h_str;
duk_bufwriter_ctx bw;
const duk_uint8_t *p;
const duk_uint8_t *p_start;
const duk_uint8_t *p_end;
} duk__transform_context;
typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx,
const void *udata, duk_codepoint_t cp);
/* XXX: refactor and share with other code */
DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p,
duk_small_int_t n) {
duk_small_int_t ch;
duk_small_int_t t = 0;
while (n > 0) {
t = t * 16;
ch = (duk_small_int_t)duk_hex_dectab[*p++];
if (DUK_LIKELY(ch >= 0)) {
t += ch;
} else {
return -1;
}
n--;
}
return t;
}
DUK_LOCAL int duk__transform_helper(duk_hthread *thr,
duk__transform_callback callback,
const void *udata) {
duk__transform_context tfm_ctx_alloc;
duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
duk_codepoint_t cp;
tfm_ctx->thr = thr;
tfm_ctx->h_str = duk_to_hstring(thr, 0);
DUK_ASSERT(tfm_ctx->h_str != NULL);
DUK_BW_INIT_PUSHBUF(
thr, &tfm_ctx->bw,
DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
tfm_ctx->p = tfm_ctx->p_start;
while (tfm_ctx->p < tfm_ctx->p_end) {
cp = (duk_codepoint_t)duk_unicode_decode_xutf8_checked(
thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
callback(tfm_ctx, udata, cp);
}
DUK_BW_COMPACT(thr, &tfm_ctx->bw);
(void)duk_buffer_to_string(thr, -1); /* Safe if transform is safe. */
return 1;
}
DUK_LOCAL void duk__transform_callback_encode_uri(
duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
duk_small_int_t len;
duk_codepoint_t cp1, cp2;
duk_small_int_t i, t;
const duk_uint8_t *unescaped_table = (const duk_uint8_t *)udata;
/* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
* Codepoint range is restricted so this is a slightly too large
* but doesn't matter.
*/
DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH);
if (cp < 0) {
goto uri_error;
} else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t)cp);
return;
} else if (cp >= 0xdc00L && cp <= 0xdfffL) {
goto uri_error;
} else if (cp >= 0xd800L && cp <= 0xdbffL) {
/* Needs lookahead */
if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start,
tfm_ctx->p_end,
(duk_ucodepoint_t *)&cp2) == 0) {
goto uri_error;
}
if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
goto uri_error;
}
cp1 = cp;
cp =
(duk_codepoint_t)(((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L);
} else if (cp > 0x10ffffL) {
/* Although we can allow non-BMP characters (they'll decode
* back into surrogate pairs), we don't allow extended UTF-8
* characters; they would encode to URIs which won't decode
* back because of strict UTF-8 checks in URI decoding.
* (However, we could just as well allow them here.)
*/
goto uri_error;
} else {
/* Non-BMP characters within valid UTF-8 range: encode as is.
* They'll decode back into surrogate pairs if the escaped
* output is decoded.
*/
;
}
len = duk_unicode_encode_xutf8((duk_ucodepoint_t)cp, xutf8_buf);
for (i = 0; i < len; i++) {
t = (duk_small_int_t)xutf8_buf[i];
DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, &tfm_ctx->bw, DUK_ASC_PERCENT,
(duk_uint8_t)duk_uc_nybbles[t >> 4],
(duk_uint8_t)duk_uc_nybbles[t & 0x0f]);
}
return;
uri_error:
DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
DUK_WO_NORETURN(return;);
}
DUK_LOCAL void duk__transform_callback_decode_uri(
duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
const duk_uint8_t *reserved_table = (const duk_uint8_t *)udata;
duk_small_uint_t utf8_blen;
duk_codepoint_t min_cp;
duk_small_int_t t; /* must be signed */
duk_small_uint_t i;
/* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
* percent escape path writes max two times CESU-8 encoded BMP length.
*/
DUK_BW_ENSURE(
tfm_ctx->thr, &tfm_ctx->bw,
(DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH
? DUK_UNICODE_MAX_XUTF8_LENGTH
: DUK_UNICODE_MAX_CESU8_BMP_LENGTH));
if (cp == (duk_codepoint_t)'%') {
const duk_uint8_t *p = tfm_ctx->p;
duk_size_t left = (duk_size_t)(tfm_ctx->p_end - p); /* bytes left */
DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long)left));
if (left < 2) {
goto uri_error;
}
t = duk__decode_hex_escape(p, 2);
DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long)t));
if (t < 0) {
goto uri_error;
}
if (t < 0x80) {
if (DUK__CHECK_BITMASK(reserved_table, t)) {
/* decode '%xx' to '%xx' if decoded char in reserved set */
DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, &tfm_ctx->bw, DUK_ASC_PERCENT, p[0],
p[1]);
} else {
DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t)t);
}
tfm_ctx->p += 2;
return;
}
/* Decode UTF-8 codepoint from a sequence of hex escapes. The
* first byte of the sequence has been decoded to 't'.
*
* Note that UTF-8 validation must be strict according to the
* specification: E5.1 Section 15.1.3, decode algorithm step
* 4.d.vii.8. URIError from non-shortest encodings is also
* specifically noted in the spec.
*/
DUK_ASSERT(t >= 0x80);
if (t < 0xc0) {
/* continuation byte */
goto uri_error;
} else if (t < 0xe0) {
/* 110x xxxx; 2 bytes */
utf8_blen = 2;
min_cp = 0x80L;
cp = t & 0x1f;
} else if (t < 0xf0) {
/* 1110 xxxx; 3 bytes */
utf8_blen = 3;
min_cp = 0x800L;
cp = t & 0x0f;
} else if (t < 0xf8) {
/* 1111 0xxx; 4 bytes */
utf8_blen = 4;
min_cp = 0x10000L;
cp = t & 0x07;
} else {
/* extended utf-8 not allowed for URIs */
goto uri_error;
}
if (left < utf8_blen * 3 - 1) {
/* '%xx%xx...%xx', p points to char after first '%' */
goto uri_error;
}
p += 3;
for (i = 1; i < utf8_blen; i++) {
/* p points to digit part ('%xy', p points to 'x') */
t = duk__decode_hex_escape(p, 2);
DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx", (long)i,
(long)utf8_blen, (long)cp, (unsigned long)t));
if (t < 0) {
goto uri_error;
}
if ((t & 0xc0) != 0x80) {
goto uri_error;
}
cp = (cp << 6) + (t & 0x3f);
p += 3;
}
p--; /* p overshoots */
tfm_ctx->p = p;
DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long)cp, (long)min_cp));
if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
goto uri_error;
}
/* The E5.1 algorithm checks whether or not a decoded codepoint
* is below 0x80 and perhaps may be in the "reserved" set.
* This seems pointless because the single byte UTF-8 case is
* handled separately, and non-shortest encodings are rejected.
* So, 'cp' cannot be below 0x80 here, and thus cannot be in
* the reserved set.
*/
/* utf-8 validation ensures these */
DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
if (cp >= 0x10000L) {
cp -= 0x10000L;
DUK_ASSERT(cp < 0x100000L);
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw,
((cp >> 10) + 0xd800L));
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw,
((cp & 0x03ffL) + 0xdc00L));
} else {
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
}
} else {
DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
}
return;
uri_error:
DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
DUK_WO_NORETURN(return;);
}
#if defined(DUK_USE_SECTION_B)
DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx,
const void *udata,
duk_codepoint_t cp) {
DUK_UNREF(udata);
DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
if (cp < 0) {
goto esc_error;
} else if ((cp < 0x80L) &&
DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t)cp);
} else if (cp < 0x100L) {
DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr, &tfm_ctx->bw,
(duk_uint8_t)DUK_ASC_PERCENT,
(duk_uint8_t)duk_uc_nybbles[cp >> 4],
(duk_uint8_t)duk_uc_nybbles[cp & 0x0f]);
} else if (cp < 0x10000L) {
DUK_BW_WRITE_RAW_U8_6(
tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t)DUK_ASC_PERCENT,
(duk_uint8_t)DUK_ASC_LC_U, (duk_uint8_t)duk_uc_nybbles[cp >> 12],
(duk_uint8_t)duk_uc_nybbles[(cp >> 8) & 0x0f],
(duk_uint8_t)duk_uc_nybbles[(cp >> 4) & 0x0f],
(duk_uint8_t)duk_uc_nybbles[cp & 0x0f]);
} else {
/* Characters outside BMP cannot be escape()'d. We could
* encode them as surrogate pairs (for codepoints inside
* valid UTF-8 range, but not extended UTF-8). Because
* escape() and unescape() are legacy functions, we don't.
*/
goto esc_error;
}
return;
esc_error:
DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
DUK_WO_NORETURN(return;);
}
DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx,
const void *udata,
duk_codepoint_t cp) {
duk_small_int_t t;
DUK_UNREF(udata);
if (cp == (duk_codepoint_t)'%') {
const duk_uint8_t *p = tfm_ctx->p;
duk_size_t left = (duk_size_t)(tfm_ctx->p_end - p); /* bytes left */
if (left >= 5 && p[0] == 'u' &&
((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
cp = (duk_codepoint_t)t;
tfm_ctx->p += 5;
} else if (left >= 2 && ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
cp = (duk_codepoint_t)t;
tfm_ctx->p += 2;
}
}
DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
}
#endif /* DUK_USE_SECTION_B */
/*
* Eval
*
* Eval needs to handle both a "direct eval" and an "indirect eval".
* Direct eval handling needs access to the caller's activation so that its
* lexical environment can be accessed. A direct eval is only possible from
* ECMAScript code; an indirect eval call is possible also from C code.
* When an indirect eval call is made from C code, there may not be a
* calling activation at all which needs careful handling.
*/
DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) {
duk_hstring *h;
duk_activation *act_caller;
duk_activation *act_eval;
duk_hcompfunc *func;
duk_hobject *outer_lex_env;
duk_hobject *outer_var_env;
duk_bool_t this_to_global = 1;
duk_small_uint_t comp_flags;
duk_int_t level = -2;
duk_small_uint_t call_flags;
DUK_ASSERT(duk_get_top(thr) == 1 ||
duk_get_top(thr) == 2); /* 2 when called by debugger */
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
DUK_ASSERT(thr->callstack_curr != NULL);
DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) ==
0 || /* indirect eval */
(thr->callstack_top >=
2)); /* if direct eval, calling activation must exist */
/*
* callstack_top - 1 --> this function
* callstack_top - 2 --> caller (may not exist)
*
* If called directly from C, callstack_top might be 1. If calling
* activation doesn't exist, call must be indirect.
*/
h = duk_get_hstring_notsymbol(thr, 0);
if (!h) {
/* Symbol must be returned as is, like any non-string values. */
return 1; /* return arg as-is */
}
#if defined(DUK_USE_DEBUGGER_SUPPORT)
/* NOTE: level is used only by the debugger and should never be present
* for an ECMAScript eval().
*/
DUK_ASSERT(level == -2); /* by default, use caller's environment */
if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) {
level = duk_get_int(thr, 1);
}
DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
#endif
/* [ source ] */
comp_flags = DUK_COMPILE_EVAL;
act_eval = thr->callstack_curr; /* this function */
DUK_ASSERT(act_eval != NULL);
act_caller = duk_hthread_get_activation_for_level(thr, level);
if (act_caller != NULL) {
/* Have a calling activation, check for direct eval (otherwise
* assume indirect eval.
*/
if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
(act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
/* Only direct eval inherits strictness from calling code
* (E5.1 Section 10.1.1).
*/
comp_flags |= DUK_COMPILE_STRICT;
}
} else {
DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
}
duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
duk_js_compile(thr, (const duk_uint8_t *)DUK_HSTRING_GET_DATA(h),
(duk_size_t)DUK_HSTRING_GET_BYTELEN(h), comp_flags);
func = (duk_hcompfunc *)duk_known_hobject(thr, -1);
DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *)func));
/* [ source template ] */
/* E5 Section 10.4.2 */
if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
DUK_ASSERT(thr->callstack_top >= 2);
DUK_ASSERT(act_caller != NULL);
if (act_caller->lex_env == NULL) {
DUK_ASSERT(act_caller->var_env == NULL);
DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
/* this may have side effects, so re-lookup act */
duk_js_init_activation_environment_records_delayed(thr, act_caller);
}
DUK_ASSERT(act_caller->lex_env != NULL);
DUK_ASSERT(act_caller->var_env != NULL);
this_to_global = 0;
if (DUK_HOBJECT_HAS_STRICT((duk_hobject *)func)) {
duk_hdecenv *new_env;
duk_hobject *act_lex_env;
DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
"var_env and lex_env to a fresh env, "
"this_binding to caller's this_binding"));
act_lex_env = act_caller->lex_env;
new_env = duk_hdecenv_alloc(
thr, DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
DUK_ASSERT(new_env != NULL);
duk_push_hobject(thr, (duk_hobject *)new_env);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *)new_env) ==
NULL);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *)new_env, act_lex_env);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, act_lex_env);
DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *)new_env));
outer_lex_env = (duk_hobject *)new_env;
outer_var_env = (duk_hobject *)new_env;
duk_insert(thr, 0); /* stash to bottom of value stack to keep new_env
reachable for duration of eval */
/* compiler's responsibility */
DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *)func));
} else {
DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
"var_env and lex_env to caller's envs, "
"this_binding to caller's this_binding"));
outer_lex_env = act_caller->lex_env;
outer_var_env = act_caller->var_env;
/* compiler's responsibility */
DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *)func));
}
} else {
DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
"global object, this_binding to global object"));
this_to_global = 1;
outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
}
/* Eval code doesn't need an automatic .prototype object. */
duk_js_push_closure(thr, func, outer_var_env, outer_lex_env,
0 /*add_auto_proto*/);
/* [ env? source template closure ] */
if (this_to_global) {
DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
} else {
duk_tval *tv;
DUK_ASSERT(thr->callstack_top >= 2);
DUK_ASSERT(act_caller != NULL);
tv = (duk_tval *)(void *)((duk_uint8_t *)thr->valstack +
act_caller->bottom_byteoff -
sizeof(
duk_tval)); /* this is just beneath bottom */
DUK_ASSERT(tv >= thr->valstack);
duk_push_tval(thr, tv);
}
DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
(duk_heaphdr *)outer_lex_env,
(duk_heaphdr *)outer_var_env, duk_get_tval(thr, -1)));
/* [ env? source template closure this ] */
call_flags = 0;
if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
/* Set DIRECT_EVAL flag for the call; it's not strictly
* needed for the 'inner' eval call (the eval body) but
* current new.target implementation expects to find it
* so it can traverse direct eval chains up to the real
* calling function.
*/
call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
}
duk_handle_call_unprotected_nargs(thr, 0, call_flags);
/* [ env? source template result ] */
return 1;
}
/*
* Parsing of ints and floats
*/
#if defined(DUK_USE_GLOBAL_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) {
duk_int32_t radix;
duk_small_uint_t s2n_flags;
DUK_ASSERT_TOP(thr, 2);
duk_to_string(thr, 0); /* Reject symbols. */
radix = duk_to_int32(thr, 1);
/* While parseInt() recognizes 0xdeadbeef, it doesn't recognize
* ES2015 0o123 or 0b10001.
*/
s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | DUK_S2N_FLAG_ALLOW_GARBAGE |
DUK_S2N_FLAG_ALLOW_PLUS | DUK_S2N_FLAG_ALLOW_MINUS |
DUK_S2N_FLAG_ALLOW_LEADING_ZERO | DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
/* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
*
* Don't autodetect octals (from leading zeroes), require user code to
* provide an explicit radix 8 for parsing octal. See write-up from Mozilla:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
*/
if (radix != 0) {
if (radix < 2 || radix > 36) {
goto ret_nan;
}
if (radix != 16) {
s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
}
} else {
radix = 10;
}
duk_dup_0(thr);
duk_numconv_parse(thr, (duk_small_int_t)radix, s2n_flags);
return 1;
ret_nan:
duk_push_nan(thr);
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
#if defined(DUK_USE_GLOBAL_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) {
duk_small_uint_t s2n_flags;
DUK_ASSERT_TOP(thr, 1);
duk_to_string(thr, 0); /* Reject symbols. */
/* XXX: check flags */
s2n_flags = DUK_S2N_FLAG_TRIM_WHITE | DUK_S2N_FLAG_ALLOW_EXP |
DUK_S2N_FLAG_ALLOW_GARBAGE | DUK_S2N_FLAG_ALLOW_PLUS |
DUK_S2N_FLAG_ALLOW_MINUS | DUK_S2N_FLAG_ALLOW_INF |
DUK_S2N_FLAG_ALLOW_FRAC | DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
DUK_S2N_FLAG_ALLOW_EMPTY_FRAC | DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
/*
* Number checkers
*/
#if defined(DUK_USE_GLOBAL_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) {
duk_double_t d = duk_to_number(thr, 0);
duk_push_boolean(thr, (duk_bool_t)DUK_ISNAN(d));
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
#if defined(DUK_USE_GLOBAL_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) {
duk_double_t d = duk_to_number(thr, 0);
duk_push_boolean(thr, (duk_bool_t)DUK_ISFINITE(d));
return 1;
}
#endif /* DUK_USE_GLOBAL_BUILTIN */
/*
* URI handling
*/
#if defined(DUK_USE_GLOBAL_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) {
return duk__transform_helper(thr, duk__transform_callback_decode_uri,
(const void *)duk__decode_uri_reserved_table);
}
DUK_INTERNAL duk_ret_t
duk_bi_global_object_decode_uri_component(duk_hthread *thr) {
return duk__transform_helper(
thr, duk__transform_callback_decode_uri,
(const void *)duk__decode_uri_component_reserved_table);
}
DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) {
return duk__transform_helper(thr, duk__transform_callback_encode_uri,
(const void *)duk__encode_uriunescaped_table);
}
DUK_INTERNAL duk_ret_t
duk_bi_global_object_encode_uri_component(duk_hthread *thr) {
return duk__transform_helper(
thr, duk__transform_callback_encode_uri,
(const void *)duk__encode_uricomponent_unescaped_table);
}
#if defined(DUK_USE_SECTION_B)
DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) {
return duk__transform_helper(thr, duk__transform_callback_escape,
(const void *)NULL);
}
DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) {
return duk__transform_helper(thr, duk__transform_callback_unescape,
(const void *)NULL);
}
#endif /* DUK_USE_SECTION_B */
#endif /* DUK_USE_GLOBAL_BUILTIN */

File diff suppressed because it is too large Load diff

View file

@ -1,519 +0,0 @@
/*
* Math built-ins
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_MATH_BUILTIN)
/*
* Use static helpers which can work with math.h functions matching
* the following signatures. This is not portable if any of these math
* functions is actually a macro.
*
* Typing here is intentionally 'double' wherever values interact with
* the standard library APIs.
*/
typedef double (*duk__one_arg_func)(double);
typedef double (*duk__two_arg_func)(double, double);
DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk__two_arg_func min_max) {
duk_idx_t n = duk_get_top(thr);
duk_idx_t i;
duk_double_t res = initial;
duk_double_t t;
/*
* Note: fmax() does not match the E5 semantics. E5 requires
* that if -any- input to Math.max() is a NaN, the result is a
* NaN. fmax() will return a NaN only if -both- inputs are NaN.
* Same applies to fmin().
*
* Note: every input value must be coerced with ToNumber(), even
* if we know the result will be a NaN anyway: ToNumber() may have
* side effects for which even order of evaluation matters.
*/
for (i = 0; i < n; i++) {
t = duk_to_number(thr, i);
if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
/* Note: not normalized, but duk_push_number() will normalize */
res = (duk_double_t) DUK_DOUBLE_NAN;
} else {
res = (duk_double_t) min_max(res, (double) t);
}
}
duk_push_number(thr, res);
return 1;
}
DUK_LOCAL double duk__fmin_fixed(double x, double y) {
/* fmin() with args -0 and +0 is not guaranteed to return
* -0 as ECMAScript requires.
*/
if (duk_double_equals(x, 0.0) && duk_double_equals(y, 0.0)) {
duk_double_union du1, du2;
du1.d = x;
du2.d = y;
/* Already checked to be zero so these must hold, and allow us
* to check for "x is -0 or y is -0" by ORing the high parts
* for comparison.
*/
DUK_ASSERT(du1.ui[DUK_DBL_IDX_UI0] == 0 || du1.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
DUK_ASSERT(du2.ui[DUK_DBL_IDX_UI0] == 0 || du2.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
/* XXX: what's the safest way of creating a negative zero? */
if ((du1.ui[DUK_DBL_IDX_UI0] | du2.ui[DUK_DBL_IDX_UI0]) != 0) {
/* Enter here if either x or y (or both) is -0. */
return -0.0;
} else {
return +0.0;
}
}
return duk_double_fmin(x, y);
}
DUK_LOCAL double duk__fmax_fixed(double x, double y) {
/* fmax() with args -0 and +0 is not guaranteed to return
* +0 as ECMAScript requires.
*/
if (duk_double_equals(x, 0.0) && duk_double_equals(y, 0.0)) {
if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
return +0.0;
} else {
return -0.0;
}
}
return duk_double_fmax(x, y);
}
#if defined(DUK_USE_ES6)
DUK_LOCAL double duk__cbrt(double x) {
/* cbrt() is C99. To avoid hassling embedders with the need to provide a
* cube root function, we can get by with pow(). The result is not
* identical, but that's OK: ES2015 says it's implementation-dependent.
*/
#if defined(DUK_CBRT)
/* cbrt() matches ES2015 requirements. */
return DUK_CBRT(x);
#else
duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
/* pow() does not, however. */
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
return x;
}
if (DUK_SIGNBIT(x)) {
return -DUK_POW(-x, 1.0 / 3.0);
} else {
return DUK_POW(x, 1.0 / 3.0);
}
#endif
}
DUK_LOCAL double duk__log2(double x) {
#if defined(DUK_LOG2)
return DUK_LOG2(x);
#else
return DUK_LOG(x) * DUK_DOUBLE_LOG2E;
#endif
}
DUK_LOCAL double duk__log10(double x) {
#if defined(DUK_LOG10)
return DUK_LOG10(x);
#else
return DUK_LOG(x) * DUK_DOUBLE_LOG10E;
#endif
}
DUK_LOCAL double duk__trunc(double x) {
#if defined(DUK_TRUNC)
return DUK_TRUNC(x);
#else
/* Handles -0 correctly: -0.0 matches 'x >= 0.0' but floor()
* is required to return -0 when the argument is -0.
*/
return x >= 0.0 ? DUK_FLOOR(x) : DUK_CEIL(x);
#endif
}
#endif /* DUK_USE_ES6 */
DUK_LOCAL double duk__round_fixed(double x) {
/* Numbers half-way between integers must be rounded towards +Infinity,
* e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero
* sign must be set appropriately. E5.1 Section 15.8.2.15.
*
* Note that ANSI C round() is "round to nearest integer, away from zero",
* which is incorrect for negative values. Here we make do with floor().
*/
duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
return x;
}
/*
* x is finite and non-zero
*
* -1.6 -> floor(-1.1) -> -2
* -1.5 -> floor(-1.0) -> -1 (towards +Inf)
* -1.4 -> floor(-0.9) -> -1
* -0.5 -> -0.0 (special case)
* -0.1 -> -0.0 (special case)
* +0.1 -> +0.0 (special case)
* +0.5 -> floor(+1.0) -> 1 (towards +Inf)
* +1.4 -> floor(+1.9) -> 1
* +1.5 -> floor(+2.0) -> 2 (towards +Inf)
* +1.6 -> floor(+2.1) -> 2
*/
if (x >= -0.5 && x < 0.5) {
/* +0.5 is handled by floor, this is on purpose */
if (x < 0.0) {
return -0.0;
} else {
return +0.0;
}
}
return DUK_FLOOR(x + 0.5);
}
/* Wrappers for calling standard math library methods. These may be required
* on platforms where one or more of the math built-ins are defined as macros
* or inline functions and are thus not suitable to be used as function pointers.
*/
#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
DUK_LOCAL double duk__fabs(double x) {
return DUK_FABS(x);
}
DUK_LOCAL double duk__acos(double x) {
return DUK_ACOS(x);
}
DUK_LOCAL double duk__asin(double x) {
return DUK_ASIN(x);
}
DUK_LOCAL double duk__atan(double x) {
return DUK_ATAN(x);
}
DUK_LOCAL double duk__ceil(double x) {
return DUK_CEIL(x);
}
DUK_LOCAL double duk__cos(double x) {
return DUK_COS(x);
}
DUK_LOCAL double duk__exp(double x) {
return DUK_EXP(x);
}
DUK_LOCAL double duk__floor(double x) {
return DUK_FLOOR(x);
}
DUK_LOCAL double duk__log(double x) {
return DUK_LOG(x);
}
DUK_LOCAL double duk__sin(double x) {
return DUK_SIN(x);
}
DUK_LOCAL double duk__sqrt(double x) {
return DUK_SQRT(x);
}
DUK_LOCAL double duk__tan(double x) {
return DUK_TAN(x);
}
DUK_LOCAL double duk__atan2_fixed(double x, double y) {
#if defined(DUK_USE_ATAN2_WORKAROUNDS)
/* Specific fixes to common atan2() implementation issues:
* - test-bug-mingw-math-issues.js
*/
if (DUK_ISINF(x) && DUK_ISINF(y)) {
if (DUK_SIGNBIT(x)) {
if (DUK_SIGNBIT(y)) {
return -2.356194490192345;
} else {
return -0.7853981633974483;
}
} else {
if (DUK_SIGNBIT(y)) {
return 2.356194490192345;
} else {
return 0.7853981633974483;
}
}
}
#else
/* Some ISO C assumptions. */
DUK_ASSERT(duk_double_equals(DUK_ATAN2(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY), 0.7853981633974483));
DUK_ASSERT(duk_double_equals(DUK_ATAN2(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY), -0.7853981633974483));
DUK_ASSERT(duk_double_equals(DUK_ATAN2(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY), 2.356194490192345));
DUK_ASSERT(duk_double_equals(DUK_ATAN2(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY), -2.356194490192345));
#endif
return DUK_ATAN2(x, y);
}
#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
/* order must match constants in genbuiltins.py */
DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
duk__fabs,
duk__acos,
duk__asin,
duk__atan,
duk__ceil,
duk__cos,
duk__exp,
duk__floor,
duk__log,
duk__round_fixed,
duk__sin,
duk__sqrt,
duk__tan,
#if defined(DUK_USE_ES6)
duk__cbrt,
duk__log2,
duk__log10,
duk__trunc
#endif
#else /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
DUK_FABS,
DUK_ACOS,
DUK_ASIN,
DUK_ATAN,
DUK_CEIL,
DUK_COS,
DUK_EXP,
DUK_FLOOR,
DUK_LOG,
duk__round_fixed,
DUK_SIN,
DUK_SQRT,
DUK_TAN,
#if defined(DUK_USE_ES6)
duk__cbrt,
duk__log2,
duk__log10,
duk__trunc
#endif
#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
};
/* order must match constants in genbuiltins.py */
DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
duk__atan2_fixed,
duk_js_arith_pow
#else
duk__atan2_fixed,
duk_js_arith_pow
#endif
};
DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_hthread *thr) {
duk_small_int_t fun_idx = duk_get_current_magic(thr);
duk__one_arg_func fun;
duk_double_t arg1;
DUK_ASSERT(fun_idx >= 0);
DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
arg1 = duk_to_number(thr, 0);
fun = duk__one_arg_funcs[fun_idx];
duk_push_number(thr, (duk_double_t) fun((double) arg1));
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_hthread *thr) {
duk_small_int_t fun_idx = duk_get_current_magic(thr);
duk__two_arg_func fun;
duk_double_t arg1;
duk_double_t arg2;
DUK_ASSERT(fun_idx >= 0);
DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
arg1 = duk_to_number(thr, 0); /* explicit ordered evaluation to match coercion semantics */
arg2 = duk_to_number(thr, 1);
fun = duk__two_arg_funcs[fun_idx];
duk_push_number(thr, (duk_double_t) fun((double) arg1, (double) arg2));
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_hthread *thr) {
return duk__math_minmax(thr, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
}
DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_hthread *thr) {
return duk__math_minmax(thr, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
}
DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_hthread *thr) {
duk_push_number(thr, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr));
return 1;
}
#if defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_hthread *thr) {
/*
* E6 Section 20.2.2.18: Math.hypot
*
* - If no arguments are passed, the result is +0.
* - If any argument is +inf, the result is +inf.
* - If any argument is -inf, the result is +inf.
* - If no argument is +inf or -inf, and any argument is NaN, the result is
* NaN.
* - If all arguments are either +0 or -0, the result is +0.
*/
duk_idx_t nargs;
duk_idx_t i;
duk_bool_t found_nan;
duk_double_t max;
duk_double_t sum, summand;
duk_double_t comp, prelim;
duk_double_t t;
nargs = duk_get_top(thr);
/* Find the highest value. Also ToNumber() coerces. */
max = 0.0;
found_nan = 0;
for (i = 0; i < nargs; i++) {
t = DUK_FABS(duk_to_number(thr, i));
if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) {
found_nan = 1;
} else {
max = duk_double_fmax(max, t);
}
}
/* Early return cases. */
if (duk_double_equals(max, DUK_DOUBLE_INFINITY)) {
duk_push_number(thr, DUK_DOUBLE_INFINITY);
return 1;
} else if (found_nan) {
duk_push_number(thr, DUK_DOUBLE_NAN);
return 1;
} else if (duk_double_equals(max, 0.0)) {
duk_push_number(thr, 0.0);
/* Otherwise we'd divide by zero. */
return 1;
}
/* Use Kahan summation and normalize to the highest value to minimize
* floating point rounding error and avoid overflow.
*
* https://en.wikipedia.org/wiki/Kahan_summation_algorithm
*/
sum = 0.0;
comp = 0.0;
for (i = 0; i < nargs; i++) {
t = DUK_FABS(duk_get_number(thr, i)) / max;
summand = (t * t) - comp;
prelim = sum + summand;
comp = (prelim - sum) - summand;
sum = prelim;
}
duk_push_number(thr, (duk_double_t) DUK_SQRT(sum) * max);
return 1;
}
#endif /* DUK_USE_ES6 */
#if defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_math_object_sign(duk_hthread *thr) {
duk_double_t d;
d = duk_to_number(thr, 0);
if (duk_double_is_nan(d)) {
DUK_ASSERT(duk_is_nan(thr, -1));
return 1; /* NaN input -> return NaN */
}
if (duk_double_equals(d, 0.0)) {
/* Zero sign kept, i.e. -0 -> -0, +0 -> +0. */
return 1;
}
duk_push_int(thr, (d > 0.0 ? 1 : -1));
return 1;
}
#endif /* DUK_USE_ES6 */
#if defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_math_object_clz32(duk_hthread *thr) {
duk_uint32_t x;
duk_small_uint_t i;
#if defined(DUK_USE_PREFER_SIZE)
duk_uint32_t mask;
x = duk_to_uint32(thr, 0);
for (i = 0, mask = 0x80000000UL; mask != 0; mask >>= 1) {
if (x & mask) {
break;
}
i++;
}
DUK_ASSERT(i <= 32);
duk_push_uint(thr, i);
return 1;
#else /* DUK_USE_PREFER_SIZE */
i = 0;
x = duk_to_uint32(thr, 0);
if (x & 0xffff0000UL) {
x >>= 16;
} else {
i += 16;
}
if (x & 0x0000ff00UL) {
x >>= 8;
} else {
i += 8;
}
if (x & 0x000000f0UL) {
x >>= 4;
} else {
i += 4;
}
if (x & 0x0000000cUL) {
x >>= 2;
} else {
i += 2;
}
if (x & 0x00000002UL) {
x >>= 1;
} else {
i += 1;
}
if (x & 0x00000001UL) {
;
} else {
i += 1;
}
DUK_ASSERT(i <= 32);
duk_push_uint(thr, i);
return 1;
#endif /* DUK_USE_PREFER_SIZE */
}
#endif /* DUK_USE_ES6 */
#if defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_math_object_imul(duk_hthread *thr) {
duk_uint32_t x, y, z;
x = duk_to_uint32(thr, 0);
y = duk_to_uint32(thr, 1);
z = x * y;
/* While arguments are ToUint32() coerced and the multiplication
* is unsigned as such, the final result is curiously interpreted
* as a signed 32-bit value.
*/
duk_push_i32(thr, (duk_int32_t) z);
return 1;
}
#endif /* DUK_USE_ES6 */
#endif /* DUK_USE_MATH_BUILTIN */

View file

@ -1,280 +0,0 @@
/*
* Number built-ins
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_NUMBER_BUILTIN)
DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) {
duk_hobject *h;
/* Number built-in accepts a plain number or a Number object (whose
* internal value is operated on). Other types cause TypeError.
*/
duk_push_this(thr);
if (duk_is_number(thr, -1)) {
DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
goto done;
}
h = duk_get_hobject(thr, -1);
if (!h ||
(DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
DUK_ERROR_TYPE(thr, "number expected");
DUK_WO_NORETURN(return 0.0;);
}
duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
DUK_ASSERT(duk_is_number(thr, -1));
DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
(duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
duk_remove_m2(thr);
done:
return duk_get_number(thr, -1);
}
DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_hthread *thr) {
duk_idx_t nargs;
duk_hobject *h_this;
/*
* The Number constructor uses ToNumber(arg) for number coercion
* (coercing an undefined argument to NaN). However, if the
* argument is not given at all, +0 must be used instead. To do
* this, a vararg function is used.
*/
nargs = duk_get_top(thr);
if (nargs == 0) {
duk_push_int(thr, 0);
}
duk_to_number(thr, 0);
duk_set_top(thr, 1);
DUK_ASSERT_TOP(thr, 1);
if (!duk_is_constructor_call(thr)) {
return 1;
}
/*
* E5 Section 15.7.2.1 requires that the constructed object
* must have the original Number.prototype as its internal
* prototype. However, since Number.prototype is non-writable
* and non-configurable, this doesn't have to be enforced here:
* The default object (bound to 'this') is OK, though we have
* to change its class.
*
* Internal value set to ToNumber(arg) or +0; if no arg given,
* ToNumber(undefined) = NaN, so special treatment is needed
* (above). String internal value is immutable.
*/
/* XXX: helper */
duk_push_this(thr);
h_this = duk_known_hobject(thr, -1);
DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
duk_dup_0(thr); /* -> [ val obj val ] */
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
return 0; /* no return value -> don't replace created value */
}
DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_hthread *thr) {
(void) duk__push_this_number_plain(thr);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_hthread *thr) {
duk_small_int_t radix;
duk_small_uint_t n2s_flags;
(void) duk__push_this_number_plain(thr);
if (duk_is_undefined(thr, 0)) {
radix = 10;
} else {
radix = (duk_small_int_t) duk_to_int_check_range(thr, 0, 2, 36);
}
DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
n2s_flags = 0;
duk_numconv_stringify(thr,
radix /*radix*/,
0 /*digits*/,
n2s_flags /*flags*/);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_hthread *thr) {
/* XXX: just use toString() for now; permitted although not recommended.
* nargs==1, so radix is passed to toString().
*/
return duk_bi_number_prototype_to_string(thr);
}
/*
* toFixed(), toExponential(), toPrecision()
*/
/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) {
duk_small_int_t frac_digits;
duk_double_t d;
duk_small_int_t c;
duk_small_uint_t n2s_flags;
/* In ES5.1 frac_digits is coerced first; in ES2015 the 'this number
* value' check is done first.
*/
d = duk__push_this_number_plain(thr);
frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
goto use_to_string;
}
if (d >= 1.0e21 || d <= -1.0e21) {
goto use_to_string;
}
n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
DUK_N2S_FLAG_FRACTION_DIGITS;
duk_numconv_stringify(thr,
10 /*radix*/,
frac_digits /*digits*/,
n2s_flags /*flags*/);
return 1;
use_to_string:
DUK_ASSERT_TOP(thr, 2);
duk_to_string(thr, -1);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_hthread *thr) {
duk_bool_t frac_undefined;
duk_small_int_t frac_digits;
duk_double_t d;
duk_small_int_t c;
duk_small_uint_t n2s_flags;
d = duk__push_this_number_plain(thr);
frac_undefined = duk_is_undefined(thr, 0);
duk_to_int(thr, 0); /* for side effects */
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
goto use_to_string;
}
frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
(frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
duk_numconv_stringify(thr,
10 /*radix*/,
frac_digits + 1 /*leading digit + fractions*/,
n2s_flags /*flags*/);
return 1;
use_to_string:
DUK_ASSERT_TOP(thr, 2);
duk_to_string(thr, -1);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
/* The specification has quite awkward order of coercion and
* checks for toPrecision(). The operations below are a bit
* reordered, within constraints of observable side effects.
*/
duk_double_t d;
duk_small_int_t prec;
duk_small_int_t c;
duk_small_uint_t n2s_flags;
DUK_ASSERT_TOP(thr, 1);
d = duk__push_this_number_plain(thr);
if (duk_is_undefined(thr, 0)) {
goto use_to_string;
}
DUK_ASSERT_TOP(thr, 2);
duk_to_int(thr, 0); /* for side effects */
c = (duk_small_int_t) DUK_FPCLASSIFY(d);
if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
goto use_to_string;
}
prec = (duk_small_int_t) duk_to_int_check_range(thr, 0, 1, 21);
n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
DUK_N2S_FLAG_NO_ZERO_PAD;
duk_numconv_stringify(thr,
10 /*radix*/,
prec /*digits*/,
n2s_flags /*flags*/);
return 1;
use_to_string:
/* Used when precision is undefined; also used for NaN (-> "NaN"),
* and +/- infinity (-> "Infinity", "-Infinity").
*/
DUK_ASSERT_TOP(thr, 2);
duk_to_string(thr, -1);
return 1;
}
/*
* ES2015 isFinite() etc
*/
#if defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_number_check_shared(duk_hthread *thr) {
duk_int_t magic;
duk_bool_t ret = 0;
if (duk_is_number(thr, 0)) {
duk_double_t d;
magic = duk_get_current_magic(thr);
d = duk_get_number(thr, 0);
switch (magic) {
case 0: /* isFinite() */
ret = duk_double_is_finite(d);
break;
case 1: /* isInteger() */
ret = duk_double_is_integer(d);
break;
case 2: /* isNaN() */
ret = duk_double_is_nan(d);
break;
default: /* isSafeInteger() */
DUK_ASSERT(magic == 3);
ret = duk_double_is_safe_integer(d);
}
}
duk_push_boolean(thr, ret);
return 1;
}
#endif /* DUK_USE_ES6 */
#endif /* DUK_USE_NUMBER_BUILTIN */

View file

@ -1,803 +0,0 @@
/*
* Object built-ins
*/
#include "third_party/duktape/duk_internal.h"
/* Needed even when Object built-in disabled. */
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) {
duk_tval *tv;
tv = DUK_HTHREAD_THIS_PTR(thr);
duk_push_class_string_tval(thr, tv, 0 /*avoid_side_effects*/);
return 1;
}
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_hthread *thr) {
duk_uint_t arg_mask;
arg_mask = duk_get_type_mask(thr, 0);
if (!duk_is_constructor_call(thr) && /* not a constructor call */
((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) { /* and argument not null or undefined */
duk_to_object(thr, 0);
return 1;
}
/* Pointer and buffer primitive values are treated like other
* primitives values which have a fully fledged object counterpart:
* promote to an object value. Lightfuncs and plain buffers are
* coerced with ToObject() even they could also be returned as is.
*/
if (arg_mask & (DUK_TYPE_MASK_OBJECT |
DUK_TYPE_MASK_STRING |
DUK_TYPE_MASK_BOOLEAN |
DUK_TYPE_MASK_NUMBER |
DUK_TYPE_MASK_POINTER |
DUK_TYPE_MASK_BUFFER |
DUK_TYPE_MASK_LIGHTFUNC)) {
/* For DUK_TYPE_OBJECT the coercion is a no-op and could
* be checked for explicitly, but Object(obj) calls are
* not very common so opt for minimal footprint.
*/
duk_to_object(thr, 0);
return 1;
}
(void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
DUK_BIDX_OBJECT_PROTOTYPE);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_hthread *thr) {
duk_idx_t nargs;
duk_int_t idx;
nargs = duk_get_top_require_min(thr, 1 /*min_top*/);
duk_to_object(thr, 0);
for (idx = 1; idx < nargs; idx++) {
/* E7 19.1.2.1 (step 4a) */
if (duk_is_null_or_undefined(thr, idx)) {
continue;
}
/* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is
* convenient here.
*/
duk_to_object(thr, idx);
duk_enum(thr, idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
while (duk_next(thr, -1, 1 /*get_value*/)) {
/* [ target ... enum key value ] */
duk_put_prop(thr, 0);
/* [ target ... enum ] */
}
/* Could pop enumerator, but unnecessary because of duk_set_top()
* below.
*/
}
duk_set_top(thr, 1);
return 1;
}
#endif
#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_hthread *thr) {
DUK_ASSERT_TOP(thr, 2);
duk_push_boolean(thr, duk_samevalue(thr, 0, 1));
return 1;
}
#endif
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) {
duk_hobject *proto;
DUK_ASSERT_TOP(thr, 2);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
duk_hbufobj_promote_plain(thr, 0);
#endif
proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL);
DUK_ASSERT(proto != NULL || duk_is_null(thr, 0));
(void) duk_push_object_helper_proto(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
proto);
if (!duk_is_undefined(thr, 1)) {
/* [ O Properties obj ] */
duk_replace(thr, 0);
/* [ obj Properties ] */
/* Just call the "original" Object.defineProperties() to
* finish up.
*/
return duk_bi_object_constructor_define_properties(thr);
}
/* [ O Properties obj ] */
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_hthread *thr) {
duk_small_uint_t pass_;
duk_uint_t defprop_flags;
duk_hobject *obj;
duk_idx_t idx_value;
duk_hobject *get;
duk_hobject *set;
/* Lightfunc and plain buffer handling by ToObject() coercion. */
obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
DUK_ASSERT(obj != NULL);
duk_to_object(thr, 1); /* properties object */
DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
(duk_tval *) duk_get_tval(thr, 0),
(duk_tval *) duk_get_tval(thr, 1)));
/*
* Two pass_ approach to processing the property descriptors.
* On first pass_ validate and normalize all descriptors before
* any changes are made to the target object. On second pass_
* make the actual modifications to the target object.
*
* Right now we'll just use the same normalize/validate helper
* on both passes, ignoring its outputs on the first pass_.
*/
for (pass_ = 0; pass_ < 2; pass_++) {
duk_set_top(thr, 2); /* -> [ hobject props ] */
duk_enum(thr, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/);
for (;;) {
duk_hstring *key;
/* [ hobject props enum(props) ] */
duk_set_top(thr, 3);
if (!duk_next(thr, 2, 1 /*get_value*/)) {
break;
}
DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
(duk_tval *) duk_get_tval(thr, -2),
(duk_tval *) duk_get_tval(thr, -1)));
/* [ hobject props enum(props) key desc ] */
duk_hobject_prepare_property_descriptor(thr,
4 /*idx_desc*/,
&defprop_flags,
&idx_value,
&get,
&set);
/* [ hobject props enum(props) key desc [multiple values] ] */
if (pass_ == 0) {
continue;
}
/* This allows symbols on purpose. */
key = duk_known_hstring(thr, 3);
DUK_ASSERT(key != NULL);
duk_hobject_define_property_helper(thr,
defprop_flags,
obj,
key,
idx_value,
get,
set,
1 /*throw_flag*/);
}
}
/*
* Return target object
*/
duk_dup_0(thr);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_hthread *thr) {
DUK_ASSERT_TOP(thr, 1);
duk_seal_freeze_raw(thr, 0, (duk_bool_t) duk_get_current_magic(thr) /*is_freeze*/);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_hthread *thr) {
duk_hobject *h;
duk_bool_t is_frozen;
duk_uint_t mask;
is_frozen = (duk_bool_t) duk_get_current_magic(thr);
mask = duk_get_type_mask(thr, 0);
if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
DUK_ASSERT(is_frozen == 0 || is_frozen == 1);
duk_push_boolean(thr, (mask & DUK_TYPE_MASK_LIGHTFUNC) ?
1 : /* lightfunc always frozen and sealed */
(is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */
} else {
/* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object
* is considered to be already sealed and frozen.
*/
h = duk_get_hobject(thr, 0);
duk_push_boolean(thr, (h == NULL) ||
duk_hobject_object_is_sealed_frozen_helper(thr, h, is_frozen /*is_frozen*/));
}
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) {
DUK_ASSERT_TOP(thr, 0);
(void) duk_push_this_coercible_to_object(thr);
duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING);
#if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */
duk_require_callable(thr, 1);
#endif
duk_dup_0(thr); /* -> [ O toString O ] */
duk_call_method(thr, 0); /* XXX: call method tail call? */
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_hthread *thr) {
/* For lightfuncs and plain buffers, returns Object() coerced. */
(void) duk_push_this_coercible_to_object(thr);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) {
duk_hobject *h_v;
duk_hobject *h_obj;
DUK_ASSERT_TOP(thr, 1);
h_v = duk_get_hobject(thr, 0);
if (!h_v) {
duk_push_false(thr); /* XXX: tail call: return duk_push_false(thr) */
return 1;
}
h_obj = duk_push_this_coercible_to_object(thr);
DUK_ASSERT(h_obj != NULL);
/* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
* Prototype loops should cause an error to be thrown.
*/
duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_hthread *thr) {
return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, 0 /*required_desc_flags*/);
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_hthread *thr) {
return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
}
#endif /* DUK_USE_OBJECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
/* Shared helper to implement Object.getPrototypeOf,
* Object.prototype.__proto__ getter, and Reflect.getPrototypeOf.
*
* http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
*/
DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_hthread *thr) {
/*
* magic = 0: __proto__ getter
* magic = 1: Object.getPrototypeOf()
* magic = 2: Reflect.getPrototypeOf()
*/
duk_hobject *h;
duk_hobject *proto;
duk_tval *tv;
duk_int_t magic;
magic = duk_get_current_magic(thr);
if (magic == 0) {
DUK_ASSERT_TOP(thr, 0);
duk_push_this_coercible_to_object(thr);
}
DUK_ASSERT(duk_get_top(thr) >= 1);
if (magic < 2) {
/* ES2015 Section 19.1.2.9, step 1 */
duk_to_object(thr, 0);
}
tv = DUK_GET_TVAL_POSIDX(thr, 0);
switch (DUK_TVAL_GET_TAG(tv)) {
case DUK_TAG_BUFFER:
proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
break;
case DUK_TAG_LIGHTFUNC:
proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
break;
case DUK_TAG_OBJECT:
h = DUK_TVAL_GET_OBJECT(tv);
proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
break;
default:
/* This implicitly handles CheckObjectCoercible() caused
* TypeError.
*/
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
if (proto != NULL) {
duk_push_hobject(thr, proto);
} else {
duk_push_null(thr);
}
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
/* Shared helper to implement ES2015 Object.setPrototypeOf,
* Object.prototype.__proto__ setter, and Reflect.setPrototypeOf.
*
* http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
* http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
*/
DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) {
/*
* magic = 0: __proto__ setter
* magic = 1: Object.setPrototypeOf()
* magic = 2: Reflect.setPrototypeOf()
*/
duk_hobject *h_obj;
duk_hobject *h_new_proto;
duk_hobject *h_curr;
duk_ret_t ret_success = 1; /* retval for success path */
duk_uint_t mask;
duk_int_t magic;
/* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */
magic = duk_get_current_magic(thr);
if (magic == 0) {
duk_push_this_check_object_coercible(thr);
duk_insert(thr, 0);
if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
return 0;
}
/* __proto__ setter returns 'undefined' on success unlike the
* setPrototypeOf() call which returns the target object.
*/
ret_success = 0;
} else {
if (magic == 1) {
duk_require_object_coercible(thr, 0);
} else {
duk_require_hobject_accept_mask(thr, 0,
DUK_TYPE_MASK_LIGHTFUNC |
DUK_TYPE_MASK_BUFFER);
}
duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
}
h_new_proto = duk_get_hobject(thr, 1);
/* h_new_proto may be NULL */
mask = duk_get_type_mask(thr, 0);
if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
duk_hobject *curr_proto;
curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ?
DUK_BIDX_FUNCTION_PROTOTYPE :
DUK_BIDX_UINT8ARRAY_PROTOTYPE];
if (h_new_proto == curr_proto) {
goto skip;
}
goto fail_nonextensible;
}
h_obj = duk_get_hobject(thr, 0);
if (h_obj == NULL) {
goto skip;
}
DUK_ASSERT(h_obj != NULL);
/* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */
/* TODO: implement Proxy object support here */
if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
goto skip;
}
if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
goto fail_nonextensible;
}
for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
/* Loop prevention. */
if (h_curr == h_obj) {
goto fail_loop;
}
}
DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
/* fall thru */
skip:
duk_set_top(thr, 1);
if (magic == 2) {
duk_push_true(thr);
}
return ret_success;
fail_nonextensible:
fail_loop:
if (magic != 2) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
} else {
duk_push_false(thr);
return 1;
}
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *thr) {
/*
* magic = 0: Object.defineProperty()
* magic = 1: Reflect.defineProperty()
*/
duk_hobject *obj;
duk_hstring *key;
duk_hobject *get;
duk_hobject *set;
duk_idx_t idx_value;
duk_uint_t defprop_flags;
duk_small_uint_t magic;
duk_bool_t throw_flag;
duk_bool_t ret;
DUK_ASSERT(thr != NULL);
DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
(void *) thr,
(duk_tval *) duk_get_tval(thr, 0),
(duk_tval *) duk_get_tval(thr, 1),
(duk_tval *) duk_get_tval(thr, 2)));
/* [ obj key desc ] */
magic = (duk_small_uint_t) duk_get_current_magic(thr);
/* Lightfuncs are currently supported by coercing to a temporary
* Function object; changes will be allowed (the coerced value is
* extensible) but will be lost. Same for plain buffers.
*/
obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
DUK_ASSERT(obj != NULL);
key = duk_to_property_key_hstring(thr, 1);
(void) duk_require_hobject(thr, 2);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(key != NULL);
DUK_ASSERT(duk_get_hobject(thr, 2) != NULL);
/*
* Validate and convert argument property descriptor (an ECMAScript
* object) into a set of defprop_flags and possibly property value,
* getter, and/or setter values on the value stack.
*
* Lightfunc set/get values are coerced to full Functions.
*/
duk_hobject_prepare_property_descriptor(thr,
2 /*idx_desc*/,
&defprop_flags,
&idx_value,
&get,
&set);
/*
* Use Object.defineProperty() helper for the actual operation.
*/
DUK_ASSERT(magic == 0U || magic == 1U);
throw_flag = magic ^ 1U;
ret = duk_hobject_define_property_helper(thr,
defprop_flags,
obj,
key,
idx_value,
get,
set,
throw_flag);
/* Ignore the normalize/validate helper outputs on the value stack,
* they're popped automatically.
*/
if (magic == 0U) {
/* Object.defineProperty(): return target object. */
duk_push_hobject(thr, obj);
} else {
/* Reflect.defineProperty(): return success/fail. */
duk_push_boolean(thr, ret);
}
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) {
DUK_ASSERT_TOP(thr, 2);
/* ES2015 Section 19.1.2.6, step 1 */
if (duk_get_current_magic(thr) == 0) {
duk_to_object(thr, 0);
}
/* [ obj key ] */
duk_hobject_object_get_own_property_descriptor(thr, -2);
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) {
/*
* magic = 0: Object.isExtensible()
* magic = 1: Reflect.isExtensible()
*/
duk_hobject *h;
if (duk_get_current_magic(thr) == 0) {
h = duk_get_hobject(thr, 0);
} else {
/* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs
* and plain buffers here because they pretend to be objects.
*/
h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
}
duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h));
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
/* Shared helper for various key/symbol listings, magic:
* 0=Object.keys()
* 1=Object.getOwnPropertyNames(),
* 2=Object.getOwnPropertySymbols(),
* 3=Reflect.ownKeys()
*/
DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = {
/* Object.keys() */
DUK_ENUM_OWN_PROPERTIES_ONLY |
DUK_ENUM_NO_PROXY_BEHAVIOR,
/* Object.getOwnPropertyNames() */
DUK_ENUM_INCLUDE_NONENUMERABLE |
DUK_ENUM_OWN_PROPERTIES_ONLY |
DUK_ENUM_NO_PROXY_BEHAVIOR,
/* Object.getOwnPropertySymbols() */
DUK_ENUM_INCLUDE_SYMBOLS |
DUK_ENUM_OWN_PROPERTIES_ONLY |
DUK_ENUM_EXCLUDE_STRINGS |
DUK_ENUM_INCLUDE_NONENUMERABLE |
DUK_ENUM_NO_PROXY_BEHAVIOR,
/* Reflect.ownKeys() */
DUK_ENUM_INCLUDE_SYMBOLS |
DUK_ENUM_OWN_PROPERTIES_ONLY |
DUK_ENUM_INCLUDE_NONENUMERABLE |
DUK_ENUM_NO_PROXY_BEHAVIOR
};
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) {
duk_hobject *obj;
#if defined(DUK_USE_ES6_PROXY)
duk_hobject *h_proxy_target;
duk_hobject *h_proxy_handler;
duk_hobject *h_trap_result;
#endif
duk_small_uint_t enum_flags;
duk_int_t magic;
DUK_ASSERT_TOP(thr, 1);
magic = duk_get_current_magic(thr);
if (magic == 3) {
/* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs
* and plain buffers pretend to be objects, so accept those too.
*/
obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
} else {
/* ES2015: ToObject coerce. */
obj = duk_to_hobject(thr, 0);
}
DUK_ASSERT(obj != NULL);
DUK_UNREF(obj);
/* XXX: proxy chains */
#if defined(DUK_USE_ES6_PROXY)
/* XXX: better sharing of code between proxy target call sites */
if (DUK_LIKELY(!duk_hobject_proxy_check(obj,
&h_proxy_target,
&h_proxy_handler))) {
goto skip_proxy;
}
duk_push_hobject(thr, h_proxy_handler);
if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
/* Careful with reachability here: don't pop 'obj' before pushing
* proxy target.
*/
DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
duk_pop_2(thr);
duk_push_hobject(thr, h_proxy_target);
duk_replace(thr, 0);
DUK_ASSERT_TOP(thr, 1);
goto skip_proxy;
}
/* [ obj handler trap ] */
duk_insert(thr, -2);
duk_push_hobject(thr, h_proxy_target); /* -> [ obj trap handler target ] */
duk_call_method(thr, 1 /*nargs*/); /* -> [ obj trap_result ] */
h_trap_result = duk_require_hobject(thr, -1);
DUK_UNREF(h_trap_result);
magic = duk_get_current_magic(thr);
DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
enum_flags = duk__object_keys_enum_flags[magic];
duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
return 1;
skip_proxy:
#endif /* DUK_USE_ES6_PROXY */
DUK_ASSERT_TOP(thr, 1);
magic = duk_get_current_magic(thr);
DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
enum_flags = duk__object_keys_enum_flags[magic];
return duk_hobject_get_enumerated_keys(thr, enum_flags);
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_hthread *thr) {
/*
* magic = 0: Object.preventExtensions()
* magic = 1: Reflect.preventExtensions()
*/
duk_hobject *h;
duk_uint_t mask;
duk_int_t magic;
magic = duk_get_current_magic(thr);
/* Silent success for lightfuncs and plain buffers always. */
mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER;
/* Object.preventExtensions() silent success for non-object. */
if (magic == 0) {
mask |= DUK_TYPE_MASK_UNDEFINED |
DUK_TYPE_MASK_NULL |
DUK_TYPE_MASK_BOOLEAN |
DUK_TYPE_MASK_NUMBER |
DUK_TYPE_MASK_STRING |
DUK_TYPE_MASK_POINTER;
}
if (duk_check_type_mask(thr, 0, mask)) {
/* Not an object, already non-extensible so always success. */
goto done;
}
h = duk_require_hobject(thr, 0);
DUK_ASSERT(h != NULL);
DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
/* A non-extensible object cannot gain any more properties,
* so this is a good time to compact.
*/
duk_hobject_compact_props(thr, h);
done:
if (magic == 1) {
duk_push_true(thr);
}
return 1;
}
#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
/*
* __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__
*/
#if defined(DUK_USE_ES8)
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) {
duk_push_this(thr);
duk_insert(thr, 0);
duk_to_object(thr, 0);
duk_require_callable(thr, 2);
/* [ ToObject(this) key getter/setter ] */
/* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */
duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE |
DUK_DEFPROP_SET_CONFIGURABLE |
(duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER));
return 0;
}
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) {
duk_uint_t sanity;
duk_push_this(thr);
duk_to_object(thr, -1);
/* XXX: Prototype walk (with sanity) should be a core property
* operation, could add a flag to e.g. duk_get_prop_desc().
*/
/* ToPropertyKey() coercion is not needed, duk_get_prop_desc() does it. */
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
while (!duk_is_undefined(thr, -1)) {
/* [ key obj ] */
duk_dup(thr, 0);
duk_get_prop_desc(thr, 1, 0 /*flags*/);
if (!duk_is_undefined(thr, -1)) {
duk_get_prop_stridx(thr, -1, (duk_get_current_magic(thr) != 0 ? DUK_STRIDX_SET : DUK_STRIDX_GET));
return 1;
}
duk_pop(thr);
if (DUK_UNLIKELY(sanity-- == 0)) {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
DUK_WO_NORETURN(return 0;);
}
duk_get_prototype(thr, -1);
duk_remove(thr, -2);
}
return 1;
}
#endif /* DUK_USE_ES8 */

View file

@ -1,31 +0,0 @@
/*
* High resolution time API (performance.now() et al)
*
* API specification: https://encoding.spec.whatwg.org/#ap://www.w3.org/TR/hr-time/
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_PERFORMANCE_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_performance_now(duk_hthread *thr) {
/* From API spec:
* The DOMHighResTimeStamp type is used to store a time value in
* milliseconds, measured relative from the time origin, global
* monotonic clock, or a time value that represents a duration
* between two DOMHighResTimeStamp's.
*/
duk_push_number(thr, duk_time_get_monotonic_time(thr));
return 1;
}
#if 0 /* Missing until semantics decided. */
DUK_INTERNAL duk_ret_t duk_bi_performance_timeorigin_getter(duk_hthread *thr) {
/* No decision yet how to handle timeOrigins, e.g. should one be
* initialized per heap, or per global object set. See
* https://www.w3.org/TR/hr-time/#time-origin.
*/
duk_push_uint(thr, 0);
return 1;
}
#endif /* 0 */
#endif /* DUK_USE_PERFORMANCE_BUILTIN */

View file

@ -1,75 +0,0 @@
/*
* Pointer built-ins
*/
#include "third_party/duktape/duk_internal.h"
/*
* Constructor
*/
DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_hthread *thr) {
/* XXX: this behavior is quite useless now; it would be nice to be able
* to create pointer values from e.g. numbers or strings. Numbers are
* problematic on 64-bit platforms though. Hex encoded strings?
*/
if (duk_get_top(thr) == 0) {
duk_push_pointer(thr, NULL);
} else {
duk_to_pointer(thr, 0);
}
DUK_ASSERT(duk_is_pointer(thr, 0));
duk_set_top(thr, 1);
if (duk_is_constructor_call(thr)) {
(void) duk_push_object_helper(thr,
DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_FASTREFS |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
DUK_BIDX_POINTER_PROTOTYPE);
/* Pointer object internal value is immutable. */
duk_dup_0(thr);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
}
/* Note: unbalanced stack on purpose */
return 1;
}
/*
* toString(), valueOf()
*/
DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr) {
duk_tval *tv;
duk_small_int_t to_string = duk_get_current_magic(thr);
duk_push_this(thr);
tv = duk_require_tval(thr, -1);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_IS_POINTER(tv)) {
/* nop */
} else if (DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL);
/* Must be a "pointer object", i.e. class "Pointer" */
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
goto type_error;
}
duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
} else {
goto type_error;
}
if (to_string) {
duk_to_string(thr, -1);
}
return 1;
type_error:
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}

View file

@ -1,44 +0,0 @@
/*
* Promise built-in
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_PROMISE_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
DUK_WO_NORETURN(return 0;);
}
DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) {
DUK_ERROR_TYPE(thr, "unimplemented");
DUK_WO_NORETURN(return 0;);
}
#endif /* DUK_USE_PROMISE_BUILTIN */

View file

@ -1,81 +0,0 @@
/*
* Prototypes for built-in functions not automatically covered by the
* header declarations emitted by genbuiltins.py.
*/
#if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED)
#define DUK_BUILTIN_PROTOS_H_INCLUDED
/* Buffer size needed for ISO 8601 formatting.
* Accurate value is 32 + 1 for NUL termination:
* >>> len('+123456-01-23T12:34:56.123+12:34')
* 32
* Include additional space to be safe.
*/
#define DUK_BI_DATE_ISO8601_BUFSIZE 40
/* Helpers exposed for internal use */
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);
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
/* Built-in providers */
#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void);
#endif
#if defined(DUK_USE_DATE_NOW_TIME)
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void);
#endif
#if defined(DUK_USE_DATE_NOW_WINDOWS)
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void);
#endif
#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void);
#endif
#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
#endif
#if defined(DUK_USE_DATE_TZO_WINDOWS)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
#endif
#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d);
#endif
#if defined(DUK_USE_DATE_PRS_STRPTIME)
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str);
#endif
#if defined(DUK_USE_DATE_PRS_GETDATE)
DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str);
#endif
#if defined(DUK_USE_DATE_FMT_STRFTIME)
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);
#endif
#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void);
#endif
#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void);
#endif
DUK_INTERNAL_DECL
void duk_bi_json_parse_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_reviver,
duk_small_uint_t flags);
DUK_INTERNAL_DECL
void duk_bi_json_stringify_helper(duk_hthread *thr,
duk_idx_t idx_value,
duk_idx_t idx_replacer,
duk_idx_t idx_space,
duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr);
#if defined(DUK_USE_ES6_PROXY)
DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags);
#endif
#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */

View file

@ -1,96 +0,0 @@
/*
* Proxy built-in (ES2015)
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_ES6_PROXY)
/* Post-process a Proxy ownKeys() result at stack top. Push a cleaned up
* array of valid result keys (strings or symbols). TypeError for invalid
* values. Flags are shared with duk_enum().
*/
DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) {
duk_uarridx_t i, len, idx;
duk_propdesc desc;
DUK_CTX_ASSERT_VALID(thr);
DUK_ASSERT(h_proxy_target != NULL);
len = (duk_uarridx_t) duk_get_length(thr, -1);
idx = 0;
duk_push_array(thr);
/* XXX: preallocated dense array, fill in directly */
for (i = 0; i < len; i++) {
duk_hstring *h;
/* [ obj trap_result res_arr ] */
(void) duk_get_prop_index(thr, -2, i);
h = duk_get_hstring(thr, -1);
if (h == NULL) {
DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
DUK_WO_NORETURN(return;);
}
if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
/* No support for 'getOwnPropertyDescriptor' trap yet,
* so check enumerability always from target object
* descriptor.
*/
if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) {
if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
} else {
DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
}
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) {
DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
} else {
if (flags & DUK_ENUM_EXCLUDE_STRINGS) {
DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(thr, -1)));
goto skip_key;
}
}
/* [ obj trap_result res_arr propname ] */
duk_put_prop_index(thr, -2, idx++);
continue;
skip_key:
duk_pop(thr);
continue;
}
/* XXX: Missing trap result validation for non-configurable target keys
* (must be present), for non-extensible target all target keys must be
* present and no extra keys can be present.
* http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
*/
/* XXX: The key enumerability check should trigger the "getOwnPropertyDescriptor"
* trap which has not yet been implemented. In the absence of such a trap,
* the enumerability should be checked from the target object; this is
* handled above.
*/
}
#endif /* DUK_USE_ES6_PROXY */
#if defined(DUK_USE_ES6_PROXY)
DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_hthread *thr) {
DUK_ASSERT_TOP(thr, 2); /* [ target handler ] */
duk_require_constructor_call(thr);
duk_push_proxy(thr, 0 /*flags*/); /* [ target handler ] -> [ proxy ] */
return 1; /* replacement */
}
#endif /* DUK_USE_ES6_PROXY */

View file

@ -1,99 +0,0 @@
/*
* 'Reflect' built-in (ES2016 Section 26.1)
* http://www.ecma-international.org/ecma-262/7.0/#sec-reflect-object
*
* Many Reflect built-in functions are provided by shared helpers in
* duk_bi_object.c or duk_bi_function.c.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_REFLECT_BUILTIN)
DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t ret;
DUK_ASSERT_TOP(thr, 2);
(void) duk_require_hobject(thr, 0);
(void) duk_to_string(thr, 1);
/* [ target key ] */
DUK_ASSERT(thr != NULL);
tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/);
duk_push_boolean(thr, ret);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_idx_t nargs;
DUK_ASSERT(thr != NULL);
nargs = duk_get_top_require_min(thr, 2 /*min_top*/);
(void) duk_require_hobject(thr, 0);
(void) duk_to_string(thr, 1);
if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) {
/* XXX: [[Get]] receiver currently unsupported */
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return 0;);
}
/* [ target key receiver? ...? ] */
tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
(void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_bool_t ret;
DUK_ASSERT(thr != NULL);
DUK_ASSERT_TOP(thr, 2);
(void) duk_require_hobject(thr, 0);
(void) duk_to_string(thr, 1);
/* [ target key ] */
tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
ret = duk_hobject_hasprop(thr, tv_obj, tv_key);
duk_push_boolean(thr, ret);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) {
duk_tval *tv_obj;
duk_tval *tv_key;
duk_tval *tv_val;
duk_idx_t nargs;
duk_bool_t ret;
DUK_ASSERT(thr != NULL);
nargs = duk_get_top_require_min(thr, 3 /*min_top*/);
(void) duk_require_hobject(thr, 0);
(void) duk_to_string(thr, 1);
if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) {
/* XXX: [[Set]] receiver currently unsupported */
DUK_ERROR_UNSUPPORTED(thr);
DUK_WO_NORETURN(return 0;);
}
/* [ target key value receiver? ...? ] */
tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
tv_val = DUK_GET_TVAL_POSIDX(thr, 2);
ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/);
duk_push_boolean(thr, ret);
return 1;
}
#endif /* DUK_USE_REFLECT_BUILTIN */

View file

@ -1,226 +0,0 @@
/*
* RegExp built-ins
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_REGEXP_SUPPORT)
DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) {
duk_hobject *h;
duk_push_this(thr);
h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP);
DUK_ASSERT(h != NULL);
DUK_UNREF(h);
duk_insert(thr, 0); /* prepend regexp to valstack 0 index */
}
/* XXX: much to improve (code size) */
DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_hthread *thr) {
duk_hobject *h_pattern;
DUK_ASSERT_TOP(thr, 2);
h_pattern = duk_get_hobject(thr, 0);
if (!duk_is_constructor_call(thr) &&
h_pattern != NULL &&
DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
duk_is_undefined(thr, 1)) {
/* Called as a function, pattern has [[Class]] "RegExp" and
* flags is undefined -> return object as is.
*/
/* XXX: ES2015 has a NewTarget SameValue() check which is not
* yet implemented.
*/
duk_dup_0(thr);
return 1;
}
/* Else functionality is identical for function call and constructor
* call.
*/
if (h_pattern != NULL &&
DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_SOURCE);
if (duk_is_undefined(thr, 1)) {
/* In ES5 one would need to read the flags individually;
* in ES2015 just read .flags.
*/
duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
} else {
/* In ES2015 allowed; overrides argument RegExp flags. */
duk_dup_1(thr);
}
} else {
if (duk_is_undefined(thr, 0)) {
duk_push_hstring_empty(thr);
} else {
duk_dup_0(thr);
duk_to_string(thr, -1); /* Rejects Symbols. */
}
if (duk_is_undefined(thr, 1)) {
duk_push_hstring_empty(thr);
} else {
duk_dup_1(thr);
duk_to_string(thr, -1); /* Rejects Symbols. */
}
/* [ ... pattern flags ] */
}
DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
(duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
/* [ ... pattern flags ] (both uncoerced) */
duk_to_string(thr, -2);
duk_to_string(thr, -1);
duk_regexp_compile(thr);
/* [ ... bytecode escaped_source ] */
duk_regexp_create_instance(thr);
/* [ ... RegExp ] */
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_hthread *thr) {
duk__get_this_regexp(thr);
/* [ regexp input ] */
duk_regexp_match(thr);
/* [ result ] */
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_hthread *thr) {
duk__get_this_regexp(thr);
/* [ regexp input ] */
/* result object is created and discarded; wasteful but saves code space */
duk_regexp_match(thr);
/* [ result ] */
duk_push_boolean(thr, (duk_is_null(thr, -1) ? 0 : 1));
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) {
/* This must be generic in ES2015 and later. */
DUK_ASSERT_TOP(thr, 0);
duk_push_this(thr);
duk_push_literal(thr, "/");
duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE);
duk_dup_m2(thr); /* another "/" */
duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
duk_concat(thr, 4);
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_hthread *thr) {
/* .flags is ES2015 but present even when ES2015 bindings are
* disabled because the constructor relies on it.
*/
duk_uint8_t buf[8]; /* enough for all flags + NUL */
duk_uint8_t *p = buf;
/* .flags is generic and works on any object. */
duk_push_this(thr);
(void) duk_require_hobject(thr, -1);
if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL)) {
*p++ = DUK_ASC_LC_G;
}
if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_IGNORE_CASE, NULL)) {
*p++ = DUK_ASC_LC_I;
}
if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_MULTILINE, NULL)) {
*p++ = DUK_ASC_LC_M;
}
/* .unicode: to be added */
/* .sticky: to be added */
*p++ = DUK_ASC_NUL;
DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf));
duk_push_string(thr, (const char *) buf);
return 1;
}
/* Shared helper for providing .source, .global, .multiline, etc getters. */
DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) {
duk_hstring *h_bc;
duk_small_uint_t re_flags;
duk_hobject *h;
duk_int_t magic;
DUK_ASSERT_TOP(thr, 0);
duk_push_this(thr);
h = duk_require_hobject(thr, -1);
magic = duk_get_current_magic(thr);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) {
duk_xget_owndataprop_stridx_short(thr, 0, DUK_STRIDX_INT_SOURCE);
duk_xget_owndataprop_stridx_short(thr, 0, DUK_STRIDX_INT_BYTECODE);
h_bc = duk_require_hstring(thr, -1);
re_flags = (duk_small_uint_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */
duk_pop(thr);
} else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) {
/* In ES2015 and ES2016 a TypeError would be thrown here.
* However, this had real world issues so ES2017 draft
* allows RegExp.prototype specifically, returning '(?:)'
* for .source and undefined for all flags.
*/
if (magic != 16 /* .source */) {
return 0;
}
duk_push_literal(thr, "(?:)"); /* .source handled by switch-case */
re_flags = 0;
} else {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}
/* [ regexp source ] */
switch (magic) {
case 0: { /* global */
duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_GLOBAL));
break;
}
case 1: { /* ignoreCase */
duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
break;
}
case 2: { /* multiline */
duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_MULTILINE));
break;
}
#if 0
/* Don't provide until implemented to avoid interfering with feature
* detection in user code.
*/
case 3: /* sticky */
case 4: { /* unicode */
duk_push_false(thr);
break;
}
#endif
default: { /* source */
/* leave 'source' on top */
break;
}
}
return 1;
}
#endif /* DUK_USE_REGEXP_SUPPORT */

File diff suppressed because it is too large Load diff

View file

@ -1,170 +0,0 @@
/*
* Symbol built-in
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_SYMBOL_BUILTIN)
/*
* Constructor
*/
DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) {
const duk_uint8_t *desc;
duk_size_t len;
duk_uint8_t *buf;
duk_uint8_t *p;
duk_int_t magic;
magic = duk_get_current_magic(thr);
if (duk_is_undefined(thr, 0) && (magic == 0)) {
/* Symbol() accepts undefined and empty string, but they are
* treated differently.
*/
desc = NULL;
len = 0;
} else {
/* Symbol.for() coerces undefined to 'undefined' */
desc = (const duk_uint8_t *) duk_to_lstring(thr, 0, &len);
}
/* Maximum symbol data length:
* +1 initial byte (0x80 or 0x81)
* +len description
* +1 0xff after description, before unique suffix
* +17 autogenerated unique suffix: 'ffffffff-ffffffff' is longest
* +1 0xff after unique suffix for symbols with undefined description
*/
buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1);
DUK_ASSERT(buf != NULL);
p = buf + 1;
DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */
duk_memcpy_unsafe((void *) p, (const void *) desc, len);
p += len;
if (magic == 0) {
/* Symbol(): create unique symbol. Use two 32-bit values
* to avoid dependency on 64-bit types and 64-bit integer
* formatting (at least for now).
*/
if (++thr->heap->sym_counter[0] == 0) {
thr->heap->sym_counter[1]++;
}
p += DUK_SPRINTF((char *) p, "\xFF" "%lx-%lx",
(unsigned long) thr->heap->sym_counter[1],
(unsigned long) thr->heap->sym_counter[0]);
if (desc == NULL) {
/* Special case for 'undefined' description, trailing
* 0xff distinguishes from empty string description,
* but needs minimal special case handling elsewhere.
*/
*p++ = 0xff;
}
buf[0] = 0x81;
} else {
/* Symbol.for(): create a global symbol */
buf[0] = 0x80;
}
duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(thr, -1)));
return 1;
}
DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_hthread *thr, duk_tval *tv_arg) {
duk_tval *tv;
duk_hobject *h_obj;
duk_hstring *h_str;
DUK_ASSERT(tv_arg != NULL);
/* XXX: add internal helper: duk_auto_unbox_tval(thr, tv, mask); */
/* XXX: add internal helper: duk_auto_unbox(thr, tv, idx); */
tv = tv_arg;
if (DUK_TVAL_IS_OBJECT(tv)) {
h_obj = DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h_obj != NULL);
if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) {
tv = duk_hobject_get_internal_value_tval_ptr(thr->heap, h_obj);
if (tv == NULL) {
return NULL;
}
} else {
return NULL;
}
}
if (!DUK_TVAL_IS_STRING(tv)) {
return NULL;
}
h_str = DUK_TVAL_GET_STRING(tv);
DUK_ASSERT(h_str != NULL);
/* Here symbol is more expected than not. */
if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) {
return NULL;
}
return h_str;
}
DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_hthread *thr) {
duk_hstring *h_str;
h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
if (h_str == NULL) {
return DUK_RET_TYPE_ERROR;
}
if (duk_get_current_magic(thr) == 0) {
/* .toString() */
duk_push_symbol_descriptive_string(thr, h_str);
} else {
/* .valueOf() */
duk_push_hstring(thr, h_str);
}
return 1;
}
DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_hthread *thr) {
duk_hstring *h;
const duk_uint8_t *p;
/* Argument must be a symbol but not checked here. The initial byte
* check will catch non-symbol strings.
*/
h = duk_require_hstring(thr, 0);
DUK_ASSERT(h != NULL);
p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
DUK_ASSERT(p != NULL);
/* Even for zero length strings there's at least one NUL byte so
* we can safely check the initial byte.
*/
if (p[0] == 0x80) {
/* Global symbol, return its key (bytes just after the initial byte). */
duk_push_lstring(thr, (const char *) (p + 1), (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h) - 1));
return 1;
} else if (p[0] == 0x81 || p[0] == 0x82 || p[0] == 0xff) {
/* Local symbol or hidden symbol, return undefined. */
return 0;
}
/* Covers normal strings and unknown initial bytes. */
return DUK_RET_TYPE_ERROR;
}
DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_hthread *thr) {
duk_hstring *h_str;
h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
if (h_str == NULL) {
return DUK_RET_TYPE_ERROR;
}
duk_push_hstring(thr, h_str);
return 1;
}
#endif /* DUK_USE_SYMBOL_BUILTIN */

View file

@ -1,326 +0,0 @@
/*
* Thread builtins
*/
#include "third_party/duktape/duk_internal.h"
/*
* Constructor
*/
#if defined(DUK_USE_COROUTINE_SUPPORT)
DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) {
duk_hthread *new_thr;
duk_hobject *func;
/* Check that the argument is callable; this is not 100% because we
* don't allow native functions to be a thread's initial function.
* Resume will reject such functions in any case.
*/
/* XXX: need a duk_require_func_promote_lfunc() */
func = duk_require_hobject_promote_lfunc(thr, 0);
DUK_ASSERT(func != NULL);
duk_require_callable(thr, 0);
duk_push_thread(thr);
new_thr = (duk_hthread *) duk_known_hobject(thr, -1);
new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
/* push initial function call to new thread stack; this is
* picked up by resume().
*/
duk_push_hobject(new_thr, func);
return 1; /* return thread */
}
#endif
/*
* Resume a thread.
*
* The thread must be in resumable state, either (a) new thread which hasn't
* yet started, or (b) a thread which has previously yielded. This method
* must be called from an ECMAScript function.
*
* Args:
* - thread
* - value
* - isError (defaults to false)
*
* Note: yield and resume handling is currently asymmetric.
*/
#if defined(DUK_USE_COROUTINE_SUPPORT)
DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_hthread *thr_resume;
duk_hobject *caller_func;
duk_small_uint_t is_error;
DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
(duk_tval *) duk_get_tval(thr, 0),
(duk_tval *) duk_get_tval(thr, 1),
(duk_tval *) duk_get_tval(thr, 2)));
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->heap->curr_thread == thr);
thr_resume = duk_require_hthread(thr, 0);
DUK_ASSERT(duk_get_top(thr) == 3);
is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
DUK_ASSERT(duk_get_top(thr) == 2);
/* [ thread value ] */
/*
* Thread state and calling context checks
*/
if (thr->callstack_top < 2) {
DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
goto state_error;
}
DUK_ASSERT(thr->callstack_curr != NULL);
DUK_ASSERT(thr->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
DUK_DD(DUK_DDPRINT("resume state invalid: caller must be ECMAScript code"));
goto state_error;
}
/* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
* like for yield.
*/
if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
goto state_error;
}
DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
/* Further state-dependent pre-checks */
if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
/* no pre-checks now, assume a previous yield() has left things in
* tip-top shape (longjmp handler will assert for these).
*/
} else {
duk_hobject *h_fun;
DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
/* The initial function must be an ECMAScript function (but
* can be bound). We must make sure of that before we longjmp
* because an error in the RESUME handler call processing will
* not be handled very cleanly.
*/
if ((thr_resume->callstack_top != 0) ||
(thr_resume->valstack_top - thr_resume->valstack != 1)) {
goto state_error;
}
duk_push_tval(thr, DUK_GET_TVAL_NEGIDX(thr_resume, -1));
duk_resolve_nonbound_function(thr);
h_fun = duk_require_hobject(thr, -1); /* reject lightfuncs on purpose */
if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) {
goto state_error;
}
duk_pop(thr);
}
#if 0
/* This check would prevent a heap destruction time finalizer from
* launching a coroutine, which would ensure that during finalization
* 'thr' would always equal heap_thread. Normal runtime finalizers
* run with ms_running == 0, i.e. outside mark-and-sweep. See GH-2030.
*/
if (thr->heap->ms_running) {
DUK_D(DUK_DPRINT("refuse Duktape.Thread.resume() when ms_running != 0"));
goto state_error;
}
#endif
/*
* The error object has been augmented with a traceback and other
* info from its creation point -- usually another thread. The
* error handler is called here right before throwing, but it also
* runs in the resumer's thread. It might be nice to get a traceback
* from the resumee but this is not the case now.
*/
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
if (is_error) {
DUK_ASSERT_TOP(thr, 2); /* value (error) is at stack top */
duk_err_augment_error_throw(thr); /* in resumer's context */
}
#endif
#if defined(DUK_USE_DEBUG)
if (is_error) {
DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
(duk_tval *) duk_get_tval(thr, 0),
(duk_tval *) duk_get_tval(thr, 1)));
} else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
(duk_tval *) duk_get_tval(thr, 0),
(duk_tval *) duk_get_tval(thr, 1)));
} else {
DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
(duk_tval *) duk_get_tval(thr, 0),
(duk_tval *) duk_get_tval(thr, 1)));
}
#endif
thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
/* lj value2: thread */
DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */
/* lj value1: value */
DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
thr->heap->lj.iserror = is_error;
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
DUK_UNREACHABLE();
/* Never here, fall through to error (from compiler point of view). */
state_error:
DUK_DCERROR_TYPE_INVALID_STATE(thr);
}
#endif
/*
* Yield the current thread.
*
* The thread must be in yieldable state: it must have a resumer, and there
* must not be any yield-preventing calls (native calls and constructor calls,
* currently) in the thread's call stack (otherwise a resume would not be
* possible later). This method must be called from an ECMAScript function.
*
* Args:
* - value
* - isError (defaults to false)
*
* Note: yield and resume handling is currently asymmetric.
*/
#if defined(DUK_USE_COROUTINE_SUPPORT)
DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) {
duk_hobject *caller_func;
duk_small_uint_t is_error;
DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
(duk_tval *) duk_get_tval(thr, 0),
(duk_tval *) duk_get_tval(thr, 1)));
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
DUK_ASSERT(thr->heap->curr_thread == thr);
DUK_ASSERT(duk_get_top(thr) == 2);
is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
DUK_ASSERT(duk_get_top(thr) == 1);
/* [ value ] */
/*
* Thread state and calling context checks
*/
if (!thr->resumer) {
DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
goto state_error;
}
DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
if (thr->callstack_top < 2) {
DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
goto state_error;
}
DUK_ASSERT(thr->callstack_curr != NULL);
DUK_ASSERT(thr->callstack_curr->parent != NULL);
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL); /* us */
DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL); /* caller */
caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
DUK_DD(DUK_DDPRINT("yield state invalid: caller must be ECMAScript code"));
goto state_error;
}
DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
if (thr->callstack_preventcount != 1) {
/* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
(long) thr->callstack_preventcount));
goto state_error;
}
/*
* The error object has been augmented with a traceback and other
* info from its creation point -- usually the current thread.
* The error handler, however, is called right before throwing
* and runs in the yielder's thread.
*/
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
if (is_error) {
DUK_ASSERT_TOP(thr, 1); /* value (error) is at stack top */
duk_err_augment_error_throw(thr); /* in yielder's context */
}
#endif
#if defined(DUK_USE_DEBUG)
if (is_error) {
DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
(duk_tval *) duk_get_tval(thr, 0)));
} else {
DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
(duk_tval *) duk_get_tval(thr, 0)));
}
#endif
/*
* Process yield
*
* After longjmp(), processing continues in bytecode executor longjmp
* handler, which will e.g. update thr->resumer to NULL.
*/
thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
/* lj value1: value */
DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
thr->heap->lj.iserror = is_error;
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
DUK_UNREACHABLE();
/* Never here, fall through to error (from compiler point of view). */
state_error:
DUK_DCERROR_TYPE_INVALID_STATE(thr);
}
#endif
#if defined(DUK_USE_COROUTINE_SUPPORT)
DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_hthread *thr) {
duk_push_current_thread(thr);
return 1;
}
#endif

View file

@ -1,9 +0,0 @@
/*
* Type error thrower, E5 Section 13.2.3.
*/
#include "third_party/duktape/duk_internal.h"
DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_hthread *thr) {
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
}

View file

@ -1,861 +0,0 @@
/*
* Automatically generated by genbuiltins.py, do not edit!
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_ASSERTIONS)
#define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/
#else
#define DUK__REFCINIT(refc) (refc) /*actual*/
#endif
#if defined(DUK_USE_ROM_STRINGS)
#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
DUK_INTERNAL const duk_uint8_t duk_strings_data[972] = {
79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224,
193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32,
196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8,
196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11,
229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10,
183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32,
184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64,
178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18,
32,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156,
113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115,
119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137,
101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75,
226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64,
52,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133,
67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2,
249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226,
231,146,51,192,204,73,140,224,145,221,102,241,68,196,169,248,30,75,12,11,
151,242,233,187,143,138,24,137,162,164,255,253,63,3,201,97,129,114,254,92,
112,75,136,108,166,6,136,159,255,167,224,121,44,48,46,95,203,166,238,74,
113,67,77,201,128,223,255,223,224,121,44,48,46,95,203,145,46,9,205,16,39,
201,62,36,0,192,21,147,255,238,145,39,199,197,211,116,240,242,113,197,78,
214,211,226,233,187,107,105,19,119,37,56,161,166,52,221,212,201,205,36,240,
242,16,96,152,12,26,20,164,137,150,70,154,103,28,137,50,202,96,18,132,241,
41,104,105,56,218,48,36,138,183,57,56,128,68,24,38,2,52,12,34,10,133,147,
141,3,8,119,185,13,153,34,125,206,76,17,49,38,93,206,52,151,154,119,56,28,
76,130,112,200,141,206,21,209,96,23,35,238,114,160,139,0,243,238,114,78,
164,68,68,110,113,226,210,90,26,66,110,113,128,121,247,57,80,68,141,170,
183,56,84,52,11,70,73,19,110,114,160,93,8,113,57,143,66,200,84,53,244,154,
73,24,240,81,32,38,68,18,49,228,207,23,88,100,109,70,114,92,193,4,137,173,
168,36,220,73,19,247,247,182,168,209,144,187,223,58,156,104,79,190,183,127,
123,105,160,110,247,206,167,26,19,239,173,223,222,218,67,75,189,243,169,
198,132,251,235,183,247,182,154,134,151,123,231,83,141,9,247,215,111,239,
109,22,141,22,247,206,167,26,19,239,172,223,218,45,26,47,157,78,52,39,223,
74,24,144,10,32,129,34,20,64,152,142,129,57,179,67,104,68,12,129,161,140,
72,156,100,40,40,185,152,100,89,38,65,13,196,34,228,67,149,13,2,215,129,
149,209,65,104,209,77,14,104,144,81,33,170,67,101,48,52,68,113,70,210,88,
209,36,233,22,154,86,68,196,114,76,232,145,102,120,186,195,156,112,105,225,
228,113,71,80,68,162,115,101,50,85,200,25,108,116,44,132,178,38,114,137,96,
148,136,70,209,134,37,222,232,204,228,188,200,209,200,200,99,221,25,150,84,
121,34,70,209,107,36,227,66,20,160,92,136,164,49,235,35,8,217,201,40,108,
201,18,128,68,26,201,51,188,2,80,12,67,190,40,168,38,68,190,46,153,5,50,12,
207,160,86,129,26,83,4,208,34,225,4,88,192,
};
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_OBJECTS */
/* native functions: 185 */
DUK_INTERNAL const duk_c_function duk_bi_native_functions[185] = {
NULL,
duk_bi_array_constructor,
duk_bi_array_constructor_is_array,
duk_bi_array_prototype_concat,
duk_bi_array_prototype_indexof_shared,
duk_bi_array_prototype_iter_shared,
duk_bi_array_prototype_join_shared,
duk_bi_array_prototype_pop,
duk_bi_array_prototype_push,
duk_bi_array_prototype_reduce_shared,
duk_bi_array_prototype_reverse,
duk_bi_array_prototype_shift,
duk_bi_array_prototype_slice,
duk_bi_array_prototype_sort,
duk_bi_array_prototype_splice,
duk_bi_array_prototype_to_string,
duk_bi_array_prototype_unshift,
duk_bi_arraybuffer_constructor,
duk_bi_arraybuffer_isview,
duk_bi_boolean_constructor,
duk_bi_boolean_prototype_tostring_shared,
duk_bi_buffer_compare_shared,
duk_bi_buffer_readfield,
duk_bi_buffer_slice_shared,
duk_bi_buffer_writefield,
duk_bi_cbor_decode,
duk_bi_cbor_encode,
duk_bi_dataview_constructor,
duk_bi_date_constructor,
duk_bi_date_constructor_now,
duk_bi_date_constructor_parse,
duk_bi_date_constructor_utc,
duk_bi_date_prototype_get_shared,
duk_bi_date_prototype_get_timezone_offset,
duk_bi_date_prototype_set_shared,
duk_bi_date_prototype_set_time,
duk_bi_date_prototype_to_json,
duk_bi_date_prototype_toprimitive,
duk_bi_date_prototype_tostring_shared,
duk_bi_date_prototype_value_of,
duk_bi_duktape_object_act,
duk_bi_duktape_object_compact,
duk_bi_duktape_object_dec,
duk_bi_duktape_object_enc,
duk_bi_duktape_object_fin,
duk_bi_duktape_object_gc,
duk_bi_duktape_object_info,
duk_bi_error_constructor_shared,
duk_bi_error_prototype_filename_getter,
duk_bi_error_prototype_filename_setter,
duk_bi_error_prototype_linenumber_getter,
duk_bi_error_prototype_linenumber_setter,
duk_bi_error_prototype_stack_getter,
duk_bi_error_prototype_stack_setter,
duk_bi_error_prototype_to_string,
duk_bi_function_constructor,
duk_bi_function_prototype,
duk_bi_function_prototype_apply,
duk_bi_function_prototype_bind,
duk_bi_function_prototype_call,
duk_bi_function_prototype_hasinstance,
duk_bi_function_prototype_to_string,
duk_bi_global_object_decode_uri,
duk_bi_global_object_decode_uri_component,
duk_bi_global_object_encode_uri,
duk_bi_global_object_encode_uri_component,
duk_bi_global_object_escape,
duk_bi_global_object_eval,
duk_bi_global_object_is_finite,
duk_bi_global_object_is_nan,
duk_bi_global_object_parse_float,
duk_bi_global_object_parse_int,
duk_bi_global_object_unescape,
duk_bi_json_object_parse,
duk_bi_json_object_stringify,
duk_bi_math_object_clz32,
duk_bi_math_object_hypot,
duk_bi_math_object_imul,
duk_bi_math_object_max,
duk_bi_math_object_min,
duk_bi_math_object_onearg_shared,
duk_bi_math_object_random,
duk_bi_math_object_sign,
duk_bi_math_object_twoarg_shared,
duk_bi_native_function_length,
duk_bi_native_function_name,
duk_bi_nodejs_buffer_byte_length,
duk_bi_nodejs_buffer_concat,
duk_bi_nodejs_buffer_constructor,
duk_bi_nodejs_buffer_copy,
duk_bi_nodejs_buffer_fill,
duk_bi_nodejs_buffer_is_buffer,
duk_bi_nodejs_buffer_is_encoding,
duk_bi_nodejs_buffer_tojson,
duk_bi_nodejs_buffer_tostring,
duk_bi_nodejs_buffer_write,
duk_bi_number_check_shared,
duk_bi_number_constructor,
duk_bi_number_prototype_to_exponential,
duk_bi_number_prototype_to_fixed,
duk_bi_number_prototype_to_locale_string,
duk_bi_number_prototype_to_precision,
duk_bi_number_prototype_to_string,
duk_bi_number_prototype_value_of,
duk_bi_object_constructor,
duk_bi_object_constructor_assign,
duk_bi_object_constructor_create,
duk_bi_object_constructor_define_properties,
duk_bi_object_constructor_define_property,
duk_bi_object_constructor_get_own_property_descriptor,
duk_bi_object_constructor_is,
duk_bi_object_constructor_is_extensible,
duk_bi_object_constructor_is_sealed_frozen_shared,
duk_bi_object_constructor_keys_shared,
duk_bi_object_constructor_prevent_extensions,
duk_bi_object_constructor_seal_freeze_shared,
duk_bi_object_getprototype_shared,
duk_bi_object_prototype_defineaccessor,
duk_bi_object_prototype_has_own_property,
duk_bi_object_prototype_is_prototype_of,
duk_bi_object_prototype_lookupaccessor,
duk_bi_object_prototype_property_is_enumerable,
duk_bi_object_prototype_to_locale_string,
duk_bi_object_prototype_to_string,
duk_bi_object_prototype_value_of,
duk_bi_object_setprototype_shared,
duk_bi_performance_now,
duk_bi_pointer_constructor,
duk_bi_pointer_prototype_tostring_shared,
duk_bi_proxy_constructor,
duk_bi_reflect_apply,
duk_bi_reflect_construct,
duk_bi_reflect_object_delete_property,
duk_bi_reflect_object_get,
duk_bi_reflect_object_has,
duk_bi_reflect_object_set,
duk_bi_regexp_constructor,
duk_bi_regexp_prototype_exec,
duk_bi_regexp_prototype_flags,
duk_bi_regexp_prototype_shared_getter,
duk_bi_regexp_prototype_test,
duk_bi_regexp_prototype_tostring,
duk_bi_string_constructor,
duk_bi_string_constructor_from_char_code,
duk_bi_string_constructor_from_code_point,
duk_bi_string_prototype_caseconv_shared,
duk_bi_string_prototype_char_at,
duk_bi_string_prototype_char_code_at,
duk_bi_string_prototype_concat,
duk_bi_string_prototype_includes,
duk_bi_string_prototype_indexof_shared,
duk_bi_string_prototype_locale_compare,
duk_bi_string_prototype_match,
duk_bi_string_prototype_repeat,
duk_bi_string_prototype_replace,
duk_bi_string_prototype_search,
duk_bi_string_prototype_slice,
duk_bi_string_prototype_split,
duk_bi_string_prototype_startswith_endswith,
duk_bi_string_prototype_substr,
duk_bi_string_prototype_substring,
duk_bi_string_prototype_to_string,
duk_bi_string_prototype_trim,
duk_bi_symbol_constructor_shared,
duk_bi_symbol_key_for,
duk_bi_symbol_toprimitive,
duk_bi_symbol_tostring_shared,
duk_bi_textdecoder_constructor,
duk_bi_textdecoder_prototype_decode,
duk_bi_textdecoder_prototype_shared_getter,
duk_bi_textencoder_constructor,
duk_bi_textencoder_prototype_encode,
duk_bi_textencoder_prototype_encoding_getter,
duk_bi_thread_constructor,
duk_bi_thread_current,
duk_bi_thread_resume,
duk_bi_thread_yield,
duk_bi_type_error_thrower,
duk_bi_typedarray_buffer_getter,
duk_bi_typedarray_bytelength_getter,
duk_bi_typedarray_byteoffset_getter,
duk_bi_typedarray_constructor,
duk_bi_typedarray_set,
duk_bi_uint8array_allocplain,
duk_bi_uint8array_plainof,
};
#if defined(DUK_USE_DOUBLE_LE)
DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = {
144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245,
124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33,
167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228,
64,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46,
142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240,
242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0,
1,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
33,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237,
198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181,
10,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62,
53,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45,
84,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53,
109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61,
11,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232,
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,
155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,23,
194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104,
137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156,
36,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5,
209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85,
144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30,
122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19,
136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137,
195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13,
17,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154,
2,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205,
35,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11,
174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32,
0,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12,
73,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199,
89,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40,
144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26,
78,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23,
196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249,
132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8,
162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164,
160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224,
151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242,
113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84,
129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144,
168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147,
153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212,
36,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163,
203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17,
136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189,
207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11,
37,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103,
44,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138,
231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1,
30,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5,
196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56,
35,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135,
34,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4,
120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115,
68,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23,
228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15,
18,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39,
249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4,
102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4,
9,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12,
255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26,
57,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246,
130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84,
11,161,32,127,255,255,255,255,255,247,191,137,235,16,221,170,129,116,36,0,
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,
74,134,162,120,128,0,0,0,0,0,1,224,254,71,173,33,129,52,84,155,72,105,80,
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,
33,214,2,251,82,1,73,180,134,204,134,36,96,127,255,255,255,255,255,159,161,
144,235,16,221,169,0,164,218,67,102,67,18,48,63,255,255,255,255,255,207,
240,196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34,
92,42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187,
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,
0,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238,
18,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3,
5,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,0,0,0,
0,0,0,248,127,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155,
185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193,
130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41,
197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77,
12,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139,
218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210,
98,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16,
250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97,
40,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10,
49,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97,
56,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28,
173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51,
168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89,
18,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149,
210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62,
72,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5,
72,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146,
186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82,
50,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151,
74,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103,
186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189,
162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2,
55,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127,
48,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94,
82,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207,
144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21,
221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32,
105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104,
137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
72,115,96,0,0,0,0,96,2,106,32,91,60,165,195,201,194,8,134,149,216,162,0,
192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
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,
216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
20,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96,
68,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68,
159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148,
67,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194,
173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44,
140,35,103,0,0,0,0,0,0,3,192,252,206,25,228,35,208,226,100,150,211,201,29,
162,44,140,35,103,0,0,0,0,0,0,3,192,252,206,25,244,35,208,226,100,150,211,
201,29,162,44,140,35,103,0,0,0,0,0,0,3,192,252,206,26,4,35,208,226,100,150,
211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,1,0,206,26,20,35,208,226,100,
150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,1,0,206,26,36,35,208,226,
100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,52,35,208,
226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,68,35,
208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,65,0,206,26,84,
35,208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,0,0,0,0,129,0,195,
154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150,
25,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232,
235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7,
196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80,
200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165,
213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10,
183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224,
221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128,
31,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19,
18,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153,
59,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19,
39,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232,
73,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27,
61,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217,
67,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103,
167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209,
68,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104,
193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2,
178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76,
157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180,
81,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196,
133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0,
22,209,68,201,187,129,4,2,8,3,132,64,60,36,6,149,113,72,176,171,240,84,0,
157,91,116,116,32,11,42,218,221,216,181,129,32,3,234,219,165,3,188,231,235,
249,8,187,152,252,47,86,227,105,18,7,244,17,91,42,56,175,185,248,110,173,
198,209,208,36,0,238,82,97,87,188,189,179,240,93,122,32,12,22,162,42,125,
144,132,160,7,236,161,25,232,237,105,64,205,59,127,102,158,160,230,63,11,
217,66,51,210,129,154,118,254,205,61,65,236,127,171,197,34,168,48,6,90,194,
1,0,39,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,
65,6,51,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,
80,0,201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,
69,234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,
165,1,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,
107,64,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,
132,103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,
145,52,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,
104,146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,
56,18,52,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,
47,129,6,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,
15,155,163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,
36,3,17,46,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,
248,75,204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,
206,9,113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,
178,66,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,
38,232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,
38,3,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,
202,160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,
0,0,179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,
181,192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,
121,35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,153,188,56,132,122,28,76,
146,218,121,35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,168,160,45,110,23,
30,176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,
153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63,51,120,145,8,244,
56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,120,161,8,
244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,120,177,
8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,120,
193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,
120,209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,
51,120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,32,
64,32,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,
137,112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,
34,74,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,
8,35,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,
117,96,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,
32,148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,
238,2,3,107,173,218,3,192,
};
#elif defined(DUK_USE_DOUBLE_BE)
DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = {
144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245,
124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33,
167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228,
64,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46,
142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240,
242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0,
1,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
33,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237,
198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181,
10,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62,
53,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45,
84,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53,
109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61,
11,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232,
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,
155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,23,
194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104,
137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156,
36,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5,
209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85,
144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30,
122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19,
136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137,
195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13,
17,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154,
2,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205,
35,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11,
174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32,
0,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12,
73,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199,
89,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40,
144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26,
78,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23,
196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249,
132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8,
162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164,
160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224,
151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242,
113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84,
129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144,
168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147,
153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212,
36,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163,
203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17,
136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189,
207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11,
37,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103,
44,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138,
231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1,
30,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5,
196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56,
35,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135,
34,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4,
120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115,
68,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23,
228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15,
18,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39,
249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4,
102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4,
9,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12,
255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26,
57,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246,
130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84,
11,161,32,63,247,255,255,255,255,255,255,137,235,16,221,170,129,116,36,0,0,
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,
134,162,120,128,255,224,0,0,0,0,0,0,71,173,33,129,52,84,155,72,105,80,212,
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,
214,2,251,82,1,73,180,134,204,134,36,96,33,159,255,255,255,255,255,255,144,
235,16,221,169,0,164,218,67,102,67,18,48,48,207,255,255,255,255,255,255,
196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34,92,
42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187,
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,
0,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238,
18,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3,
5,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,127,
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,
185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193,
130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41,
197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77,
12,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139,
218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210,
98,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16,
250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97,
40,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10,
49,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97,
56,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28,
173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51,
168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89,
18,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149,
210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62,
72,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5,
72,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146,
186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82,
50,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151,
74,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103,
186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189,
162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2,
55,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127,
48,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94,
82,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207,
144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21,
221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32,
105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104,
137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
72,115,96,32,106,2,96,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,
192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
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,
216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
20,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96,
68,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68,
159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148,
67,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194,
173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44,
140,35,103,0,255,192,0,0,0,0,0,0,206,25,228,35,208,226,100,150,211,201,29,
162,44,140,35,103,0,255,192,0,0,0,0,0,0,206,25,244,35,208,226,100,150,211,
201,29,162,44,140,35,103,0,255,192,0,0,0,0,0,0,206,26,4,35,208,226,100,150,
211,201,29,162,44,140,35,103,1,0,0,0,0,0,0,0,0,206,26,20,35,208,226,100,
150,211,201,29,162,44,140,35,103,1,0,0,0,0,0,0,0,0,206,26,36,35,208,226,
100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,52,35,208,
226,100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,68,35,
208,226,100,150,211,201,29,162,44,140,35,103,1,0,64,0,0,0,0,0,0,206,26,84,
35,208,226,100,150,211,201,29,162,44,140,35,103,1,0,128,0,0,0,0,0,0,195,
154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150,
25,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232,
235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7,
196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80,
200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165,
213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10,
183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224,
221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128,
31,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19,
18,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153,
59,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19,
39,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232,
73,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27,
61,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217,
67,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103,
167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209,
68,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104,
193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2,
178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76,
157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180,
81,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196,
133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0,
22,209,68,201,187,129,4,2,8,3,132,64,60,36,4,0,91,240,168,177,69,118,144,
157,91,116,116,32,32,1,53,216,221,218,170,139,3,234,219,165,0,255,152,185,
11,251,232,231,188,47,86,227,105,18,1,255,184,170,59,41,92,23,240,110,173,
198,209,208,36,3,253,188,183,177,82,110,80,224,93,122,32,32,4,144,253,170,
34,22,140,7,236,161,25,232,237,105,64,63,230,160,158,102,127,59,205,11,217,
66,51,210,128,127,237,65,60,204,254,119,155,171,197,34,168,48,6,90,194,1,0,
39,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,65,6,
51,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,80,0,
201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,69,
234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,165,
1,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,107,
64,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,132,
103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,145,
52,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,104,
146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,56,18,
52,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,47,129,
6,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,
163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,36,3,17,
46,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,248,75,
204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,206,9,
113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,178,
66,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,38,
232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,38,
3,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,202,
160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,0,0,
179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,181,
192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,121,
35,180,69,145,132,108,224,31,248,0,0,0,0,0,0,25,188,56,132,122,28,76,146,
218,121,35,180,69,145,132,108,224,31,248,0,0,0,0,0,0,40,160,45,110,23,30,
176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,153,
37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,51,120,145,8,244,56,
153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,120,161,8,244,
56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,120,177,8,
244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,120,193,
8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,120,
209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,
120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,32,0,0,0,0,0,0,
32,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,137,
112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,34,
74,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,8,
35,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,117,
96,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,32,
148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,238,2,
3,107,173,218,3,192,
};
#elif defined(DUK_USE_DOUBLE_ME)
DUK_INTERNAL const duk_uint8_t duk_builtins_data[4281] = {
144,148,105,226,32,68,52,228,254,12,104,202,37,132,52,167,194,138,105,245,
124,57,28,211,57,18,64,52,239,126,44,138,111,175,241,164,19,87,145,30,33,
167,22,145,159,8,211,139,9,225,42,5,240,145,139,163,163,8,211,139,10,228,
64,211,19,132,140,93,29,56,70,156,88,119,34,66,146,36,104,137,194,70,46,
142,172,35,78,44,47,146,195,102,11,240,145,139,163,175,8,211,139,9,228,240,
242,112,145,139,163,179,8,211,139,8,237,34,130,118,49,116,118,225,26,48,0,
1,98,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
33,8,66,26,180,105,97,167,68,150,34,33,154,112,0,1,91,247,35,79,111,237,
198,174,232,47,31,23,95,17,13,31,249,96,211,49,50,53,214,77,141,24,0,0,181,
10,228,240,242,15,128,140,65,128,134,188,0,0,90,167,97,181,224,0,2,213,62,
53,224,0,2,213,66,237,120,0,0,181,81,204,107,192,0,5,170,150,67,94,0,0,45,
84,245,90,240,0,1,106,169,162,215,128,0,11,85,93,150,188,0,0,90,171,111,53,
109,22,162,26,48,0,1,84,23,201,146,243,225,26,39,12,145,136,104,192,0,5,61,
11,228,201,121,240,100,19,134,72,196,33,195,14,40,203,112,64,190,76,232,
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,
96,155,194,56,80,206,36,67,141,20,228,70,57,81,206,100,131,156,39,132,168,
23,194,70,46,137,208,21,200,129,166,39,9,24,186,39,72,119,34,66,146,36,104,
137,194,70,46,137,212,23,201,97,179,5,248,72,197,209,58,194,121,60,60,156,
36,98,232,157,129,29,164,80,78,198,46,137,218,146,121,25,71,146,9,209,5,
209,61,48,126,14,138,152,30,67,186,23,143,139,175,131,202,135,228,72,85,
144,83,60,179,30,94,209,233,102,30,98,105,230,103,30,114,121,231,104,30,
122,137,231,233,30,130,153,232,106,30,138,169,232,235,30,144,67,193,25,19,
136,108,207,30,41,224,140,137,194,173,192,153,228,5,242,100,188,248,70,137,
195,36,79,78,47,147,37,231,193,144,78,25,34,122,145,111,36,74,232,176,13,
17,61,234,226,93,207,148,160,84,75,141,7,27,161,32,33,18,225,80,212,76,154,
2,2,70,65,56,100,237,34,140,209,2,67,32,156,50,118,145,64,186,230,61,205,
35,103,155,32,36,141,19,134,78,210,40,206,16,36,70,137,195,39,105,20,11,
174,99,220,210,54,121,210,1,137,33,1,228,207,16,17,70,146,66,3,201,164,32,
0,65,112,152,56,196,159,31,23,77,211,195,201,199,23,160,72,214,246,81,6,12,
73,241,214,111,31,23,60,145,158,56,50,72,81,67,230,232,242,80,19,49,39,199,
89,188,124,92,242,70,120,227,64,194,75,154,72,12,9,73,6,111,21,120,12,40,
144,19,39,25,0,225,144,168,105,56,248,185,228,140,241,200,96,64,100,42,26,
78,62,46,121,35,52,18,92,116,1,36,64,47,158,64,49,98,66,100,156,242,65,23,
196,149,35,103,194,94,100,108,144,230,203,156,64,66,37,201,16,11,32,249,
132,4,34,92,44,93,146,55,152,72,24,137,112,151,153,27,36,5,100,229,144,8,
162,98,92,210,5,76,73,241,214,111,31,23,60,145,158,57,44,48,46,92,185,164,
160,72,151,41,0,50,107,179,244,59,36,93,127,92,6,19,172,3,11,216,0,56,224,
151,29,102,241,241,115,201,25,227,164,64,106,37,199,197,211,116,240,242,
113,197,233,144,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,84,
129,13,173,161,144,168,105,56,98,78,100,142,214,215,69,1,13,173,161,144,
168,105,57,34,78,100,142,214,215,69,16,67,107,105,110,114,168,254,24,147,
153,35,181,181,212,32,67,107,105,110,114,168,254,72,147,153,35,181,181,212,
36,65,130,3,144,8,26,252,200,13,30,85,16,16,64,90,242,231,192,64,161,163,
203,31,26,172,193,17,4,23,105,159,96,27,172,251,16,32,196,4,14,137,112,17,
136,48,164,28,134,80,215,202,1,132,130,8,12,39,52,64,155,31,24,56,36,1,189,
207,132,0,35,233,35,195,62,3,196,149,36,100,72,160,2,200,232,44,227,0,11,
37,160,68,142,128,36,157,25,200,32,26,79,90,4,73,43,192,122,54,71,65,103,
44,248,14,134,140,151,227,138,231,208,45,96,148,248,134,140,151,227,138,
231,240,1,255,254,10,74,146,56,128,104,4,147,152,72,6,144,28,174,143,8,1,
30,1,165,3,96,31,0,211,3,21,11,153,35,0,211,131,68,131,160,137,16,250,5,
196,131,160,137,200,160,199,156,67,248,0,255,255,65,140,10,48,177,115,56,
35,130,60,19,134,79,89,240,52,177,115,56,39,12,156,123,144,217,251,15,135,
34,167,30,20,170,154,255,232,12,47,244,0,97,28,17,224,39,238,32,40,71,4,
120,39,12,156,4,253,228,5,137,195,39,30,228,54,124,4,253,228,128,194,115,
68,9,252,15,128,232,104,201,126,56,191,35,64,90,193,41,241,13,25,47,199,23,
228,105,3,86,225,1,100,224,156,199,130,36,249,144,10,192,76,71,250,16,15,
18,61,96,17,62,200,3,72,128,136,143,247,32,22,75,64,137,248,64,22,79,90,39,
249,64,38,84,12,167,20,52,223,196,2,230,238,45,214,36,120,32,72,158,208,4,
102,238,45,194,2,201,197,186,196,143,4,9,19,218,0,92,221,202,61,228,143,4,
9,19,218,8,35,55,113,110,16,22,78,81,239,36,120,32,72,158,208,64,73,197,12,
255,0,13,18,60,128,159,212,128,169,76,17,156,185,100,76,255,163,64,65,26,
57,114,200,153,255,70,144,33,13,18,232,50,75,226,104,6,149,3,41,199,246,
130,12,128,28,142,156,120,203,175,158,8,194,207,1,6,81,20,79,88,11,237,84,
11,161,32,127,255,247,191,255,255,255,255,137,235,16,221,170,129,116,36,0,
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,
74,134,162,120,128,0,1,224,254,0,0,0,0,71,173,33,129,52,84,155,72,105,80,
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,
33,214,2,251,82,1,73,180,134,204,134,36,96,127,255,159,161,255,255,255,255,
144,235,16,221,169,0,164,218,67,102,67,18,48,63,255,207,240,255,255,255,
255,196,60,17,145,56,134,204,241,226,158,8,200,156,42,220,9,158,65,196,34,
92,42,26,137,147,120,64,74,37,196,54,100,49,35,188,36,5,68,184,208,113,187,
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,
0,32,235,248,68,48,156,2,24,94,24,0,243,119,10,139,144,123,242,3,102,238,
18,239,115,72,217,160,11,223,16,23,55,113,241,32,145,36,57,188,18,16,102,3,
5,120,35,34,89,32,15,180,152,173,127,0,218,235,88,0,228,180,227,200,0,0,
248,127,0,0,0,0,197,107,240,64,6,77,220,24,38,78,74,113,67,77,130,4,12,155,
185,52,48,156,148,226,134,155,4,10,194,96,129,132,166,238,45,194,2,201,193,
130,100,228,167,20,52,216,32,113,41,187,139,112,128,178,114,104,97,57,41,
197,13,54,8,32,48,216,32,130,195,224,130,19,97,124,134,23,6,0,57,137,62,77,
12,38,12,0,179,18,124,45,22,190,96,128,141,176,134,28,98,79,180,152,139,
218,45,124,193,1,27,97,16,32,196,159,24,230,204,246,194,40,89,137,62,210,
98,103,92,217,158,216,70,7,49,39,193,130,100,182,17,194,140,73,246,147,16,
250,9,146,216,72,6,49,39,193,131,22,194,72,73,137,62,210,98,31,65,139,97,
40,32,196,159,14,234,70,86,194,88,89,137,62,210,98,63,93,72,202,216,76,10,
49,39,198,33,180,153,37,108,38,134,152,147,237,38,38,117,13,164,201,43,97,
56,40,196,159,36,65,57,163,149,176,158,26,98,79,180,152,165,210,9,205,28,
173,133,0,243,18,124,98,22,180,72,130,115,71,43,97,68,72,196,159,105,49,51,
168,90,209,34,9,205,28,173,133,33,19,18,124,154,24,76,185,164,227,138,89,
18,119,0,7,145,39,201,161,132,188,64,124,137,62,49,11,90,36,65,57,163,149,
210,166,37,34,79,180,152,153,212,45,104,145,4,230,142,87,74,160,84,137,62,
72,130,115,71,43,171,234,134,200,147,237,38,41,116,130,115,71,43,171,235,5,
72,147,227,16,218,76,146,186,254,184,108,137,62,210,98,103,80,218,76,146,
186,254,192,68,137,62,29,212,140,174,207,178,23,34,79,180,152,143,215,82,
50,187,62,208,60,137,62,12,19,37,210,182,21,34,79,180,152,135,208,76,151,
74,224,68,137,62,49,205,153,238,175,186,23,34,79,180,152,153,215,54,103,
186,190,240,92,137,62,22,139,95,48,64,70,235,251,225,210,36,251,73,136,189,
162,215,204,16,17,186,255,2,14,98,79,152,32,35,108,48,64,242,36,249,130,2,
55,75,6,212,224,72,200,51,128,114,108,28,100,128,0,0,0,0,0,0,0,12,110,127,
48,98,115,249,201,117,243,249,195,21,159,206,38,47,63,156,86,8,75,144,94,
82,1,38,73,79,208,67,95,233,1,6,128,14,79,129,186,40,249,18,149,182,207,
144,200,155,188,248,204,105,184,207,142,199,137,175,201,0,159,72,10,5,21,
221,10,120,74,129,124,36,98,232,228,74,81,62,160,20,10,107,186,21,114,32,
105,137,194,70,46,142,68,165,19,235,1,64,170,187,161,119,34,66,146,36,104,
137,194,70,46,142,68,165,19,236,1,64,174,187,161,95,37,134,204,23,225,35,
23,71,34,82,137,246,128,160,89,93,208,167,147,195,201,194,70,46,142,68,165,
19,238,1,64,182,187,161,71,105,20,19,177,139,163,145,41,68,16,7,6,15,82,70,
72,115,96,96,2,106,32,0,0,0,0,91,60,165,195,201,194,8,134,149,216,162,0,
192,41,225,8,2,48,177,36,1,149,13,196,15,0,200,209,97,199,128,99,32,176,
195,192,113,57,143,0,167,133,32,230,80,28,202,139,175,238,2,48,189,192,20,
1,119,80,87,193,186,129,89,56,72,197,209,200,193,185,35,23,71,109,13,219,
36,98,232,237,156,13,26,208,211,14,102,19,87,137,91,95,128,0,10,96,24,92,0,
0,83,2,53,56,0,0,165,3,28,204,160,160,226,100,226,200,211,76,241,240,0,1,
102,8,22,75,64,137,73,20,230,105,133,7,19,39,22,70,154,103,143,128,0,11,48,
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,
216,162,152,192,131,18,124,162,27,61,138,41,108,32,196,159,16,217,232,235,
81,76,104,73,137,62,81,13,158,142,181,20,184,16,98,79,136,108,244,244,168,
166,56,36,196,159,40,134,207,79,74,138,93,10,49,39,194,173,192,158,158,149,
20,188,20,98,79,133,91,129,61,109,74,41,124,30,68,159,16,217,236,83,108,96,
68,137,62,81,13,158,197,54,182,17,34,79,136,108,244,117,169,182,52,38,68,
159,40,134,207,71,90,155,92,8,145,39,196,54,122,122,84,219,28,19,34,79,148,
67,103,167,165,77,174,133,72,147,225,86,224,79,79,74,155,94,10,145,39,194,
173,192,158,182,165,54,190,206,25,212,35,208,226,100,150,211,201,29,162,44,
140,35,103,0,0,3,192,252,0,0,0,0,206,25,228,35,208,226,100,150,211,201,29,
162,44,140,35,103,0,0,3,192,252,0,0,0,0,206,25,244,35,208,226,100,150,211,
201,29,162,44,140,35,103,0,0,3,192,252,0,0,0,0,206,26,4,35,208,226,100,150,
211,201,29,162,44,140,35,103,0,0,0,1,0,0,0,0,0,206,26,20,35,208,226,100,
150,211,201,29,162,44,140,35,103,0,0,0,1,0,0,0,0,0,206,26,36,35,208,226,
100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,52,35,208,
226,100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,68,35,
208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,65,0,0,0,0,0,206,26,84,
35,208,226,100,150,211,201,29,162,44,140,35,103,0,0,0,129,0,0,0,0,0,195,
154,99,16,38,36,0,251,68,117,179,216,162,128,68,72,1,241,13,158,197,20,150,
25,18,0,125,162,58,217,232,235,117,100,162,136,25,18,0,125,162,58,217,232,
235,116,36,162,145,2,226,64,15,136,108,244,117,186,178,81,73,129,113,32,7,
196,54,122,58,221,9,40,165,64,200,144,3,237,17,214,207,79,75,171,37,20,80,
200,144,3,237,17,214,207,79,75,161,37,20,138,23,18,0,124,67,103,167,165,
213,146,138,77,11,137,0,62,33,179,211,210,232,73,69,42,133,196,128,31,10,
183,2,125,89,40,163,5,196,128,31,10,183,2,125,9,40,164,96,200,144,3,224,
221,64,172,157,89,40,163,134,68,128,31,6,234,5,100,232,73,69,35,133,68,128,
31,104,142,182,125,89,40,180,0,168,144,3,237,17,214,207,161,37,22,144,19,
18,0,124,67,103,213,146,139,80,9,137,0,62,33,179,232,73,69,172,5,90,40,153,
59,68,117,179,216,166,192,77,162,137,147,136,108,246,41,180,176,219,69,19,
39,104,142,182,122,58,221,89,41,178,6,218,40,153,59,68,117,179,209,214,232,
73,77,162,6,90,40,153,56,134,207,71,91,171,37,54,152,25,104,162,100,226,27,
61,29,110,132,148,218,160,109,162,137,147,180,71,91,61,61,46,172,148,217,
67,109,20,76,157,162,58,217,233,233,116,36,166,209,67,45,20,76,156,67,103,
167,165,213,146,155,77,12,180,81,50,113,13,158,158,151,66,74,109,84,50,209,
68,201,194,173,192,159,86,74,108,193,150,138,38,78,21,110,4,250,18,83,104,
193,182,138,38,78,13,212,10,201,213,146,155,56,109,162,137,147,131,117,2,
178,116,36,166,209,194,237,20,76,157,162,58,217,245,100,167,16,2,237,20,76,
157,162,58,217,244,36,167,18,2,173,20,76,156,67,103,213,146,156,80,10,180,
81,50,113,13,159,66,74,113,97,175,221,48,216,110,64,4,42,22,189,179,0,196,
133,0,185,80,32,28,78,99,193,18,80,36,4,19,159,141,172,0,178,90,4,74,73,0,
22,209,68,201,187,129,4,2,8,3,132,64,60,36,0,171,240,84,6,149,113,72,176,
157,91,116,116,32,88,181,129,32,11,42,218,221,131,234,219,165,1,8,187,152,
255,188,231,235,248,47,86,227,105,18,2,56,175,185,255,244,17,91,40,110,173,
198,209,208,36,7,188,189,179,240,238,82,97,80,93,122,32,125,144,132,160,12,
22,162,42,7,236,161,25,232,237,105,64,158,160,230,63,205,59,127,102,11,217,
66,51,210,129,61,65,236,127,154,118,254,205,171,197,34,168,48,6,90,194,1,0,
39,75,88,72,8,9,33,186,194,80,64,76,13,214,19,2,130,96,110,150,189,0,65,6,
51,214,20,128,65,17,11,214,19,130,137,121,211,210,211,144,6,39,75,88,80,0,
201,119,235,10,8,41,86,231,71,88,80,129,79,135,186,122,133,224,34,25,69,
234,80,3,91,141,172,40,96,139,113,180,181,133,36,21,110,54,142,134,176,165,
1,176,23,213,47,0,216,134,234,215,128,111,117,181,232,128,209,3,70,230,107,
64,5,139,168,209,235,10,32,36,144,102,235,136,3,146,27,172,40,160,146,132,
103,172,40,192,115,3,117,133,28,22,113,163,69,172,41,103,1,66,188,17,145,
52,168,4,202,113,67,76,130,227,76,194,13,240,108,0,0,83,224,0,2,193,0,104,
146,84,97,48,0,1,94,192,56,169,24,145,179,192,0,5,112,8,56,16,32,128,56,18,
52,125,230,86,147,190,140,28,50,21,13,39,31,23,60,145,158,57,12,141,47,129,
6,155,194,188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,
163,201,68,14,49,39,199,197,211,116,240,242,113,197,232,18,180,254,36,3,17,
46,18,243,35,100,128,172,156,178,70,163,154,76,34,248,146,164,108,248,75,
204,141,146,28,217,115,137,27,95,27,241,173,236,162,160,224,200,2,206,9,
113,13,148,192,209,18,22,164,146,37,193,57,162,4,249,39,196,128,24,2,178,
66,213,136,68,201,16,77,209,131,31,192,242,88,96,92,191,151,34,100,136,38,
232,255,252,92,221,199,197,12,68,209,82,66,212,11,155,185,41,197,13,55,38,
3,66,213,47,135,254,72,12,162,99,133,116,112,0,1,72,66,14,16,16,50,37,202,
160,150,154,66,14,20,8,57,192,28,24,80,113,50,113,100,105,166,120,248,0,0,
179,1,65,196,201,199,20,178,36,227,224,0,2,208,54,113,240,0,1,100,11,181,
192,0,5,178,1,18,160,65,24,131,20,145,25,188,48,132,122,28,76,146,218,121,
35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,25,188,56,132,122,28,76,146,
218,121,35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,40,160,45,110,23,30,
176,33,184,0,0,183,32,29,235,2,27,199,23,0,0,23,4,51,120,129,8,244,56,153,
37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0,51,120,145,8,244,56,
153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,120,161,8,244,
56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,120,177,8,
244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,120,193,
8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,120,
209,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,
120,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,32,64,0,0,0,0,
32,227,194,0,97,57,162,4,246,104,5,34,92,35,68,225,161,166,220,16,16,137,
112,52,41,73,29,185,1,65,196,201,197,145,166,153,246,72,3,137,204,120,34,
74,8,199,1,67,17,162,112,201,84,128,97,144,78,25,42,16,131,169,1,205,66,8,
35,68,225,161,166,239,128,0,10,192,64,196,104,156,50,96,0,2,172,73,240,117,
96,57,170,97,4,104,156,52,52,221,240,0,1,82,1,74,9,129,125,240,0,1,82,32,
148,25,174,137,58,23,51,190,0,0,42,69,64,195,32,156,50,96,0,2,160,81,238,2,
3,107,173,218,3,192,
};
#else
#error invalid endianness defines
#endif
#endif /* DUK_USE_ROM_OBJECTS */

View file

@ -1,791 +0,0 @@
/*
* Automatically generated by genbuiltins.py, do not edit!
*/
#if !defined(DUK_BUILTINS_H_INCLUDED)
#define DUK_BUILTINS_H_INCLUDED
#if defined(DUK_USE_ROM_STRINGS)
#error ROM support not enabled, rerun configure.py with --rom-support
#else /* DUK_USE_ROM_STRINGS */
#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED)
#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */
#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL)
#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL)
#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */
#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */
#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */
#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
#define DUK_STRIDX_UC_ARRAY 6 /* 'Array' */
#define DUK_HEAP_STRING_UC_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARRAY)
#define DUK_HTHREAD_STRING_UC_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARRAY)
#define DUK_STRIDX_UC_STRING 7 /* 'String' */
#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */
#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */
#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
#define DUK_STRIDX_UC_DATE 10 /* 'Date' */
#define DUK_HEAP_STRING_UC_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_DATE)
#define DUK_HTHREAD_STRING_UC_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_DATE)
#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */
#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */
#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
#define DUK_STRIDX_MATH 13 /* 'Math' */
#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
#define DUK_STRIDX_JSON 14 /* 'JSON' */
#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
#define DUK_STRIDX_EMPTY_STRING 15 /* '' */
#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */
#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */
#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */
#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */
#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */
#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */
#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */
#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */
#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */
#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */
#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */
#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
#define DUK_STRIDX_GLOBAL 27 /* 'global' */
#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */
#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */
#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */
#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */
#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */
#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
#define DUK_STRIDX_EVAL 33 /* 'eval' */
#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
#define DUK_STRIDX_VALUE 34 /* 'value' */
#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
#define DUK_STRIDX_WRITABLE 35 /* 'writable' */
#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */
#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */
#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
#define DUK_STRIDX_JOIN 38 /* 'join' */
#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */
#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */
#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */
#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */
#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */
#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
#define DUK_STRIDX_SOURCE 44 /* 'source' */
#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */
#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */
#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
#define DUK_STRIDX_FLAGS 48 /* 'flags' */
#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS)
#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS)
#define DUK_STRIDX_INDEX 49 /* 'index' */
#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */
#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */
#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
#define DUK_STRIDX_MESSAGE 52 /* 'message' */
#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */
#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */
#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
#define DUK_STRIDX_LC_STRING 55 /* 'string' */
#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */
#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL)
#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL)
#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */
#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */
#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
#define DUK_STRIDX_NAN 59 /* 'NaN' */
#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */
#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */
#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */
#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
#define DUK_STRIDX_COMMA 63 /* ',' */
#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */
#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */
#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */
#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
#define DUK_STRIDX_CALLEE 68 /* 'callee' */
#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
#define DUK_STRIDX_CALLER 69 /* 'caller' */
#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
#define DUK_STRIDX_APPLY 70 /* 'apply' */
#define DUK_HEAP_STRING_APPLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
#define DUK_HTHREAD_STRING_APPLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
#define DUK_STRIDX_CONSTRUCT 71 /* 'construct' */
#define DUK_HEAP_STRING_CONSTRUCT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT)
#define DUK_HTHREAD_STRING_CONSTRUCT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT)
#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
#define DUK_STRIDX_GET 73 /* 'get' */
#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
#define DUK_STRIDX_HAS 74 /* 'has' */
#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
#define DUK_STRIDX_OWN_KEYS 75 /* 'ownKeys' */
#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE 76 /* '\x81Symbol.toPrimitive\xff' */
#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
#define DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE 77 /* '\x81Symbol.hasInstance\xff' */
#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
#define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG 78 /* '\x81Symbol.toStringTag\xff' */
#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
#define DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE 79 /* '\x81Symbol.isConcatSpreadable\xff' */
#define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
#define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
#define DUK_STRIDX_SET_PROTOTYPE_OF 80 /* 'setPrototypeOf' */
#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
#define DUK_STRIDX___PROTO__ 81 /* '__proto__' */
#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
#define DUK_STRIDX_TO_STRING 82 /* 'toString' */
#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
#define DUK_STRIDX_TO_JSON 83 /* 'toJSON' */
#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
#define DUK_STRIDX_TYPE 84 /* 'type' */
#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
#define DUK_STRIDX_DATA 85 /* 'data' */
#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
#define DUK_STRIDX_LC_BUFFER 86 /* 'buffer' */
#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
#define DUK_STRIDX_LENGTH 87 /* 'length' */
#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
#define DUK_STRIDX_SET 88 /* 'set' */
#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
#define DUK_STRIDX_STACK 89 /* 'stack' */
#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
#define DUK_STRIDX_PC 90 /* 'pc' */
#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
#define DUK_STRIDX_LINE_NUMBER 91 /* 'lineNumber' */
#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
#define DUK_STRIDX_INT_TRACEDATA 92 /* '\x82Tracedata' */
#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
#define DUK_STRIDX_NAME 93 /* 'name' */
#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
#define DUK_STRIDX_FILE_NAME 94 /* 'fileName' */
#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
#define DUK_STRIDX_LC_POINTER 95 /* 'pointer' */
#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
#define DUK_STRIDX_INT_TARGET 96 /* '\x82Target' */
#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
#define DUK_STRIDX_INT_NEXT 97 /* '\x82Next' */
#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
#define DUK_STRIDX_INT_BYTECODE 98 /* '\x82Bytecode' */
#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
#define DUK_STRIDX_INT_FORMALS 99 /* '\x82Formals' */
#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
#define DUK_STRIDX_INT_VARMAP 100 /* '\x82Varmap' */
#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
#define DUK_STRIDX_INT_SOURCE 101 /* '\x82Source' */
#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
#define DUK_STRIDX_INT_PC2LINE 102 /* '\x82Pc2line' */
#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
#define DUK_STRIDX_INT_MAP 103 /* '\x82Map' */
#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
#define DUK_STRIDX_INT_VARENV 104 /* '\x82Varenv' */
#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
#define DUK_STRIDX_INT_FINALIZER 105 /* '\x82Finalizer' */
#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
#define DUK_STRIDX_INT_VALUE 106 /* '\x82Value' */
#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
#define DUK_STRIDX_COMPILE 107 /* 'compile' */
#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
#define DUK_STRIDX_INPUT 108 /* 'input' */
#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
#define DUK_STRIDX_ERR_CREATE 109 /* 'errCreate' */
#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
#define DUK_STRIDX_ERR_THROW 110 /* 'errThrow' */
#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
#define DUK_STRIDX_ENV 111 /* 'env' */
#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
#define DUK_STRIDX_HEX 112 /* 'hex' */
#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
#define DUK_STRIDX_BASE64 113 /* 'base64' */
#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
#define DUK_STRIDX_JX 114 /* 'jx' */
#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
#define DUK_STRIDX_JC 115 /* 'jc' */
#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
#define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */
#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
#define DUK_STRIDX_JSON_EXT_NAN 117 /* '{"_nan":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
#define DUK_STRIDX_JSON_EXT_POSINF 118 /* '{"_inf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
#define DUK_STRIDX_JSON_EXT_NEGINF 119 /* '{"_ninf":true}' */
#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
#define DUK_STRIDX_JSON_EXT_FUNCTION1 120 /* '{"_func":true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
#define DUK_STRIDX_JSON_EXT_FUNCTION2 121 /* '{_func:true}' */
#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
#define DUK_STRIDX_BREAK 122 /* 'break' */
#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
#define DUK_STRIDX_CASE 123 /* 'case' */
#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
#define DUK_STRIDX_CATCH 124 /* 'catch' */
#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
#define DUK_STRIDX_CONTINUE 125 /* 'continue' */
#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
#define DUK_STRIDX_DEBUGGER 126 /* 'debugger' */
#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
#define DUK_STRIDX_DEFAULT 127 /* 'default' */
#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
#define DUK_STRIDX_DELETE 128 /* 'delete' */
#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
#define DUK_STRIDX_DO 129 /* 'do' */
#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
#define DUK_STRIDX_ELSE 130 /* 'else' */
#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
#define DUK_STRIDX_FINALLY 131 /* 'finally' */
#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
#define DUK_STRIDX_FOR 132 /* 'for' */
#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
#define DUK_STRIDX_LC_FUNCTION 133 /* 'function' */
#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
#define DUK_STRIDX_IF 134 /* 'if' */
#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
#define DUK_STRIDX_IN 135 /* 'in' */
#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
#define DUK_STRIDX_INSTANCEOF 136 /* 'instanceof' */
#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
#define DUK_STRIDX_NEW 137 /* 'new' */
#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
#define DUK_STRIDX_RETURN 138 /* 'return' */
#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
#define DUK_STRIDX_SWITCH 139 /* 'switch' */
#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
#define DUK_STRIDX_THIS 140 /* 'this' */
#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
#define DUK_STRIDX_THROW 141 /* 'throw' */
#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
#define DUK_STRIDX_TRY 142 /* 'try' */
#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
#define DUK_STRIDX_TYPEOF 143 /* 'typeof' */
#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
#define DUK_STRIDX_VAR 144 /* 'var' */
#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
#define DUK_STRIDX_CONST 145 /* 'const' */
#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
#define DUK_STRIDX_VOID 146 /* 'void' */
#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
#define DUK_STRIDX_WHILE 147 /* 'while' */
#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
#define DUK_STRIDX_WITH 148 /* 'with' */
#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
#define DUK_STRIDX_CLASS 149 /* 'class' */
#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
#define DUK_STRIDX_ENUM 150 /* 'enum' */
#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
#define DUK_STRIDX_EXPORT 151 /* 'export' */
#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
#define DUK_STRIDX_EXTENDS 152 /* 'extends' */
#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
#define DUK_STRIDX_IMPORT 153 /* 'import' */
#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
#define DUK_STRIDX_SUPER 154 /* 'super' */
#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
#define DUK_STRIDX_LC_NULL 155 /* 'null' */
#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
#define DUK_STRIDX_TRUE 156 /* 'true' */
#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
#define DUK_STRIDX_FALSE 157 /* 'false' */
#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
#define DUK_STRIDX_IMPLEMENTS 158 /* 'implements' */
#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
#define DUK_STRIDX_INTERFACE 159 /* 'interface' */
#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
#define DUK_STRIDX_LET 160 /* 'let' */
#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
#define DUK_STRIDX_PACKAGE 161 /* 'package' */
#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
#define DUK_STRIDX_PRIVATE 162 /* 'private' */
#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
#define DUK_STRIDX_PROTECTED 163 /* 'protected' */
#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
#define DUK_STRIDX_PUBLIC 164 /* 'public' */
#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
#define DUK_STRIDX_STATIC 165 /* 'static' */
#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
#define DUK_STRIDX_YIELD 166 /* 'yield' */
#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
#define DUK_HEAP_NUM_STRINGS 167
#define DUK_STRIDX_START_RESERVED 122
#define DUK_STRIDX_START_STRICT_RESERVED 158
#define DUK_STRIDX_END_RESERVED 167 /* exclusive endpoint */
/* To convert a heap stridx to a token number, subtract
* DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
*/
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[972];
#endif /* !DUK_SINGLE_FILE */
#define DUK_STRDATA_MAX_STRLEN 27
#define DUK_STRDATA_DATA_LENGTH 972
#endif /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_ROM_OBJECTS)
#error RAM support not enabled, rerun configure.py with --ram-support
#else /* DUK_USE_ROM_OBJECTS */
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_hasinstance(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_check_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_toprimitive(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_key_for(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_tostring_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_symbol_toprimitive(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_cbor_encode(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_cbor_decode(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx);
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[185];
#endif /* !DUK_SINGLE_FILE */
#define DUK_BIDX_GLOBAL 0
#define DUK_BIDX_GLOBAL_ENV 1
#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
#define DUK_BIDX_OBJECT_PROTOTYPE 3
#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
#define DUK_BIDX_FUNCTION_PROTOTYPE 5
#define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE 6
#define DUK_BIDX_ARRAY_CONSTRUCTOR 7
#define DUK_BIDX_ARRAY_PROTOTYPE 8
#define DUK_BIDX_STRING_CONSTRUCTOR 9
#define DUK_BIDX_STRING_PROTOTYPE 10
#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 11
#define DUK_BIDX_BOOLEAN_PROTOTYPE 12
#define DUK_BIDX_NUMBER_CONSTRUCTOR 13
#define DUK_BIDX_NUMBER_PROTOTYPE 14
#define DUK_BIDX_DATE_CONSTRUCTOR 15
#define DUK_BIDX_DATE_PROTOTYPE 16
#define DUK_BIDX_REGEXP_CONSTRUCTOR 17
#define DUK_BIDX_REGEXP_PROTOTYPE 18
#define DUK_BIDX_ERROR_CONSTRUCTOR 19
#define DUK_BIDX_ERROR_PROTOTYPE 20
#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 21
#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 22
#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 23
#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 24
#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 25
#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 26
#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 27
#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 28
#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 29
#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 30
#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 31
#define DUK_BIDX_URI_ERROR_PROTOTYPE 32
#define DUK_BIDX_TYPE_ERROR_THROWER 33
#define DUK_BIDX_DUKTAPE 34
#define DUK_BIDX_THREAD_PROTOTYPE 35
#define DUK_BIDX_POINTER_PROTOTYPE 36
#define DUK_BIDX_DOUBLE_ERROR 37
#define DUK_BIDX_SYMBOL_PROTOTYPE 38
#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 39
#define DUK_BIDX_DATAVIEW_PROTOTYPE 40
#define DUK_BIDX_INT8ARRAY_PROTOTYPE 41
#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 42
#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 43
#define DUK_BIDX_INT16ARRAY_PROTOTYPE 44
#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 45
#define DUK_BIDX_INT32ARRAY_PROTOTYPE 46
#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 47
#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 48
#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 49
#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 50
#define DUK_NUM_BUILTINS 51
#define DUK_NUM_BIDX_BUILTINS 51
#define DUK_NUM_ALL_BUILTINS 80
#if defined(DUK_USE_DOUBLE_LE)
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281];
#endif /* !DUK_SINGLE_FILE */
#define DUK_BUILTINS_DATA_LENGTH 4281
#elif defined(DUK_USE_DOUBLE_BE)
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281];
#endif /* !DUK_SINGLE_FILE */
#define DUK_BUILTINS_DATA_LENGTH 4281
#elif defined(DUK_USE_DOUBLE_ME)
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4281];
#endif /* !DUK_SINGLE_FILE */
#define DUK_BUILTINS_DATA_LENGTH 4281
#else
#error invalid endianness defines
#endif
#endif /* DUK_USE_ROM_OBJECTS */
#endif /* DUK_BUILTINS_H_INCLUDED */

File diff suppressed because it is too large Load diff

View file

@ -1,424 +0,0 @@
/*
* Union to access IEEE double memory representation, indexes for double
* memory representation, and some macros for double manipulation.
*
* Also used by packed duk_tval. Use a union for bit manipulation to
* minimize aliasing issues in practice. The C99 standard does not
* guarantee that this should work, but it's a very widely supported
* practice for low level manipulation.
*
* IEEE double format summary:
*
* seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
* A B C D E F G H
*
* s sign bit
* eee... exponent field
* fff... fraction
*
* See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
*
* NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a
* signaling NaN when the highest bit of the mantissa is zero, and a quiet
* NaN when the highest bit is set.
*
* At least three memory layouts are relevant here:
*
* A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE
* H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE
* D C B A H G F E Mixed endian (e.g. ARM FPA) DUK_USE_DOUBLE_ME
*
* Legacy ARM (FPA) is a special case: ARM double values are in mixed
* endian format while ARM duk_uint64_t values are in standard little endian
* format (H G F E D C B A). When a double is read as a duk_uint64_t
* from memory, the register will contain the (logical) value
* E F G H A B C D. This requires some special handling below.
* See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0056d/Bcfhgcgd.html.
*
* Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
* the logical (big endian) order:
*
* byte order duk_uint8_t duk_uint16_t duk_uint32_t
* BE 01234567 0123 01
* LE 76543210 3210 10
* ME (ARM) 32107654 1032 01
*
* Some processors may alter NaN values in a floating point load+store.
* For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
* quiet one. This is catastrophic when NaN space is used in packed
* duk_tval values. See: misc/clang_aliasing.c.
*/
#if !defined(DUK_DBLUNION_H_INCLUDED)
#define DUK_DBLUNION_H_INCLUDED
/*
* Union for accessing double parts, also serves as packed duk_tval
*/
union duk_double_union {
double d;
float f[2];
#if defined(DUK_USE_64BIT_OPS)
duk_uint64_t ull[1];
#endif
duk_uint32_t ui[2];
duk_uint16_t us[4];
duk_uint8_t uc[8];
#if defined(DUK_USE_PACKED_TVAL)
void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */
#endif
};
typedef union duk_double_union duk_double_union;
/*
* Indexes of various types with respect to big endian (logical) layout
*/
#if defined(DUK_USE_DOUBLE_LE)
#if defined(DUK_USE_64BIT_OPS)
#define DUK_DBL_IDX_ULL0 0
#endif
#define DUK_DBL_IDX_UI0 1
#define DUK_DBL_IDX_UI1 0
#define DUK_DBL_IDX_US0 3
#define DUK_DBL_IDX_US1 2
#define DUK_DBL_IDX_US2 1
#define DUK_DBL_IDX_US3 0
#define DUK_DBL_IDX_UC0 7
#define DUK_DBL_IDX_UC1 6
#define DUK_DBL_IDX_UC2 5
#define DUK_DBL_IDX_UC3 4
#define DUK_DBL_IDX_UC4 3
#define DUK_DBL_IDX_UC5 2
#define DUK_DBL_IDX_UC6 1
#define DUK_DBL_IDX_UC7 0
#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
#elif defined(DUK_USE_DOUBLE_BE)
#if defined(DUK_USE_64BIT_OPS)
#define DUK_DBL_IDX_ULL0 0
#endif
#define DUK_DBL_IDX_UI0 0
#define DUK_DBL_IDX_UI1 1
#define DUK_DBL_IDX_US0 0
#define DUK_DBL_IDX_US1 1
#define DUK_DBL_IDX_US2 2
#define DUK_DBL_IDX_US3 3
#define DUK_DBL_IDX_UC0 0
#define DUK_DBL_IDX_UC1 1
#define DUK_DBL_IDX_UC2 2
#define DUK_DBL_IDX_UC3 3
#define DUK_DBL_IDX_UC4 4
#define DUK_DBL_IDX_UC5 5
#define DUK_DBL_IDX_UC6 6
#define DUK_DBL_IDX_UC7 7
#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
#elif defined(DUK_USE_DOUBLE_ME)
#if defined(DUK_USE_64BIT_OPS)
#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */
#endif
#define DUK_DBL_IDX_UI0 0
#define DUK_DBL_IDX_UI1 1
#define DUK_DBL_IDX_US0 1
#define DUK_DBL_IDX_US1 0
#define DUK_DBL_IDX_US2 3
#define DUK_DBL_IDX_US3 2
#define DUK_DBL_IDX_UC0 3
#define DUK_DBL_IDX_UC1 2
#define DUK_DBL_IDX_UC2 1
#define DUK_DBL_IDX_UC3 0
#define DUK_DBL_IDX_UC4 7
#define DUK_DBL_IDX_UC5 6
#define DUK_DBL_IDX_UC6 5
#define DUK_DBL_IDX_UC7 4
#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
#else
#error internal error
#endif
/*
* Helper macros for reading/writing memory representation parts, used
* by duk_numconv.c and duk_tval.h.
*/
#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \
(u)->d = (v); \
} while (0)
#define DUK_DBLUNION_SET_HIGH32(u,v) do { \
(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
} while (0)
#if defined(DUK_USE_64BIT_OPS)
#if defined(DUK_USE_DOUBLE_ME)
#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
(u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
} while (0)
#else
#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
(u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
} while (0)
#endif
#else /* DUK_USE_64BIT_OPS */
#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
} while (0)
#endif /* DUK_USE_64BIT_OPS */
#define DUK_DBLUNION_SET_LOW32(u,v) do { \
(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
} while (0)
#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d)
#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0])
#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1])
#if defined(DUK_USE_64BIT_OPS)
#if defined(DUK_USE_DOUBLE_ME)
#define DUK_DBLUNION_SET_UINT64(u,v) do { \
(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
} while (0)
#define DUK_DBLUNION_GET_UINT64(u) \
((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
#else
#define DUK_DBLUNION_SET_UINT64(u,v) do { \
(u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
} while (0)
#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0])
#endif
#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
#endif /* DUK_USE_64BIT_OPS */
/*
* Double NaN manipulation macros related to NaN normalization needed when
* using the packed duk_tval representation. NaN normalization is necessary
* to keep double values compatible with the duk_tval format.
*
* When packed duk_tval is used, the NaN space is used to store pointers
* and other tagged values in addition to NaNs. Actual NaNs are normalized
* to a specific quiet NaN. The macros below are used by the implementation
* to check and normalize NaN values when they might be created. The macros
* are essentially NOPs when the non-packed duk_tval representation is used.
*
* A FULL check is exact and checks all bits. A NOTFULL check is used by
* the packed duk_tval and works correctly for all NaNs except those that
* begin with 0x7ff0. Since the 'normalized NaN' values used with packed
* duk_tval begin with 0x7ff8, the partial check is reliable when packed
* duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a
* quiet NaN regardless of its remaining lower bits.
*
* The ME variant below is specifically for ARM byte order, which has the
* feature that while doubles have a mixed byte order (32107654), unsigned
* long long values has a little endian byte order (76543210). When writing
* a logical double value through a ULL pointer, the 32-bit words need to be
* swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME.
* This is not full ARM support but suffices for some environments.
*/
#if defined(DUK_USE_64BIT_OPS)
#if defined(DUK_USE_DOUBLE_ME)
/* Macros for 64-bit ops + mixed endian doubles. */
#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
(u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \
} while (0)
#define DUK__DBLUNION_IS_NAN_FULL(u) \
((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \
((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0))
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000))
#define DUK__DBLUNION_IS_ANYINF(u) \
(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000))
#define DUK__DBLUNION_IS_POSINF(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000))
#define DUK__DBLUNION_IS_NEGINF(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000))
#define DUK__DBLUNION_IS_ANYZERO(u) \
(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_POSZERO(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_NEGZERO(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000))
#else
/* Macros for 64-bit ops + big/little endian doubles. */
#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
(u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \
} while (0)
#define DUK__DBLUNION_IS_NAN_FULL(u) \
((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \
((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0))
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000))
#define DUK__DBLUNION_IS_ANYINF(u) \
(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000))
#define DUK__DBLUNION_IS_POSINF(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000))
#define DUK__DBLUNION_IS_NEGINF(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000))
#define DUK__DBLUNION_IS_ANYZERO(u) \
(((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_POSZERO(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
#define DUK__DBLUNION_IS_NEGZERO(u) \
((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000))
#endif
#else /* DUK_USE_64BIT_OPS */
/* Macros for no 64-bit ops, any endianness. */
#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
(u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
(u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
} while (0)
#define DUK__DBLUNION_IS_NAN_FULL(u) \
((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
(((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
(u)->ui[DUK_DBL_IDX_UI1] != 0))
#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
(((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
#define DUK__DBLUNION_IS_ANYINF(u) \
((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \
((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
#define DUK__DBLUNION_IS_POSINF(u) \
(((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \
((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
#define DUK__DBLUNION_IS_NEGINF(u) \
(((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \
((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
#define DUK__DBLUNION_IS_ANYZERO(u) \
((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \
((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
#define DUK__DBLUNION_IS_POSZERO(u) \
(((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \
((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
#define DUK__DBLUNION_IS_NEGZERO(u) \
(((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \
((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
#endif /* DUK_USE_64BIT_OPS */
#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \
(u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
} while (0)
#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
/* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
(((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
/* E == 0x7ff, F == 8 => normalized NaN */ \
((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \
if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
DUK__DBLUNION_SET_NAN_FULL((u)); \
} \
} while (0)
#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \
if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
} \
} while (0)
/* Concrete macros for NaN handling used by the implementation internals.
* Chosen so that they match the duk_tval representation: with a packed
* duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
* these are essentially NOPs.
*/
#if defined(DUK_USE_PACKED_TVAL)
#if defined(DUK_USE_FULL_TVAL)
#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u))
#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d))
#else
#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u))
#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d))
#endif
#define DUK_DBLUNION_IS_NORMALIZED(u) \
(!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \
DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */
#else /* DUK_USE_PACKED_TVAL */
#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */
#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u)) /* (DUK_ISNAN((u)->d)) */
#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */
#define DUK_DBLUNION_SET_NAN(u) do { \
/* in non-packed representation we don't care about which NaN is used */ \
(u)->d = DUK_DOUBLE_NAN; \
} while (0)
#endif /* DUK_USE_PACKED_TVAL */
#define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u))
#define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u))
#define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u))
#define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u))
#define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u))
#define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u))
/* XXX: native 64-bit byteswaps when available */
/* 64-bit byteswap, same operation independent of target endianness. */
#define DUK_DBLUNION_BSWAP64(u) do { \
duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
duk__bswaptmp1 = (u)->ui[0]; \
duk__bswaptmp2 = (u)->ui[1]; \
duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
(u)->ui[0] = duk__bswaptmp2; \
(u)->ui[1] = duk__bswaptmp1; \
} while (0)
/* Byteswap an IEEE double in the duk_double_union from host to network
* order. For a big endian target this is a no-op.
*/
#if defined(DUK_USE_DOUBLE_LE)
#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
duk__bswaptmp1 = (u)->ui[0]; \
duk__bswaptmp2 = (u)->ui[1]; \
duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
(u)->ui[0] = duk__bswaptmp2; \
(u)->ui[1] = duk__bswaptmp1; \
} while (0)
#elif defined(DUK_USE_DOUBLE_ME)
#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
duk__bswaptmp1 = (u)->ui[0]; \
duk__bswaptmp2 = (u)->ui[1]; \
duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
(u)->ui[0] = duk__bswaptmp1; \
(u)->ui[1] = duk__bswaptmp2; \
} while (0)
#elif defined(DUK_USE_DOUBLE_BE)
#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
#else
#error internal error, double endianness insane
#endif
/* Reverse operation is the same. */
#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
/* Some sign bit helpers. */
#if defined(DUK_USE_64BIT_OPS)
#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0)
#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U))
#else
#define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0)
#define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U))
#endif
#endif /* DUK_DBLUNION_H_INCLUDED */

View file

@ -1,184 +0,0 @@
/*
* Debugging macros, DUK_DPRINT() and its variants in particular.
*
* DUK_DPRINT() allows formatted debug prints, and supports standard
* and Duktape specific formatters. See duk_debug_vsnprintf.c for details.
*
* DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
* for technical reasons. They are concretely used to hide 'x' from the
* compiler when the corresponding log level is disabled. This allows
* clean builds on non-C99 compilers, at the cost of more verbose code.
* Examples:
*
* DUK_D(DUK_DPRINT("foo"));
* DUK_DD(DUK_DDPRINT("foo"));
* DUK_DDD(DUK_DDDPRINT("foo"));
*
* This approach is preferable to the old "double parentheses" hack because
* double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
* no longer be added transparently without going through globals, which
* works poorly with threading.
*/
#if !defined(DUK_DEBUG_H_INCLUDED)
#define DUK_DEBUG_H_INCLUDED
#if defined(DUK_USE_DEBUG)
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_D(x) x
#else
#define DUK_D(x) do { } while (0) /* omit */
#endif
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DD(x) x
#else
#define DUK_DD(x) do { } while (0) /* omit */
#endif
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDD(x) x
#else
#define DUK_DDD(x) do { } while (0) /* omit */
#endif
/*
* Exposed debug macros: debugging enabled
*/
#if defined(DUK_USE_VARIADIC_MACROS)
/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
* possible compile time, but waste some space with shared function names.
*/
#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__);
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
#else
#define DUK_DPRINT(...)
#endif
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
#else
#define DUK_DDPRINT(...)
#endif
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
#else
#define DUK_DDDPRINT(...)
#endif
#else /* DUK_USE_VARIADIC_MACROS */
#define DUK__DEBUG_STASH(lev) \
(void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
(void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
(void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \
(void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
(void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
(void) (duk_debug_level_stash = (lev))
/* Without variadic macros resort to comma expression trickery to handle debug
* prints. This generates a lot of harmless warnings. These hacks are not
* needed normally because DUK_D() and friends will hide the entire debug log
* statement from the compiler.
*/
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
#endif
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DDPRINT 0 && /* args */
#endif
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
#else
#define DUK_DDDPRINT 0 && /* args */
#endif
#endif /* DUK_USE_VARIADIC_MACROS */
#else /* DUK_USE_DEBUG */
/*
* Exposed debug macros: debugging disabled
*/
#define DUK_D(x) do { } while (0) /* omit */
#define DUK_DD(x) do { } while (0) /* omit */
#define DUK_DDD(x) do { } while (0) /* omit */
#if defined(DUK_USE_VARIADIC_MACROS)
#define DUK_DPRINT(...)
#define DUK_DDPRINT(...)
#define DUK_DDDPRINT(...)
#else /* DUK_USE_VARIADIC_MACROS */
#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
#define DUK_DDPRINT 0 && /* args */
#define DUK_DDDPRINT 0 && /* args */
#endif /* DUK_USE_VARIADIC_MACROS */
#endif /* DUK_USE_DEBUG */
/*
* Structs
*/
#if defined(DUK_USE_DEBUG)
struct duk_fixedbuffer {
duk_uint8_t *buffer;
duk_size_t length;
duk_size_t offset;
duk_bool_t truncated;
};
#endif
/*
* Prototypes
*/
#if defined(DUK_USE_DEBUG)
DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
#if 0 /*unused*/
DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
#endif
DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
#if defined(DUK_USE_VARIADIC_MACROS)
DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
#else /* DUK_USE_VARIADIC_MACROS */
/* parameter passing, not thread safe */
#define DUK_DEBUG_STASH_SIZE 128
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash;
DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash;
#endif
DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
#endif /* DUK_USE_VARIADIC_MACROS */
DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
#endif /* DUK_USE_DEBUG */
#endif /* DUK_DEBUG_H_INCLUDED */

View file

@ -1,69 +0,0 @@
/*
* Fixed buffer helper useful for debugging, requires no allocation
* which is critical for debugging.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_DEBUG)
DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
duk_size_t avail;
duk_size_t copylen;
avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
if (length > avail) {
copylen = avail;
fb->truncated = 1;
} else {
copylen = length;
}
duk_memcpy_unsafe(fb->buffer + fb->offset, buffer, copylen);
fb->offset += copylen;
}
DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
}
DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
}
DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
duk_size_t avail;
va_list ap;
va_start(ap, fmt);
avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
if (avail > 0) {
duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
if (res < 0) {
/* error */
} else if ((duk_size_t) res >= avail) {
/* (maybe) truncated */
fb->offset += avail;
if ((duk_size_t) res > avail) {
/* actual chars dropped (not just NUL term) */
fb->truncated = 1;
}
} else {
/* normal */
fb->offset += (duk_size_t) res;
}
}
va_end(ap);
}
DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) {
char buf[64+1];
duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size);
buf[sizeof(buf) - 1] = (char) 0;
duk_fb_put_cstring(fb, buf);
}
DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
return (fb->offset >= fb->length);
}
#endif /* DUK_USE_DEBUG */

View file

@ -1,85 +0,0 @@
/*
* Debugging macro calls.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_DEBUG)
/*
* Debugging enabled
*/
#if !defined(DUK_USE_DEBUG_WRITE)
#error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined
#endif
#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
#if defined(DUK_USE_VARIADIC_MACROS)
DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
va_list ap;
long arg_level;
const char *arg_file;
long arg_line;
const char *arg_func;
const char *arg_msg;
char buf[DUK__DEBUG_BUFSIZE];
va_start(ap, fmt);
duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
arg_level = (long) level;
arg_file = (const char *) file;
arg_line = (long) line;
arg_func = (const char *) func;
arg_msg = (const char *) buf;
DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
va_end(ap);
}
#else /* DUK_USE_VARIADIC_MACROS */
DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
DUK_INTERNAL duk_int_t duk_debug_line_stash;
DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
DUK_INTERNAL duk_int_t duk_debug_level_stash;
DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
va_list ap;
long arg_level;
const char *arg_file;
long arg_line;
const char *arg_func;
const char *arg_msg;
char buf[DUK__DEBUG_BUFSIZE];
va_start(ap, fmt);
duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
arg_level = (long) duk_debug_level_stash;
arg_file = (const char *) duk_debug_file_stash;
arg_line = (long) duk_debug_line_stash;
arg_func = (const char *) duk_debug_func_stash;
arg_msg = (const char *) buf;
DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
va_end(ap);
}
#endif /* DUK_USE_VARIADIC_MACROS */
#else /* DUK_USE_DEBUG */
/*
* Debugging disabled
*/
#endif /* DUK_USE_DEBUG */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,151 +0,0 @@
#if !defined(DUK_DEBUGGER_H_INCLUDED)
#define DUK_DEBUGGER_H_INCLUDED
/* Debugger protocol version is defined in the public API header. */
/* Initial bytes for markers. */
#define DUK_DBG_IB_EOM 0x00
#define DUK_DBG_IB_REQUEST 0x01
#define DUK_DBG_IB_REPLY 0x02
#define DUK_DBG_IB_ERROR 0x03
#define DUK_DBG_IB_NOTIFY 0x04
/* Other initial bytes. */
#define DUK_DBG_IB_INT4 0x10
#define DUK_DBG_IB_STR4 0x11
#define DUK_DBG_IB_STR2 0x12
#define DUK_DBG_IB_BUF4 0x13
#define DUK_DBG_IB_BUF2 0x14
#define DUK_DBG_IB_UNUSED 0x15
#define DUK_DBG_IB_UNDEFINED 0x16
#define DUK_DBG_IB_NULL 0x17
#define DUK_DBG_IB_TRUE 0x18
#define DUK_DBG_IB_FALSE 0x19
#define DUK_DBG_IB_NUMBER 0x1a
#define DUK_DBG_IB_OBJECT 0x1b
#define DUK_DBG_IB_POINTER 0x1c
#define DUK_DBG_IB_LIGHTFUNC 0x1d
#define DUK_DBG_IB_HEAPPTR 0x1e
/* The short string/integer initial bytes starting from 0x60 don't have
* defines now.
*/
/* Error codes. */
#define DUK_DBG_ERR_UNKNOWN 0x00
#define DUK_DBG_ERR_UNSUPPORTED 0x01
#define DUK_DBG_ERR_TOOMANY 0x02
#define DUK_DBG_ERR_NOTFOUND 0x03
#define DUK_DBG_ERR_APPLICATION 0x04
/* Commands and notifys initiated by Duktape. */
#define DUK_DBG_CMD_STATUS 0x01
#define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */
#define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */
#define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */
#define DUK_DBG_CMD_THROW 0x05
#define DUK_DBG_CMD_DETACHING 0x06
#define DUK_DBG_CMD_APPNOTIFY 0x07
/* Commands initiated by debug client. */
#define DUK_DBG_CMD_BASICINFO 0x10
#define DUK_DBG_CMD_TRIGGERSTATUS 0x11
#define DUK_DBG_CMD_PAUSE 0x12
#define DUK_DBG_CMD_RESUME 0x13
#define DUK_DBG_CMD_STEPINTO 0x14
#define DUK_DBG_CMD_STEPOVER 0x15
#define DUK_DBG_CMD_STEPOUT 0x16
#define DUK_DBG_CMD_LISTBREAK 0x17
#define DUK_DBG_CMD_ADDBREAK 0x18
#define DUK_DBG_CMD_DELBREAK 0x19
#define DUK_DBG_CMD_GETVAR 0x1a
#define DUK_DBG_CMD_PUTVAR 0x1b
#define DUK_DBG_CMD_GETCALLSTACK 0x1c
#define DUK_DBG_CMD_GETLOCALS 0x1d
#define DUK_DBG_CMD_EVAL 0x1e
#define DUK_DBG_CMD_DETACH 0x1f
#define DUK_DBG_CMD_DUMPHEAP 0x20
#define DUK_DBG_CMD_GETBYTECODE 0x21
#define DUK_DBG_CMD_APPREQUEST 0x22
#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23
#define DUK_DBG_CMD_GETOBJPROPDESC 0x24
#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25
/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
* The remaining flags are specific to the debugger.
*/
#define DUK_DBG_PROPFLAG_SYMBOL (1U << 8)
#define DUK_DBG_PROPFLAG_HIDDEN (1U << 9)
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length);
DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length);
DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr);
DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr);
DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr);
/* XXX: exposed duk_debug_read_pointer */
/* XXX: exposed duk_debug_read_buffer */
/* XXX: exposed duk_debug_read_hbuffer */
#if 0
DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr);
#endif
#if defined(DUK_USE_DEBUGGER_INSPECT)
DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr);
#endif
DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
#if defined(DUK_USE_DEBUGGER_INSPECT)
DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr);
#endif
DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val);
DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data);
DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
#endif
DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
#if 0 /* unused */
DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command);
#endif
DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg);
DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
#endif
DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap);
DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap);
DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap);
DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap);
DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap);
#endif /* DUK_USE_DEBUGGER_SUPPORT */
#endif /* DUK_DEBUGGER_H_INCLUDED */

View file

@ -1,525 +0,0 @@
/*
* Error handling macros, assertion macro, error codes.
*
* There are three types of 'errors':
*
* 1. Ordinary errors relative to a thread, cause a longjmp, catchable.
* 2. Fatal errors relative to a heap, cause fatal handler to be called.
* 3. Fatal errors without context, cause the default (not heap specific)
* fatal handler to be called.
*
* Fatal errors without context are used by debug code such as assertions.
* By providing a fatal error handler for a Duktape heap, user code can
* avoid fatal errors without context in non-debug builds.
*/
#if !defined(DUK_ERROR_H_INCLUDED)
#define DUK_ERROR_H_INCLUDED
/*
* Error codes: defined in duktape.h
*
* Error codes are used as a shorthand to throw exceptions from inside
* the implementation. The appropriate ECMAScript object is constructed
* based on the code. ECMAScript code throws objects directly. The error
* codes are defined in the public API header because they are also used
* by calling code.
*/
/*
* Normal error
*
* Normal error is thrown with a longjmp() through the current setjmp()
* catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap
* identifies the throwing thread.
*
* Error formatting is usually unnecessary. The error macros provide a
* zero argument version (no formatting) and separate macros for small
* argument counts. Variadic macros are not used to avoid portability
* issues and avoid the need for stash-based workarounds when they're not
* available. Vararg calls are avoided for non-formatted error calls
* because vararg call sites are larger than normal, and there are a lot
* of call sites with no formatting.
*
* Note that special formatting provided by debug macros is NOT available.
*
* The _RAW variants allow the caller to specify file and line. This makes
* it easier to write checked calls which want to use the call site of the
* checked function, not the error macro call inside the checked function.
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
/* Because there are quite many call sites, pack error code (require at most
* 8-bit) into a single argument.
*/
#define DUK_ERROR(thr,err,msg) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
} while (0)
#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
} while (0)
#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
} while (0)
#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
} while (0)
#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
} while (0)
#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
} while (0)
#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
} while (0)
#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
} while (0)
#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
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)); \
} while (0)
#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \
duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
} while (0)
#else /* DUK_USE_VERBOSE_ERRORS */
#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err))
#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err))
#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt))
#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt))
#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt))
#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt))
#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
#endif /* DUK_USE_VERBOSE_ERRORS */
/*
* Fatal error without context
*
* The macro is an expression to make it compatible with DUK_ASSERT_EXPR().
*/
#define DUK_FATAL_WITHOUT_CONTEXT(msg) \
duk_default_fatal_handler(NULL, (msg))
/*
* Error throwing helpers
*
* The goal is to provide verbose and configurable error messages. Call
* sites should be clean in source code and compile to a small footprint.
* Small footprint is also useful for performance because small cold paths
* reduce code cache pressure. Adding macros here only makes sense if there
* are enough call sites to get concrete benefits.
*
* DUK_ERROR_xxx() macros are generic and can be used anywhere.
*
* DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where
* the "return DUK_RET_xxx;" shorthand is available for low memory targets.
* The DUK_DCERROR_xxx() macros always either throw or perform a
* 'return DUK_RET_xxx' from the calling function.
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
/* Verbose errors with key/value summaries (non-paranoid) or without key/value
* summaries (paranoid, for some security sensitive environments), the paranoid
* vs. non-paranoid distinction affects only a few specific errors.
*/
#if defined(DUK_USE_PARANOID_ERRORS)
#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
} while (0)
#else /* DUK_USE_PARANOID_ERRORS */
#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
} while (0)
#endif /* DUK_USE_PARANOID_ERRORS */
#define DUK_ERROR_INTERNAL(thr) do { \
duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
#define DUK_DCERROR_INTERNAL(thr) do { \
DUK_ERROR_INTERNAL((thr)); \
return 0; \
} while (0)
#define DUK_ERROR_ALLOC_FAILED(thr) do { \
duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
#define DUK_ERROR_UNSUPPORTED(thr) do { \
DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \
} while (0)
#define DUK_DCERROR_UNSUPPORTED(thr) do { \
DUK_ERROR_UNSUPPORTED((thr)); \
return 0; \
} while (0)
#define DUK_ERROR_ERROR(thr,msg) do { \
duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
} while (0)
#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \
} while (0)
#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \
} while (0)
#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
DUK_ERROR_RANGE_INVALID_ARGS((thr)); \
return 0; \
} while (0)
#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \
} while (0)
#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
DUK_ERROR_RANGE_INVALID_COUNT((thr)); \
return 0; \
} while (0)
#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \
} while (0)
#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \
return 0; \
} while (0)
#define DUK_ERROR_RANGE(thr,msg) do { \
duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
} while (0)
#define DUK_ERROR_EVAL(thr,msg) do { \
DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \
} while (0)
#define DUK_ERROR_REFERENCE(thr,msg) do { \
DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \
} while (0)
#define DUK_ERROR_SYNTAX(thr,msg) do { \
DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
} while (0)
#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
DUK_ERROR_TYPE_INVALID_ARGS((thr)); \
return 0; \
} while (0)
#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
DUK_ERROR_TYPE_INVALID_STATE((thr)); \
return 0; \
} while (0)
#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
} while (0)
#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \
} while (0)
#define DUK_ERROR_TYPE(thr,msg) do { \
DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
} while (0)
#define DUK_ERROR_URI(thr,msg) do { \
DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \
} while (0)
#else /* DUK_USE_VERBOSE_ERRORS */
/* Non-verbose errors for low memory targets: no file, line, or message. */
#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
duk_err_type((thr)); \
} while (0)
#define DUK_ERROR_INTERNAL(thr) do { \
duk_err_error((thr)); \
} while (0)
#define DUK_DCERROR_INTERNAL(thr) do { \
DUK_UNREF((thr)); \
return DUK_RET_ERROR; \
} while (0)
#define DUK_ERROR_ALLOC_FAILED(thr) do { \
duk_err_error((thr)); \
} while (0)
#define DUK_ERROR_UNSUPPORTED(thr) do { \
duk_err_error((thr)); \
} while (0)
#define DUK_DCERROR_UNSUPPORTED(thr) do { \
DUK_UNREF((thr)); \
return DUK_RET_ERROR; \
} while (0)
#define DUK_ERROR_ERROR(thr,msg) do { \
duk_err_error((thr)); \
} while (0)
#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
duk_err_range((thr)); \
} while (0)
#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
duk_err_range((thr)); \
} while (0)
#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
duk_err_range((thr)); \
} while (0)
#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
DUK_UNREF((thr)); \
return DUK_RET_RANGE_ERROR; \
} while (0)
#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
duk_err_range((thr)); \
} while (0)
#define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
DUK_UNREF((thr)); \
return DUK_RET_RANGE_ERROR; \
} while (0)
#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
duk_err_range((thr)); \
} while (0)
#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
DUK_UNREF((thr)); \
return DUK_RET_RANGE_ERROR; \
} while (0)
#define DUK_ERROR_RANGE(thr,msg) do { \
duk_err_range((thr)); \
} while (0)
#define DUK_ERROR_EVAL(thr,msg) do { \
duk_err_eval((thr)); \
} while (0)
#define DUK_ERROR_REFERENCE(thr,msg) do { \
duk_err_reference((thr)); \
} while (0)
#define DUK_ERROR_SYNTAX(thr,msg) do { \
duk_err_syntax((thr)); \
} while (0)
#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
duk_err_type((thr)); \
} while (0)
#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
DUK_UNREF((thr)); \
return DUK_RET_TYPE_ERROR; \
} while (0)
#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
duk_err_type((thr)); \
} while (0)
#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
duk_err_type((thr)); \
} while (0)
#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
duk_err_type((thr)); \
} while (0)
#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
DUK_UNREF((thr)); \
return DUK_RET_TYPE_ERROR; \
} while (0)
#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
duk_err_type((thr)); \
} while (0)
#define DUK_ERROR_TYPE(thr,msg) do { \
duk_err_type((thr)); \
} while (0)
#define DUK_ERROR_URI(thr,msg) do { \
duk_err_uri((thr)); \
} while (0)
#endif /* DUK_USE_VERBOSE_ERRORS */
/*
* Assert macro: failure causes a fatal error.
*
* NOTE: since the assert macro doesn't take a heap/context argument, there's
* no way to look up a heap/context specific fatal error handler which may have
* been given by the application. Instead, assertion failures always use the
* internal default fatal error handler; it can be replaced via duk_config.h
* and then applies to all Duktape heaps.
*/
#if defined(DUK_USE_ASSERTIONS)
/* The message should be a compile time constant without formatting (less risk);
* we don't care about assertion text size because they're not used in production
* builds.
*/
#define DUK_ASSERT(x) do { \
if (!(x)) { \
DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
" (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
} \
} while (0)
/* Assertion compatible inside a comma expression, evaluates to void. */
#define DUK_ASSERT_EXPR(x) \
((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
" (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
#else /* DUK_USE_ASSERTIONS */
#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0)
#define DUK_ASSERT_EXPR(x) ((void) 0)
#endif /* DUK_USE_ASSERTIONS */
/* this variant is used when an assert would generate a compile warning by
* being always true (e.g. >= 0 comparison for an unsigned value
*/
#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0)
/*
* Assertion helpers
*/
#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \
DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
} while (0)
#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \
if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
} \
} while (0)
#else
#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */
#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */
#endif
#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n))
#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \
duk_double_union duk__assert_tmp_du; \
duk__assert_tmp_du.d = (dval); \
DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \
} while (0)
#else
#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
#endif
#define DUK_ASSERT_VS_SPACE(thr) \
DUK_ASSERT(thr->valstack_top < thr->valstack_end)
/*
* Helper to initialize a memory area (e.g. struct) with garbage when
* assertions enabled.
*/
#if defined(DUK_USE_ASSERTIONS)
#define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
duk_memset_unsafe((void *) (ptr), 0x5a, size); \
} while (0)
#else
#define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)
#endif
/*
* Helper for valstack space
*
* Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
* required for its own use, and any child calls which are not (a) Duktape API calls
* or (b) Duktape calls which involve extending the valstack (e.g. getter call).
*/
#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape
* API calls in addition to function's own use
*/
#if defined(DUK_USE_ASSERTIONS)
#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \
DUK_ASSERT((thr) != NULL); \
DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
} while (0)
#else
#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */
#endif
/*
* Prototypes
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
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));
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, ...));
#else /* DUK_USE_VERBOSE_ERRORS */
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
#endif /* DUK_USE_VERBOSE_ERRORS */
#if defined(DUK_USE_VERBOSE_ERRORS)
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));
#else
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
#endif
DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
#define DUK_AUGMENT_FLAG_NOBLAME_FILELINE (1U << 0) /* if set, don't blame C file/line for .fileName and .lineNumber */
#define DUK_AUGMENT_FLAG_SKIP_ONE (1U << 1) /* if set, skip topmost activation in traceback construction */
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
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);
#endif
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
#endif
#if defined(DUK_USE_VERBOSE_ERRORS)
#if defined(DUK_USE_PARANOID_ERRORS)
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));
#else
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));
#endif
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber));
#else /* DUK_VERBOSE_ERRORS */
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr));
#endif /* DUK_VERBOSE_ERRORS */
DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg));
DUK_INTERNAL_DECL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL_DECL void duk_err_check_debugger_integration(duk_hthread *thr);
#endif
DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
#endif /* DUK_ERROR_H_INCLUDED */

View file

@ -1,588 +0,0 @@
/*
* Augmenting errors at their creation site and their throw site.
*
* When errors are created, traceback data is added by built-in code
* and a user error handler (if defined) can process or replace the
* error. Similarly, when errors are thrown, a user error handler
* (if defined) can process or replace the error.
*
* Augmentation and other processing at error creation time is nice
* because an error is only created once, but it may be thrown and
* rethrown multiple times. User error handler registered for processing
* an error at its throw site must be careful to handle rethrowing in
* a useful manner.
*
* Error augmentation may throw an internal error (e.g. alloc error).
*
* ECMAScript allows throwing any values, so all values cannot be
* augmented. Currently, the built-in augmentation at error creation
* only augments error values which are Error instances (= have the
* built-in Error.prototype in their prototype chain) and are also
* extensible. User error handlers have no limitations in this respect.
*/
#include "third_party/duktape/duk_internal.h"
/*
* Helper for calling a user error handler.
*
* 'thr' must be the currently active thread; the error handler is called
* in its context. The valstack of 'thr' must have the error value on
* top, and will be replaced by another error value based on the return
* value of the error handler.
*
* The helper calls duk_handle_call() recursively in protected mode.
* Before that call happens, no longjmps should happen; as a consequence,
* we must assume that the valstack contains enough temporary space for
* arguments and such.
*
* While the error handler runs, any errors thrown will not trigger a
* recursive error handler call (this is implemented using a heap level
* flag which will "follow" through any coroutines resumed inside the
* error handler). If the error handler is not callable or throws an
* error, the resulting error replaces the original error (for Duktape
* internal errors, duk_error_throw.c further substitutes this error with
* a DoubleError which is not ideal). This would be easy to change and
* even signal to the caller.
*
* The user error handler is stored in 'Duktape.errCreate' or
* 'Duktape.errThrow' depending on whether we're augmenting the error at
* creation or throw time. There are several alternatives to this approach,
* see doc/error-objects.rst for discussion.
*
* Note: since further longjmp()s may occur while calling the error handler
* (for many reasons, e.g. a labeled 'break' inside the handler), the
* caller can make no assumptions on the thr->heap->lj state after the
* call (this affects especially duk_error_throw.c). This is not an issue
* as long as the caller writes to the lj state only after the error handler
* finishes.
*/
#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
duk_tval *tv_hnd;
duk_int_t rc;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT_STRIDX_VALID(stridx_cb);
if (thr->heap->augmenting_error) {
DUK_D(DUK_DPRINT("recursive call to error augmentation, ignore"));
return;
}
/*
* Check whether or not we have an error handler.
*
* We must be careful of not triggering an error when looking up the
* property. For instance, if the property is a getter, we don't want
* to call it, only plain values are allowed. The value, if it exists,
* is not checked. If the value is not a function, a TypeError happens
* when it is called and that error replaces the original one.
*/
DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */
/* [ ... errval ] */
if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
/* When creating built-ins, some of the built-ins may not be set
* and we want to tolerate that when throwing errors.
*/
DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
return;
}
tv_hnd = duk_hobject_find_entry_tval_ptr_stridx(thr->heap,
thr->builtins[DUK_BIDX_DUKTAPE],
stridx_cb);
if (tv_hnd == NULL) {
DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
(duk_tval *) tv_hnd));
return;
}
DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
(duk_tval *) tv_hnd));
duk_push_tval(thr, tv_hnd);
/* [ ... errval errhandler ] */
duk_insert(thr, -2); /* -> [ ... errhandler errval ] */
duk_push_undefined(thr);
duk_insert(thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */
/* [ ... errhandler undefined errval ] */
/*
* heap->augmenting_error prevents recursive re-entry and also causes
* call handling to use a larger (but not unbounded) call stack limit
* for the duration of error augmentation.
*
* We ignore errors now: a success return and an error value both
* replace the original error value. (This would be easy to change.)
*/
DUK_ASSERT(thr->heap->augmenting_error == 0);
thr->heap->augmenting_error = 1;
rc = duk_pcall_method(thr, 1);
DUK_UNREF(rc); /* no need to check now: both success and error are OK */
DUK_ASSERT(thr->heap->augmenting_error == 1);
thr->heap->augmenting_error = 0;
/* [ ... errval ] */
}
#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
/*
* Add ._Tracedata to an error on the stack top.
*/
#if defined(DUK_USE_TRACEBACKS)
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) {
duk_activation *act;
duk_int_t depth;
duk_int_t arr_size;
duk_tval *tv;
duk_hstring *s;
duk_uint32_t u32;
duk_double_t d;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr_callstack != NULL);
/* [ ... error ] */
/*
* The traceback format is pretty arcane in an attempt to keep it compact
* and cheap to create. It may change arbitrarily from version to version.
* It should be decoded/accessed through version specific accessors only.
*
* See doc/error-objects.rst.
*/
DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
(duk_tval *) duk_get_tval(thr, -1)));
/* Preallocate array to correct size, so that we can just write out
* the _Tracedata values into the array part.
*/
act = thr->callstack_curr;
depth = DUK_USE_TRACEBACK_DEPTH;
DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
if (depth > (duk_int_t) thr_callstack->callstack_top) {
depth = (duk_int_t) thr_callstack->callstack_top;
}
if (depth > 0) {
if (flags & DUK_AUGMENT_FLAG_SKIP_ONE) {
DUK_ASSERT(act != NULL);
act = act->parent;
depth--;
}
}
arr_size = depth * 2;
if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
arr_size += 2;
}
if (c_filename) {
/* We need the C filename to be interned before getting the
* array part pointer to avoid any GC interference while the
* array part is populated.
*/
duk_push_string(thr, c_filename);
arr_size += 2;
}
/* XXX: Uninitialized would be OK. Maybe add internal primitive to
* push bare duk_harray with size?
*/
DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size));
tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) arr_size);
duk_clear_prototype(thr, -1);
DUK_ASSERT(duk_is_bare_object(thr, -1));
DUK_ASSERT(arr_size == 0 || tv != NULL);
/* Compiler SyntaxErrors (and other errors) come first, and are
* blamed by default (not flagged "noblame").
*/
if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
s = thr->compile_ctx->h_filename;
DUK_TVAL_SET_STRING(tv, s);
DUK_HSTRING_INCREF(thr, s);
tv++;
u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line; /* (flags<<32) + (line), flags = 0 */
DUK_TVAL_SET_U32(tv, u32);
tv++;
}
/* Filename/line from C macros (__FILE__, __LINE__) are added as an
* entry with a special format: (string, number). The number contains
* the line and flags.
*/
/* [ ... error c_filename? arr ] */
if (c_filename) {
DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2));
s = DUK_TVAL_GET_STRING(thr->valstack_top - 2); /* interned c_filename */
DUK_ASSERT(s != NULL);
DUK_TVAL_SET_STRING(tv, s);
DUK_HSTRING_INCREF(thr, s);
tv++;
d = ((flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
(duk_double_t) c_line;
DUK_TVAL_SET_DOUBLE(tv, d);
tv++;
}
/* Traceback depth doesn't take into account the filename/line
* special handling above (intentional).
*/
for (; depth-- > 0; act = act->parent) {
duk_uint32_t pc;
duk_tval *tv_src;
/* [... arr] */
DUK_ASSERT(act != NULL); /* depth check above, assumes book-keeping is correct */
DUK_ASSERT_DISABLE(act->pc >= 0); /* unsigned */
/* Add function object. */
tv_src = &act->tv_func; /* object (function) or lightfunc */
DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src));
DUK_TVAL_SET_TVAL(tv, tv_src);
DUK_TVAL_INCREF(thr, tv);
tv++;
/* Add a number containing: pc, activation flags.
*
* PC points to next instruction, find offending PC. Note that
* PC == 0 for native code.
*/
pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr_callstack, act);
DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
d = ((duk_double_t) act->flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
DUK_TVAL_SET_DOUBLE(tv, d);
tv++;
}
#if defined(DUK_USE_ASSERTIONS)
{
duk_harray *a;
a = (duk_harray *) duk_known_hobject(thr, -1);
DUK_ASSERT(a != NULL);
DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
DUK_ASSERT(a->length == (duk_uint32_t) arr_size);
DUK_ASSERT(duk_is_bare_object(thr, -1));
}
#endif
/* [ ... error c_filename? arr ] */
if (c_filename) {
duk_remove_m2(thr);
}
/* [ ... error arr ] */
duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
}
#endif /* DUK_USE_TRACEBACKS */
/*
* Add .fileName and .lineNumber to an error on the stack top.
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !defined(DUK_USE_TRACEBACKS)
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) {
#if defined(DUK_USE_ASSERTIONS)
duk_int_t entry_top;
#endif
#if defined(DUK_USE_ASSERTIONS)
entry_top = duk_get_top(thr);
#endif
/*
* If tracebacks are disabled, 'fileName' and 'lineNumber' are added
* as plain own properties. Since Error.prototype has accessors of
* the same name, we need to define own properties directly (cannot
* just use e.g. duk_put_prop_stridx). Existing properties are not
* overwritten in case they already exist.
*/
if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
/* Compiler SyntaxError (or other error) gets the primary blame.
* Currently no flag to prevent blaming.
*/
duk_push_uint(thr, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
duk_push_hstring(thr, thr->compile_ctx->h_filename);
} else if (c_filename && (flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) == 0) {
/* C call site gets blamed next, unless flagged not to do so.
* XXX: file/line is disabled in minimal builds, so disable this
* too when appropriate.
*/
duk_push_int(thr, c_line);
duk_push_string(thr, c_filename);
} else {
/* Finally, blame the innermost callstack entry which has a
* .fileName property.
*/
duk_small_uint_t depth;
duk_uint32_t ecma_line;
duk_activation *act;
DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
depth = DUK_USE_TRACEBACK_DEPTH;
if (depth > thr_callstack->callstack_top) {
depth = thr_callstack->callstack_top;
}
for (act = thr_callstack->callstack_curr; depth-- > 0; act = act->parent) {
duk_hobject *func;
duk_uint32_t pc;
DUK_ASSERT(act != NULL);
func = DUK_ACT_GET_FUNC(act);
if (func == NULL) {
/* Lightfunc, not blamed now. */
continue;
}
/* PC points to next instruction, find offending PC,
* PC == 0 for native code.
*/
pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
DUK_UNREF(pc);
DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
duk_push_hobject(thr, func);
/* [ ... error func ] */
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
if (!duk_is_string_notsymbol(thr, -1)) {
duk_pop_2(thr);
continue;
}
/* [ ... error func fileName ] */
ecma_line = 0;
#if defined(DUK_USE_PC2LINE)
if (DUK_HOBJECT_IS_COMPFUNC(func)) {
ecma_line = duk_hobject_pc2line_query(thr, -2, (duk_uint_fast32_t) pc);
} else {
/* Native function, no relevant lineNumber. */
}
#endif /* DUK_USE_PC2LINE */
duk_push_u32(thr, ecma_line);
/* [ ... error func fileName lineNumber ] */
duk_replace(thr, -3);
/* [ ... error lineNumber fileName ] */
goto define_props;
}
/* No activation matches, use undefined for both .fileName and
* .lineNumber (matches what we do with a _Tracedata based
* no-match lookup.
*/
duk_push_undefined(thr);
duk_push_undefined(thr);
}
define_props:
/* [ ... error lineNumber fileName ] */
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(duk_get_top(thr) == entry_top + 2);
#endif
duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */
/*
* Add line number to a compiler error.
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
/* Append a "(line NNN)" to the "message" property of any error
* thrown during compilation. Usually compilation errors are
* SyntaxErrors but they can also be out-of-memory errors and
* the like.
*/
/* [ ... error ] */
DUK_ASSERT(duk_is_object(thr, -1));
if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
return;
}
DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
(duk_tval *) duk_get_tval(thr, -1)));
if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_MESSAGE)) {
duk_bool_t at_end;
/* Best guesstimate that error occurred at end of input, token
* truncated by end of input, etc.
*/
#if 0
at_end = (thr->compile_ctx->curr_token.start_offset + 1 >= thr->compile_ctx->lex.input_length);
at_end = (thr->compile_ctx->lex.window[0].codepoint < 0 || thr->compile_ctx->lex.window[1].codepoint < 0);
#endif
at_end = (thr->compile_ctx->lex.window[0].codepoint < 0);
DUK_D(DUK_DPRINT("syntax error, determined at_end=%ld; curr_token.start_offset=%ld, "
"lex.input_length=%ld, window[0].codepoint=%ld, window[1].codepoint=%ld",
(long) at_end,
(long) thr->compile_ctx->curr_token.start_offset,
(long) thr->compile_ctx->lex.input_length,
(long) thr->compile_ctx->lex.window[0].codepoint,
(long) thr->compile_ctx->lex.window[1].codepoint));
duk_push_sprintf(thr, " (line %ld%s)",
(long) thr->compile_ctx->curr_token.start_line,
at_end ? ", end of input" : "");
duk_concat(thr, 2);
duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
} else {
duk_pop(thr);
}
DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
(duk_tval *) duk_get_tval(thr, -1)));
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
/*
* Augment an error being created using Duktape specific properties
* like _Tracedata or .fileName/.lineNumber.
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
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) {
#if defined(DUK_USE_ASSERTIONS)
duk_int_t entry_top;
#endif
#if defined(DUK_USE_ASSERTIONS)
entry_top = duk_get_top(thr);
#endif
DUK_ASSERT(obj != NULL);
DUK_UNREF(obj); /* unreferenced w/o tracebacks */
duk__add_compiler_error_line(thr);
#if defined(DUK_USE_TRACEBACKS)
/* If tracebacks are enabled, the '_Tracedata' property is the only
* thing we need: 'fileName' and 'lineNumber' are virtual properties
* which use '_Tracedata'. (Check _Tracedata only as own property.)
*/
if (duk_hobject_find_entry_tval_ptr_stridx(thr->heap, obj, DUK_STRIDX_INT_TRACEDATA) != NULL) {
DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
} else {
duk__add_traceback(thr, thr_callstack, c_filename, c_line, flags);
}
#else
/* Without tracebacks the concrete .fileName and .lineNumber need
* to be added directly.
*/
duk__add_fileline(thr, thr_callstack, c_filename, c_line, flags);
#endif
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(duk_get_top(thr) == entry_top);
#endif
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
/*
* Augment an error at creation time with _Tracedata/fileName/lineNumber
* and allow a user error handler (if defined) to process/replace the error.
* The error to be augmented is at the stack top.
*
* thr: thread containing the error value
* thr_callstack: thread which should be used for generating callstack etc.
* c_filename: C __FILE__ related to the error
* c_line: C __LINE__ related to the error
* flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE:
* if true, don't fileName/line as error source, otherwise use traceback
* (needed because user code filename/line are reported but internal ones
* are not)
*/
#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
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) {
duk_hobject *obj;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr_callstack != NULL);
/* [ ... error ] */
/*
* Criteria for augmenting:
*
* - augmentation enabled in build (naturally)
* - error value internal prototype chain contains the built-in
* Error prototype object (i.e. 'val instanceof Error')
*
* Additional criteria for built-in augmenting:
*
* - error value is an extensible object
*/
obj = duk_get_hobject(thr, -1);
if (!obj) {
DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
return;
}
if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
/* If the value has a prototype loop, it's critical not to
* throw here. Instead, assume the value is not to be
* augmented.
*/
DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment"));
return;
}
if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, obj, flags);
} else {
DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
}
/* [ ... error ] */
#if defined(DUK_USE_ERRCREATE)
duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE);
#endif
}
#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
/*
* Augment an error at throw time; allow a user error handler (if defined)
* to process/replace the error. The error to be augmented is at the
* stack top.
*/
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
#if defined(DUK_USE_ERRTHROW)
duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW);
#endif /* DUK_USE_ERRTHROW */
}
#endif /* DUK_USE_AUGMENT_ERROR_THROW */

View file

@ -1,103 +0,0 @@
/*
* Do a longjmp call, calling the fatal error handler if no
* catchpoint exists.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_PREFER_SIZE)
DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_minimal(duk_hthread *thr));
DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) {
(void) duk_fatal(thr, "uncaught error");
DUK_WO_NORETURN(return;);
}
#endif
#if 0
DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_readable(duk_hthread *thr));
DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
const char *summary;
char buf[DUK_USE_FATAL_MAXLEN];
summary = duk_push_string_tval_readable(thr, &thr->heap->lj.value1);
DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
buf[sizeof(buf) - 1] = (char) 0;
(void) duk_fatal(thr, (const char *) buf);
DUK_WO_NORETURN(return;);
}
#endif
#if !defined(DUK_USE_PREFER_SIZE)
DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_error_aware(duk_hthread *thr));
DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
const char *summary;
char buf[DUK_USE_FATAL_MAXLEN];
summary = duk_push_string_tval_readable_error(thr, &thr->heap->lj.value1);
DUK_ASSERT(summary != NULL);
DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
buf[sizeof(buf) - 1] = (char) 0;
(void) duk_fatal(thr, (const char *) buf);
DUK_WO_NORETURN(return;);
}
#endif
DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
(int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
&thr->heap->lj.value1, &thr->heap->lj.value2));
/* Prevent finalizer execution during error handling. All error
* handling sites will process pending finalizers once error handling
* is complete and we're ready for the side effects. Does not prevent
* refzero freeing or mark-and-sweep during error handling.
*
* NOTE: when we come here some calling code may have used DECREF
* NORZ macros without an explicit DUK_REFZERO_CHECK_xxx() call.
* We don't want to do it here because it would just check for
* pending finalizers and we prevent that explicitly. Instead,
* the error catcher will run the finalizers once error handling
* is complete.
*/
DUK_ASSERT_LJSTATE_SET(thr->heap);
thr->heap->pf_prevent_count++;
DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
#if defined(DUK_USE_ASSERTIONS)
/* XXX: set this immediately when longjmp state is set */
DUK_ASSERT(thr->heap->error_not_allowed == 0); /* Detect error within critical section. */
thr->heap->error_not_allowed = 1;
#endif
DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld", (long) thr->heap->pf_prevent_count));
/* If we don't have a jmpbuf_ptr, there is little we can do except
* cause a fatal error. The caller's expectation is that we never
* return.
*/
if (!thr->heap->lj.jmpbuf_ptr) {
DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
(int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
&thr->heap->lj.value1, &thr->heap->lj.value2));
#if defined(DUK_USE_PREFER_SIZE)
duk__uncaught_minimal(thr);
#else
duk__uncaught_error_aware(thr);
#endif
DUK_UNREACHABLE();
}
#if defined(DUK_USE_CPP_EXCEPTIONS)
throw duk_internal_exception(); /* dummy */
#else
DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
#endif
DUK_UNREACHABLE();
}

View file

@ -1,152 +0,0 @@
/*
* Error and fatal handling.
*/
#include "third_party/duktape/duk_internal.h"
#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
#if defined(DUK_USE_VERBOSE_ERRORS)
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, ...) {
va_list ap;
char msg[DUK__ERRFMT_BUFSIZE];
va_start(ap, fmt);
(void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
msg[sizeof(msg) - 1] = (char) 0;
duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
}
DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
}
#else /* DUK_USE_VERBOSE_ERRORS */
DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
duk_err_create_and_throw(thr, code);
}
#endif /* DUK_USE_VERBOSE_ERRORS */
/*
* Error throwing helpers
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
#if defined(DUK_USE_PARANOID_ERRORS)
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) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
expect_name, duk_get_type_name(thr, idx), (long) idx);
}
#else
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) {
DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
expect_name, duk_push_string_readable(thr, idx), (long) idx);
}
#endif
DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR);
}
DUK_INTERNAL DUK_COLD void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED);
}
DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message);
}
DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
}
DUK_INTERNAL DUK_COLD void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) {
DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx));
}
DUK_INTERNAL DUK_COLD void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
}
DUK_INTERNAL DUK_COLD void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS);
}
DUK_INTERNAL DUK_COLD void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE);
}
DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT);
}
#else
/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
* when non-verbose errors are used.
*/
DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code));
DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) {
DUK_ERROR_RAW(thr, NULL, 0, code, NULL);
}
DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) {
duk__err_shared(thr, DUK_ERR_ERROR);
}
DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) {
duk__err_shared(thr, DUK_ERR_RANGE_ERROR);
}
DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) {
duk__err_shared(thr, DUK_ERR_EVAL_ERROR);
}
DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) {
duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR);
}
DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) {
duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR);
}
DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) {
duk__err_shared(thr, DUK_ERR_TYPE_ERROR);
}
DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) {
duk__err_shared(thr, DUK_ERR_URI_ERROR);
}
#endif
/*
* Default fatal error handler
*/
DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) {
DUK_UNREF(udata);
DUK_UNREF(msg);
msg = msg ? msg : "NULL";
#if defined(DUK_USE_FATAL_HANDLER)
/* duk_config.h provided a custom default fatal handler. */
DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg));
DUK_USE_FATAL_HANDLER(udata, msg);
#elif defined(DUK_USE_CPP_EXCEPTIONS)
/* With C++ use a duk_fatal_exception which user code can catch in
* a natural way.
*/
DUK_D(DUK_DPRINT("built-in default C++ fatal error handler called: %s", msg));
throw duk_fatal_exception(msg);
#else
/* Default behavior is to abort() on error. There's no printout
* which makes this awkward, so it's always recommended to use an
* explicit fatal error handler.
*
* ====================================================================
* NOTE: If you are seeing this, you are most likely dealing with an
* uncaught error. You should provide a fatal error handler in Duktape
* heap creation, and should consider using a protected call as your
* first call into an empty Duktape context to properly handle errors.
* See:
* - http://duktape.org/guide.html#error-handling
* - http://wiki.duktape.org/HowtoFatalErrors.html
* - http://duktape.org/api.html#taglist-protected
* ====================================================================
*/
DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg));
DUK_ABORT();
#endif
DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop"));
for (;;) {
/* Loop forever to ensure we don't return. */
}
}

View file

@ -1,174 +0,0 @@
/*
* Error helpers
*/
#include "third_party/duktape/duk_internal.h"
/*
* Helper to walk the thread chain and see if there is an active error
* catcher. Protected calls or finally blocks aren't considered catching.
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
/* As noted above, a protected API call won't be counted as a
* catcher. This is usually convenient, e.g. in the case of a top-
* level duk_pcall(), but may not always be desirable. Perhaps add
* an argument to treat them as catchers?
*/
duk_activation *act;
duk_catcher *cat;
DUK_ASSERT(thr != NULL);
for (; thr != NULL; thr = thr->resumer) {
for (act = thr->callstack_curr; act != NULL; act = act->parent) {
for (cat = act->cat; cat != NULL; cat = cat->parent) {
if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
return 1; /* all we need to know */
}
}
}
}
return 0;
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
/*
* Get prototype object for an integer error code.
*/
DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) {
switch (code) {
case DUK_ERR_EVAL_ERROR:
return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
case DUK_ERR_RANGE_ERROR:
return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
case DUK_ERR_REFERENCE_ERROR:
return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
case DUK_ERR_SYNTAX_ERROR:
return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
case DUK_ERR_TYPE_ERROR:
return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
case DUK_ERR_URI_ERROR:
return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
case DUK_ERR_ERROR:
default:
return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
}
}
/*
* Helper for debugger throw notify and pause-on-uncaught integration.
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
duk_bool_t uncaught;
duk_tval *tv_obj;
/* If something is thrown with the debugger attached and nobody will
* catch it, execution is paused before the longjmp, turning over
* control to the debug client. This allows local state to be examined
* before the stack is unwound. Errors are not intercepted when debug
* message loop is active (e.g. for Eval).
*/
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
/* XXX: Allow customizing the pause and notify behavior at runtime
* using debugger runtime flags. For now the behavior is fixed using
* config options.
*/
if (!duk_debug_is_attached(thr->heap) ||
thr->heap->dbg_processing ||
thr->heap->lj.type != DUK_LJ_TYPE_THROW ||
thr->heap->creating_error) {
DUK_D(DUK_DPRINT("skip debugger error integration; not attached, debugger processing, not THROW, or error thrown while creating error"));
return;
}
/* Don't intercept a DoubleError, we may have caused the initial double
* fault and attempting to intercept it will cause us to be called
* recursively and exhaust the C stack. (This should no longer happen
* for the initial throw because DoubleError path doesn't do a debugger
* integration check, but it might happen for rethrows.)
*/
tv_obj = &thr->heap->lj.value1;
if (DUK_TVAL_IS_OBJECT(tv_obj) && DUK_TVAL_GET_OBJECT(tv_obj) == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
DUK_D(DUK_DPRINT("built-in DoubleError instance (re)thrown, not intercepting"));
return;
}
uncaught = !duk__have_active_catcher(thr);
/* Debugger code expects the value at stack top. This also serves
* as a backup: we need to store/restore the longjmp state because
* when the debugger is paused Eval commands may be executed and
* they can arbitrarily clobber the longjmp state.
*/
duk_push_tval(thr, tv_obj);
/* Store and reset longjmp state. */
DUK_ASSERT_LJSTATE_SET(thr->heap);
DUK_TVAL_DECREF_NORZ(thr, tv_obj);
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2)); /* Always for THROW type. */
DUK_TVAL_SET_UNDEFINED(tv_obj);
thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
DUK_ASSERT_LJSTATE_UNSET(thr->heap);
#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
/* Report it to the debug client */
DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
duk_debug_send_throw(thr, uncaught);
#endif
if (uncaught) {
if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_UNCAUGHT_ERROR) {
DUK_D(DUK_DPRINT("PAUSE TRIGGERED by uncaught error"));
duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
}
} else {
if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_CAUGHT_ERROR) {
DUK_D(DUK_DPRINT("PAUSE TRIGGERED by caught error"));
duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
}
}
/* Restore longjmp state. */
DUK_ASSERT_LJSTATE_UNSET(thr->heap);
thr->heap->lj.type = DUK_LJ_TYPE_THROW;
tv_obj = DUK_GET_TVAL_NEGIDX(thr, -1);
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, tv_obj);
DUK_TVAL_INCREF(thr, tv_obj);
DUK_ASSERT_LJSTATE_SET(thr->heap);
duk_pop(thr);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */
/*
* Helpers for setting up heap longjmp state.
*/
DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) {
duk_heap *heap;
DUK_ASSERT(thr != NULL);
heap = thr->heap;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(tv_val != NULL);
DUK_ASSERT_LJSTATE_UNSET(heap);
heap->lj.type = lj_type;
DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val);
DUK_TVAL_INCREF(thr, tv_val);
DUK_ASSERT_LJSTATE_SET(heap);
}

View file

@ -1,162 +0,0 @@
/*
* Create and throw an ECMAScript error object based on a code and a message.
*
* Used when we throw errors internally. ECMAScript generated error objects
* are created by ECMAScript code, and the throwing is handled by the bytecode
* executor.
*/
#include "third_party/duktape/duk_internal.h"
/*
* Create and throw an error (originating from Duktape internally)
*
* Push an error object on top of the stack, possibly throw augmenting
* the error, and finally longjmp.
*
* If an error occurs while we're dealing with the current error, we might
* enter an infinite recursion loop. This is prevented by detecting a
* "double fault" through the heap->creating_error flag; the recursion
* then stops at the second level.
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
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) {
#else
DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
#endif
#if defined(DUK_USE_VERBOSE_ERRORS)
DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
(long) code, (const char *) msg,
(const char *) filename, (long) line));
#else
DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code));
#endif
DUK_ASSERT(thr != NULL);
/* Even though nested call is possible because we throw an error when
* trying to create an error, the potential errors must happen before
* the longjmp state is configured.
*/
DUK_ASSERT_LJSTATE_UNSET(thr->heap);
/* Sync so that augmentation sees up-to-date activations, NULL
* thr->ptr_curr_pc so that it's not used if side effects occur
* in augmentation or longjmp handling.
*/
duk_hthread_sync_and_null_currpc(thr);
/*
* Create and push an error object onto the top of stack.
* The error is potentially augmented before throwing.
*
* If a "double error" occurs, use a fixed error instance
* to avoid further trouble.
*/
if (thr->heap->creating_error) {
duk_tval tv_val;
duk_hobject *h_err;
thr->heap->creating_error = 0;
h_err = thr->builtins[DUK_BIDX_DOUBLE_ERROR];
if (h_err != NULL) {
DUK_D(DUK_DPRINT("double fault detected -> use built-in fixed 'double error' instance"));
DUK_TVAL_SET_OBJECT(&tv_val, h_err);
} else {
DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
"-> use the error code as a number"));
DUK_TVAL_SET_I32(&tv_val, (duk_int32_t) code);
}
duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, &tv_val);
/* No augmentation to avoid any allocations or side effects. */
} else {
/* Prevent infinite recursion. Extra call stack and C
* recursion headroom (see GH-191) is added for augmentation.
* That is now signalled by heap->augmenting error and taken
* into account in call handling without an explicit limit bump.
*/
thr->heap->creating_error = 1;
duk_require_stack(thr, 1);
/* XXX: usually unnecessary '%s' formatting here, but cannot
* use 'msg' as a format string directly.
*/
#if defined(DUK_USE_VERBOSE_ERRORS)
duk_push_error_object_raw(thr,
code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
filename,
line,
"%s",
(const char *) msg);
#else
duk_push_error_object_raw(thr,
code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
NULL,
0,
NULL);
#endif
/* Note that an alloc error may happen during error augmentation.
* This may happen both when the original error is an alloc error
* and when it's something else. Because any error in augmentation
* must be handled correctly anyway, there's no special check for
* avoiding it for alloc errors (this differs from Duktape 1.x).
*/
#if defined(DUK_USE_AUGMENT_ERROR_THROW)
DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
(duk_tval *) duk_get_tval(thr, -1)));
duk_err_augment_error_throw(thr);
#endif
duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
thr->heap->creating_error = 0;
/* Error is now created and we assume no errors can occur any
* more. Check for debugger Throw integration only when the
* error is complete. If we enter debugger message loop,
* creating_error must be 0 so that errors can be thrown in
* the paused state, e.g. in Eval commands.
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
duk_err_check_debugger_integration(thr);
#endif
}
/*
* Finally, longjmp
*/
DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
(duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
duk_err_longjmp(thr);
DUK_UNREACHABLE();
}
/*
* Helper for C function call negative return values.
*/
DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(rc < 0);
/*
* The __FILE__ and __LINE__ information is intentionally not used in the
* creation of the error object, as it isn't useful in the tracedata. The
* tracedata still contains the function which returned the negative return
* code, and having the file/line of this function isn't very useful.
*
* The error messages for DUK_RET_xxx shorthand are intentionally very
* minimal: they're only really useful for low memory targets.
*/
duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc);
DUK_WO_NORETURN(return;);
}

View file

@ -1,30 +0,0 @@
/*
* Exceptions for Duktape internal throws when C++ exceptions are used
* for long control transfers.
*/
#if !defined(DUK_EXCEPTION_H_INCLUDED)
#define DUK_EXCEPTION_H_INCLUDED
#if defined(DUK_USE_CPP_EXCEPTIONS)
/* Internal exception used as a setjmp-longjmp replacement. User code should
* NEVER see or catch this exception, so it doesn't inherit from any base
* class which should minimize the chance of user code accidentally catching
* the exception.
*/
class duk_internal_exception {
/* intentionally empty */
};
/* Fatal error, thrown as a specific C++ exception with C++ exceptions
* enabled. It is unsafe to continue; doing so may cause crashes or memory
* leaks. This is intended to be either uncaught, or caught by user code
* aware of the "unsafe to continue" semantics.
*/
class duk_fatal_exception : public virtual std::runtime_error {
public:
duk_fatal_exception(const char *message) : std::runtime_error(message) {}
};
#endif
#endif /* DUK_EXCEPTION_H_INCLUDED */

View file

@ -1,39 +0,0 @@
/*
* Union to access IEEE float memory representation.
*/
#if !defined(DUK_FLTUNION_H_INCLUDED)
#define DUK_FLTUNION_H_INCLUDED
#include "third_party/duktape/duk_internal.h"
union duk_float_union {
float f;
duk_uint32_t ui[1];
duk_uint16_t us[2];
duk_uint8_t uc[4];
};
typedef union duk_float_union duk_float_union;
#if defined(DUK_USE_DOUBLE_LE) || defined(DUK_USE_DOUBLE_ME)
#define DUK_FLT_IDX_UI0 0
#define DUK_FLT_IDX_US0 1
#define DUK_FLT_IDX_US1 0
#define DUK_FLT_IDX_UC0 3
#define DUK_FLT_IDX_UC1 2
#define DUK_FLT_IDX_UC2 1
#define DUK_FLT_IDX_UC3 0
#elif defined(DUK_USE_DOUBLE_BE)
#define DUK_FLT_IDX_UI0 0
#define DUK_FLT_IDX_US0 0
#define DUK_FLT_IDX_US1 1
#define DUK_FLT_IDX_UC0 0
#define DUK_FLT_IDX_UC1 1
#define DUK_FLT_IDX_UC2 2
#define DUK_FLT_IDX_UC3 3
#else
#error internal error
#endif
#endif /* DUK_FLTUNION_H_INCLUDED */

View file

@ -1,134 +0,0 @@
/*
* Forward declarations for all Duktape structures.
*/
#if !defined(DUK_FORWDECL_H_INCLUDED)
#define DUK_FORWDECL_H_INCLUDED
/*
* Forward declarations
*/
#if defined(DUK_USE_CPP_EXCEPTIONS)
class duk_internal_exception;
#else
struct duk_jmpbuf;
#endif
/* duk_tval intentionally skipped */
struct duk_heaphdr;
struct duk_heaphdr_string;
struct duk_harray;
struct duk_hstring;
struct duk_hstring_external;
struct duk_hobject;
struct duk_hcompfunc;
struct duk_hnatfunc;
struct duk_hboundfunc;
struct duk_hthread;
struct duk_hbufobj;
struct duk_hdecenv;
struct duk_hobjenv;
struct duk_hproxy;
struct duk_hbuffer;
struct duk_hbuffer_fixed;
struct duk_hbuffer_dynamic;
struct duk_hbuffer_external;
struct duk_propaccessor;
union duk_propvalue;
struct duk_propdesc;
struct duk_heap;
struct duk_breakpoint;
struct duk_activation;
struct duk_catcher;
struct duk_ljstate;
struct duk_strcache_entry;
struct duk_litcache_entry;
struct duk_strtab_entry;
#if defined(DUK_USE_DEBUG)
struct duk_fixedbuffer;
#endif
struct duk_bitdecoder_ctx;
struct duk_bitencoder_ctx;
struct duk_bufwriter_ctx;
struct duk_token;
struct duk_re_token;
struct duk_lexer_point;
struct duk_lexer_ctx;
struct duk_lexer_codepoint;
struct duk_compiler_instr;
struct duk_compiler_func;
struct duk_compiler_ctx;
struct duk_re_matcher_ctx;
struct duk_re_compiler_ctx;
#if defined(DUK_USE_CPP_EXCEPTIONS)
/* no typedef */
#else
typedef struct duk_jmpbuf duk_jmpbuf;
#endif
/* duk_tval intentionally skipped */
typedef struct duk_heaphdr duk_heaphdr;
typedef struct duk_heaphdr_string duk_heaphdr_string;
typedef struct duk_harray duk_harray;
typedef struct duk_hstring duk_hstring;
typedef struct duk_hstring_external duk_hstring_external;
typedef struct duk_hobject duk_hobject;
typedef struct duk_hcompfunc duk_hcompfunc;
typedef struct duk_hnatfunc duk_hnatfunc;
typedef struct duk_hboundfunc duk_hboundfunc;
typedef struct duk_hthread duk_hthread;
typedef struct duk_hbufobj duk_hbufobj;
typedef struct duk_hdecenv duk_hdecenv;
typedef struct duk_hobjenv duk_hobjenv;
typedef struct duk_hproxy duk_hproxy;
typedef struct duk_hbuffer duk_hbuffer;
typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
typedef struct duk_hbuffer_external duk_hbuffer_external;
typedef struct duk_propaccessor duk_propaccessor;
typedef union duk_propvalue duk_propvalue;
typedef struct duk_propdesc duk_propdesc;
typedef struct duk_heap duk_heap;
typedef struct duk_breakpoint duk_breakpoint;
typedef struct duk_activation duk_activation;
typedef struct duk_catcher duk_catcher;
typedef struct duk_ljstate duk_ljstate;
typedef struct duk_strcache_entry duk_strcache_entry;
typedef struct duk_litcache_entry duk_litcache_entry;
typedef struct duk_strtab_entry duk_strtab_entry;
#if defined(DUK_USE_DEBUG)
typedef struct duk_fixedbuffer duk_fixedbuffer;
#endif
typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx;
typedef struct duk_bitencoder_ctx duk_bitencoder_ctx;
typedef struct duk_bufwriter_ctx duk_bufwriter_ctx;
typedef struct duk_token duk_token;
typedef struct duk_re_token duk_re_token;
typedef struct duk_lexer_point duk_lexer_point;
typedef struct duk_lexer_ctx duk_lexer_ctx;
typedef struct duk_lexer_codepoint duk_lexer_codepoint;
typedef struct duk_compiler_instr duk_compiler_instr;
typedef struct duk_compiler_func duk_compiler_func;
typedef struct duk_compiler_ctx duk_compiler_ctx;
typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
#endif /* DUK_FORWDECL_H_INCLUDED */

View file

@ -1,48 +0,0 @@
/*
* Array object representation, used for actual Array instances.
*
* All objects with the exotic array behavior (which must coincide with having
* internal class array) MUST be duk_harrays. No other object can be a
* duk_harray. However, duk_harrays may not always have an array part.
*/
#if !defined(DUK_HARRAY_H_INCLUDED)
#define DUK_HARRAY_H_INCLUDED
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_harray_assert_valid(duk_harray *h);
#define DUK_HARRAY_ASSERT_VALID(h) do { duk_harray_assert_valid((h)); } while (0)
#else
#define DUK_HARRAY_ASSERT_VALID(h) do {} while (0)
#endif
#define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable)
#define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable)
#define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0)
#define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0)
struct duk_harray {
/* Shared object part. */
duk_hobject obj;
/* Array .length.
*
* At present Array .length may be smaller, equal, or even larger
* than the allocated underlying array part. Fast path code must
* always take this into account carefully.
*/
duk_uint32_t length;
/* Array .length property attributes. The property is always
* non-enumerable and non-configurable. It's initially writable
* but per Object.defineProperty() rules it can be made non-writable
* even if it is non-configurable. Thus we need to track the
* writability explicitly.
*
* XXX: this field to be eliminated and moved into duk_hobject
* flags field to save space.
*/
duk_bool_t length_nonwritable;
};
#endif /* DUK_HARRAY_H_INCLUDED */

View file

@ -1,37 +0,0 @@
/*
* Bound function representation.
*/
#if !defined(DUK_HBOUNDFUNC_H_INCLUDED)
#define DUK_HBOUNDFUNC_H_INCLUDED
/* Artificial limit for args length. Ensures arithmetic won't overflow
* 32 bits when combining bound functions.
*/
#define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_hboundfunc_assert_valid(duk_hboundfunc *h);
#define DUK_HBOUNDFUNC_ASSERT_VALID(h) do { duk_hboundfunc_assert_valid((h)); } while (0)
#else
#define DUK_HBOUNDFUNC_ASSERT_VALID(h) do {} while (0)
#endif
struct duk_hboundfunc {
/* Shared object part. */
duk_hobject obj;
/* Final target function, stored as duk_tval so that lightfunc can be
* represented too.
*/
duk_tval target;
/* This binding. */
duk_tval this_binding;
/* Arguments to prepend. */
duk_tval *args; /* Separate allocation. */
duk_idx_t nargs;
};
#endif /* DUK_HBOUNDFUNC_H_INCLUDED */

View file

@ -1,336 +0,0 @@
/*
* Heap buffer representation.
*
* Heap allocated user data buffer which is either:
*
* 1. A fixed size buffer (data follows header statically)
* 2. A dynamic size buffer (data pointer follows header)
*
* The data pointer for a variable size buffer of zero size may be NULL.
*/
#if !defined(DUK_HBUFFER_H_INCLUDED)
#define DUK_HBUFFER_H_INCLUDED
/*
* Flags
*
* Fixed buffer: 0
* Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC
* External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL
*/
#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */
#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */
#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
/*
* Misc defines
*/
/* Impose a maximum buffer length for now. Restricted artificially to
* ensure resize computations or adding a heap header length won't
* overflow size_t and that a signed duk_int_t can hold a buffer
* length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN.
*/
#if defined(DUK_USE_BUFLEN16)
#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL)
#else
/* Intentionally not 0x7fffffffUL; at least JSON code expects that
* 2*len + 2 fits in 32 bits.
*/
#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL)
#endif
/*
* Field access
*/
#if defined(DUK_USE_BUFLEN16)
/* size stored in duk_heaphdr unused flag bits */
#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
#define DUK_HBUFFER_SET_SIZE(x,v) do { \
duk_size_t duk__v; \
duk__v = (v); \
DUK_ASSERT(duk__v <= 0xffffUL); \
(x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \
} while (0)
#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
(x)->hdr.h_flags += ((dv) << 16); \
} while (0)
#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
(x)->hdr.h_flags -= ((dv) << 16); \
} while (0)
#else
#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size)
#define DUK_HBUFFER_SET_SIZE(x,v) do { \
((duk_hbuffer *) (x))->size = (v); \
} while (0)
#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
(x)->size += (dv); \
} while (0)
#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
(x)->size -= (dv); \
} while (0)
#endif
#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x))
#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv))
#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv))
#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (void *) (x)) + 1))
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16))
#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \
} while (0)
#else
#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc)
#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
(x)->curr_alloc = (void *) (v); \
} while (0)
#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
(x)->curr_alloc = (void *) NULL; \
} while (0)
#endif
/* No pointer compression because pointer is potentially outside of
* Duktape heap.
*/
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
((void *) (x)->curr_alloc)
#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
(x)->curr_alloc = (void *) (v); \
} while (0)
#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
(x)->curr_alloc = (void *) NULL; \
} while (0)
#else
#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
((void *) (x)->curr_alloc)
#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
(x)->curr_alloc = (void *) (v); \
} while (0)
#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
(x)->curr_alloc = (void *) NULL; \
} while (0)
#endif
/* Get a pointer to the current buffer contents (matching current allocation
* size). May be NULL for zero size dynamic/external buffer.
*/
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
( \
DUK_HBUFFER_HAS_EXTERNAL((x)) ? \
DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
) : \
DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
)
#else
/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
* have the same layout so checking for fixed vs. dynamic (or external) is enough.
*/
#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
)
#endif
/* Validity assert. */
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_hbuffer_assert_valid(duk_hbuffer *h);
#define DUK_HBUFFER_ASSERT_VALID(h) do { duk_hbuffer_assert_valid((h)); } while (0)
#else
#define DUK_HBUFFER_ASSERT_VALID(h) do {} while (0)
#endif
/*
* Structs
*/
/* Shared prefix for all buffer types. */
struct duk_hbuffer {
duk_heaphdr hdr;
/* It's not strictly necessary to track the current size, but
* it is useful for writing robust native code.
*/
/* Current size. */
#if defined(DUK_USE_BUFLEN16)
/* Stored in duk_heaphdr unused flags. */
#else
duk_size_t size;
#endif
/*
* Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
* flag.
*
* If the flag is clear (the buffer is a fixed size one), the buffer
* data follows the header directly, consisting of 'size' bytes.
*
* If the flag is set, the actual buffer is allocated separately, and
* a few control fields follow the header. Specifically:
*
* - a "void *" pointing to the current allocation
* - a duk_size_t indicating the full allocated size (always >= 'size')
*
* If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated
* by user code, so that Duktape won't be able to resize it and won't
* free it. This allows buffers to point to e.g. an externally
* allocated structure such as a frame buffer.
*
* Unlike strings, no terminator byte (NUL) is guaranteed after the
* data. This would be convenient, but would pad aligned user buffers
* unnecessarily upwards in size. For instance, if user code requested
* a 64-byte dynamic buffer, 65 bytes would actually be allocated which
* would then potentially round upwards to perhaps 68 or 72 bytes.
*/
};
/* Fixed buffer; data follows struct, with proper alignment guaranteed by
* struct size.
*/
#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
#pragma pack(push, 8)
#endif
struct duk_hbuffer_fixed {
/* A union is used here as a portable struct size / alignment trick:
* by adding a 32-bit or a 64-bit (unused) union member, the size of
* the struct is effectively forced to be a multiple of 4 or 8 bytes
* (respectively) without increasing the size of the struct unless
* necessary.
*/
union {
struct {
duk_heaphdr hdr;
#if defined(DUK_USE_BUFLEN16)
/* Stored in duk_heaphdr unused flags. */
#else
duk_size_t size;
#endif
} s;
#if (DUK_USE_ALIGN_BY == 4)
duk_uint32_t dummy_for_align4;
#elif (DUK_USE_ALIGN_BY == 8)
duk_double_t dummy_for_align8_1;
#if defined(DUK_USE_64BIT_OPS)
duk_uint64_t dummy_for_align8_2;
#endif
#elif (DUK_USE_ALIGN_BY == 1)
/* no extra padding */
#else
#error invalid DUK_USE_ALIGN_BY
#endif
} u;
/*
* Data follows the struct header. The struct size is padded by the
* compiler based on the struct members. This guarantees that the
* buffer data will be aligned-by-4 but not necessarily aligned-by-8.
*
* On platforms where alignment does not matter, the struct padding
* could be removed (if there is any). On platforms where alignment
* by 8 is required, the struct size must be forced to be a multiple
* of 8 by some means. Without it, some user code may break, and also
* Duktape itself breaks (e.g. the compiler stores duk_tvals in a
* dynamic buffer).
*/
}
#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
__attribute__ ((__aligned__ (8)))
#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
__attribute__ ((__aligned__ (8)))
#endif
;
#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
#pragma pack(pop)
#endif
/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using
* heap allocation primitives. Also used for external buffers when low memory
* options are not used.
*/
struct duk_hbuffer_dynamic {
duk_heaphdr hdr;
#if defined(DUK_USE_BUFLEN16)
/* Stored in duk_heaphdr unused flags. */
#else
duk_size_t size;
#endif
#if defined(DUK_USE_HEAPPTR16)
/* Stored in duk_heaphdr h_extra16. */
#else
void *curr_alloc; /* may be NULL if alloc_size == 0 */
#endif
/*
* Allocation size for 'curr_alloc' is alloc_size. There is no
* automatic NUL terminator for buffers (see above for rationale).
*
* 'curr_alloc' is explicitly allocated with heap allocation
* primitives and will thus always have alignment suitable for
* e.g. duk_tval and an IEEE double.
*/
};
/* External buffer with 'curr_alloc' managed by user code and pointing to an
* arbitrary address. When heap pointer compression is not used, this struct
* has the same layout as duk_hbuffer_dynamic.
*/
struct duk_hbuffer_external {
duk_heaphdr hdr;
#if defined(DUK_USE_BUFLEN16)
/* Stored in duk_heaphdr unused flags. */
#else
duk_size_t size;
#endif
/* Cannot be compressed as a heap pointer because may point to
* an arbitrary address.
*/
void *curr_alloc; /* may be NULL if alloc_size == 0 */
};
/*
* Prototypes
*/
DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata);
DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */
/* dynamic buffer ops */
DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size);
DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
#endif /* DUK_HBUFFER_H_INCLUDED */

View file

@ -1,132 +0,0 @@
/*
* duk_hbuffer allocation and freeing.
*/
#include "third_party/duktape/duk_internal.h"
/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
* (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
* allocation successful).
*/
DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
duk_hbuffer *res = NULL;
duk_size_t header_size;
duk_size_t alloc_size;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(out_bufdata != NULL);
DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
/* Size sanity check. Should not be necessary because caller is
* required to check this, but we don't want to cause a segfault
* if the size wraps either in duk_size_t computation or when
* storing the size in a 16-bit field.
*/
if (size > DUK_HBUFFER_MAX_BYTELEN) {
DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
return NULL; /* no need to write 'out_bufdata' */
}
if (flags & DUK_BUF_FLAG_EXTERNAL) {
header_size = sizeof(duk_hbuffer_external);
alloc_size = sizeof(duk_hbuffer_external);
} else if (flags & DUK_BUF_FLAG_DYNAMIC) {
header_size = sizeof(duk_hbuffer_dynamic);
alloc_size = sizeof(duk_hbuffer_dynamic);
} else {
header_size = sizeof(duk_hbuffer_fixed);
alloc_size = sizeof(duk_hbuffer_fixed) + size;
DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */
}
res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
if (DUK_UNLIKELY(res == NULL)) {
goto alloc_error;
}
/* zero everything unless requested not to do so */
#if defined(DUK_USE_ZERO_BUFFER_DATA)
duk_memzero((void *) res,
(flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
#else
duk_memzero((void *) res, header_size);
#endif
if (flags & DUK_BUF_FLAG_EXTERNAL) {
duk_hbuffer_external *h;
h = (duk_hbuffer_external *) res;
DUK_UNREF(h);
*out_bufdata = NULL;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
#else
DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
#endif
#endif
DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
} else if (flags & DUK_BUF_FLAG_DYNAMIC) {
duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
void *ptr;
if (size > 0) {
DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
#if defined(DUK_USE_ZERO_BUFFER_DATA)
ptr = DUK_ALLOC_ZEROED(heap, size);
#else
ptr = DUK_ALLOC(heap, size);
#endif
if (DUK_UNLIKELY(ptr == NULL)) {
/* Because size > 0, NULL check is correct */
goto alloc_error;
}
*out_bufdata = ptr;
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
} else {
*out_bufdata = NULL;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
#else
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
#endif
#endif
DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
}
} else {
*out_bufdata = (void *) ((duk_hbuffer_fixed *) (void *) res + 1);
}
DUK_HBUFFER_SET_SIZE(res, size);
DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
if (flags & DUK_BUF_FLAG_DYNAMIC) {
DUK_HBUFFER_SET_DYNAMIC(res);
if (flags & DUK_BUF_FLAG_EXTERNAL) {
DUK_HBUFFER_SET_EXTERNAL(res);
}
} else {
DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
}
DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
return res;
alloc_error:
DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
DUK_FREE(heap, res);
return NULL; /* no need to write 'out_bufdata' */
}
/* For indirect allocs. */
DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
DUK_UNREF(heap);
return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
}

View file

@ -1,13 +0,0 @@
/*
* duk_hbuffer assertion helpers
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL void duk_hbuffer_assert_valid(duk_hbuffer *h) {
DUK_ASSERT(h != NULL);
}
#endif /* DUK_USE_ASSERTIONS */

View file

@ -1,78 +0,0 @@
/*
* duk_hbuffer operations such as resizing and inserting/appending data to
* a dynamic buffer.
*/
#include "third_party/duktape/duk_internal.h"
/*
* Resizing
*/
DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) {
void *res;
duk_size_t prev_size;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(buf != NULL);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
/*
* Maximum size check
*/
if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
DUK_ERROR_RANGE(thr, "buffer too long");
DUK_WO_NORETURN(return;);
}
/*
* Note: use indirect realloc variant just in case mark-and-sweep
* (finalizers) might resize this same buffer during garbage
* collection.
*/
res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
if (DUK_LIKELY(res != NULL || new_size == 0)) {
/* 'res' may be NULL if new allocation size is 0. */
DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
(void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf),
(long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf),
(void *) res,
(long) new_size));
/*
* The entire allocated buffer area, regardless of actual used
* size, is kept zeroed in resizes for simplicity. If the buffer
* is grown, zero the new part.
*/
prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
if (new_size > prev_size) {
DUK_ASSERT(new_size - prev_size > 0);
#if defined(DUK_USE_ZERO_BUFFER_DATA)
duk_memzero((void *) ((char *) res + prev_size),
(duk_size_t) (new_size - prev_size));
#endif
}
DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
} else {
DUK_ERROR_ALLOC_FAILED(thr);
DUK_WO_NORETURN(return;);
}
DUK_ASSERT(res != NULL || new_size == 0);
}
DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(buf != NULL);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
duk_hbuffer_resize(thr, buf, 0);
}

View file

@ -1,127 +0,0 @@
/*
* Heap Buffer object representation. Used for all Buffer variants.
*/
#if !defined(DUK_HBUFOBJ_H_INCLUDED)
#define DUK_HBUFOBJ_H_INCLUDED
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
/* All element accessors are host endian now (driven by TypedArray spec). */
#define DUK_HBUFOBJ_ELEM_UINT8 0
#define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1
#define DUK_HBUFOBJ_ELEM_INT8 2
#define DUK_HBUFOBJ_ELEM_UINT16 3
#define DUK_HBUFOBJ_ELEM_INT16 4
#define DUK_HBUFOBJ_ELEM_UINT32 5
#define DUK_HBUFOBJ_ELEM_INT32 6
#define DUK_HBUFOBJ_ELEM_FLOAT32 7
#define DUK_HBUFOBJ_ELEM_FLOAT64 8
#define DUK_HBUFOBJ_ELEM_MAX 8
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_hbufobj_assert_valid(duk_hbufobj *h);
#define DUK_HBUFOBJ_ASSERT_VALID(h) do { duk_hbufobj_assert_valid((h)); } while (0)
#else
#define DUK_HBUFOBJ_ASSERT_VALID(h) do {} while (0)
#endif
/* Get the current data pointer (caller must ensure buf != NULL) as a
* duk_uint8_t ptr. Note that the result may be NULL if the underlying
* buffer has zero size and is not a fixed buffer.
*/
#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
(((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
/* True if slice is full, i.e. offset is zero and length covers the entire
* buffer. This status may change independently of the duk_hbufobj if
* the underlying buffer is dynamic and changes without the hbufobj
* being changed.
*/
#define DUK_HBUFOBJ_FULL_SLICE(h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Validate that the whole slice [0,length[ is contained in the underlying
* buffer. Caller must ensure 'buf' != NULL.
*/
#define DUK_HBUFOBJ_VALID_SLICE(h) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Validate byte read/write for virtual 'offset', i.e. check that the
* offset, taking into account h->offset, is within the underlying
* buffer size. This is a safety check which is needed to ensure
* that even a misconfigured duk_hbufobj never causes memory unsafe
* behavior (e.g. if an underlying dynamic buffer changes after being
* setup). Caller must ensure 'buf' != NULL.
*/
#define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
#define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \
(DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
/* Clamp an input byte length (already assumed to be within the nominal
* duk_hbufobj 'length') to the current dynamic buffer limits to yield
* a byte length limit that's safe for memory accesses. This value can
* be invalidated by any side effect because it may trigger a user
* callback that resizes the underlying buffer.
*/
#define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \
(DUK_ASSERT_EXPR((h) != NULL), \
duk_hbufobj_clamp_bytelength((h), (len)))
/* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */
#define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray)
struct duk_hbufobj {
/* Shared object part. */
duk_hobject obj;
/* Underlying buffer (refcounted), may be NULL. */
duk_hbuffer *buf;
/* .buffer reference to an ArrayBuffer, may be NULL. */
duk_hobject *buf_prop;
/* Slice and accessor information.
*
* Because the underlying buffer may be dynamic, these may be
* invalidated by the buffer being modified so that both offset
* and length should be validated before every access. Behavior
* when the underlying buffer has changed doesn't need to be clean:
* virtual 'length' doesn't need to be affected, reads can return
* zero/NaN, and writes can be ignored.
*
* Note that a data pointer cannot be precomputed because 'buf' may
* be dynamic and its pointer unstable.
*/
duk_uint_t offset; /* byte offset to buf */
duk_uint_t length; /* byte index limit for element access, exclusive */
duk_uint8_t shift; /* element size shift:
* 0 = u8/i8
* 1 = u16/i16
* 2 = u32/i32/float
* 3 = double
*/
duk_uint8_t elem_type; /* element type */
duk_uint8_t is_typedarray;
};
DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len);
DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf);
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);
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);
DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx);
#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* nothing */
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
#endif /* DUK_HBUFOBJ_H_INCLUDED */

View file

@ -1,20 +0,0 @@
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len) {
duk_uint_t buf_size;
duk_uint_t buf_avail;
DUK_ASSERT(h_bufobj != NULL);
DUK_ASSERT(h_bufobj->buf != NULL);
buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf);
if (h_bufobj->offset > buf_size) {
/* Slice starting point is beyond current length. */
return 0;
}
buf_avail = buf_size - h_bufobj->offset;
return buf_avail >= len ? len : buf_avail;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */

View file

@ -1,273 +0,0 @@
/*
* Heap compiled function (ECMAScript function) representation.
*
* There is a single data buffer containing the ECMAScript function's
* bytecode, constants, and inner functions.
*/
#if !defined(DUK_HCOMPFUNC_H_INCLUDED)
#define DUK_HCOMPFUNC_H_INCLUDED
/*
* Field accessor macros
*/
/* XXX: casts could be improved, especially for GET/SET DATA */
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HCOMPFUNC_GET_DATA(heap,h) \
((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
(h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \
((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
(h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \
((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
(h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \
((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16)))
#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
(h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
#define DUK_HCOMPFUNC_GET_VARENV(heap,h) \
((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16)))
#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
(h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
} while (0)
#else
#define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data)
#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
(h)->data = (duk_hbuffer *) (v); \
} while (0)
#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs)
#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
(h)->funcs = (v); \
} while (0)
#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode)
#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
(h)->bytecode = (v); \
} while (0)
#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env)
#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
(h)->lex_env = (v); \
} while (0)
#define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env)
#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
(h)->var_env = (v); \
} while (0)
#endif
/*
* Accessor macros for function specific data areas
*/
/* Note: assumes 'data' is always a fixed buffer */
#define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \
DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h)))
#define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \
((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h)))
#define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \
DUK_HCOMPFUNC_GET_FUNCS((heap), (h))
#define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \
DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))
#define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \
((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h)))
#define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \
((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)))
/* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */
#define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \
((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \
DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h))))
#define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \
( \
(duk_size_t) \
( \
((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \
((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \
) \
)
#define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \
( \
(duk_size_t) \
( \
((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \
((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \
) \
)
#define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \
( \
(duk_size_t) \
( \
((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \
((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \
) \
)
#define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \
((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
#define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \
((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \
((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
/*
* Validity assert
*/
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_hcompfunc_assert_valid(duk_hcompfunc *h);
#define DUK_HCOMPFUNC_ASSERT_VALID(h) do { duk_hcompfunc_assert_valid((h)); } while (0)
#else
#define DUK_HCOMPFUNC_ASSERT_VALID(h) do {} while (0)
#endif
/*
* Main struct
*/
struct duk_hcompfunc {
/* shared object part */
duk_hobject obj;
/*
* Pointers to function data area for faster access. Function
* data is a buffer shared between all closures of the same
* "template" function. The data buffer is always fixed (non-
* dynamic, hence stable), with a layout as follows:
*
* constants (duk_tval)
* inner functions (duk_hobject *)
* bytecode (duk_instr_t)
*
* Note: bytecode end address can be computed from 'data' buffer
* size. It is not strictly necessary functionally, assuming
* bytecode never jumps outside its allocated area. However,
* it's a safety/robustness feature for avoiding the chance of
* executing random data as bytecode due to a compiler error.
*
* Note: values in the data buffer must be incref'd (they will
* be decref'd on release) for every compiledfunction referring
* to the 'data' element.
*/
/* Data area, fixed allocation, stable data ptrs. */
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t data16;
#else
duk_hbuffer *data;
#endif
/* No need for constants pointer (= same as data).
*
* When using 16-bit packing alignment to 4 is nice. 'funcs' will be
* 4-byte aligned because 'constants' are duk_tvals. For now the
* inner function pointers are not compressed, so that 'bytecode' will
* also be 4-byte aligned.
*/
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t funcs16;
duk_uint16_t bytecode16;
#else
duk_hobject **funcs;
duk_instr_t *bytecode;
#endif
/* Lexenv: lexical environment of closure, NULL for templates.
* Varenv: variable environment of closure, NULL for templates.
*/
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t lex_env16;
duk_uint16_t var_env16;
#else
duk_hobject *lex_env;
duk_hobject *var_env;
#endif
/*
* 'nregs' registers are allocated on function entry, at most 'nargs'
* are initialized to arguments, and the rest to undefined. Arguments
* above 'nregs' are not mapped to registers. All registers in the
* active stack range must be initialized because they are GC reachable.
* 'nargs' is needed so that if the function is given more than 'nargs'
* arguments, the additional arguments do not 'clobber' registers
* beyond 'nregs' which must be consistently initialized to undefined.
*
* Usually there is no need to know which registers are mapped to
* local variables. Registers may be allocated to variable in any
* way (even including gaps). However, a register-variable mapping
* must be the same for the duration of the function execution and
* the register cannot be used for anything else.
*
* When looking up variables by name, the '_Varmap' map is used.
* When an activation closes, registers mapped to arguments are
* copied into the environment record based on the same map. The
* reverse map (from register to variable) is not currently needed
* at run time, except for debugging, so it is not maintained.
*/
duk_uint16_t nregs; /* regs to allocate */
duk_uint16_t nargs; /* number of arguments allocated to regs */
/*
* Additional control information is placed into the object itself
* as internal properties to avoid unnecessary fields for the
* majority of functions. The compiler tries to omit internal
* control fields when possible.
*
* Function templates:
*
* {
* name: "func", // declaration, named function expressions
* fileName: <debug info for creating nice errors>
* _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
* _Formals: [ "arg1", "arg2" ],
* _Source: "function func(arg1, arg2) { ... }",
* _Pc2line: <debug info for pc-to-line mapping>,
* }
*
* Function instances:
*
* {
* length: 2,
* prototype: { constructor: <func> },
* caller: <thrower>,
* arguments: <thrower>,
* name: "func", // declaration, named function expressions
* fileName: <debug info for creating nice errors>
* _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
* _Formals: [ "arg1", "arg2" ],
* _Source: "function func(arg1, arg2) { ... }",
* _Pc2line: <debug info for pc-to-line mapping>,
* }
*
* More detailed description of these properties can be found
* in the documentation.
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
/* Line number range for function. Needed during debugging to
* determine active breakpoints.
*/
duk_uint32_t start_line;
duk_uint32_t end_line;
#endif
};
#endif /* DUK_HCOMPFUNC_H_INCLUDED */

View file

@ -1,723 +0,0 @@
/*
* Heap structure.
*
* Heap contains allocated heap objects, interned strings, and built-in
* strings for one or more threads.
*/
#if !defined(DUK_HEAP_H_INCLUDED)
#define DUK_HEAP_H_INCLUDED
/* alloc function typedefs in duktape.h */
/*
* Heap flags
*/
#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1U << 0) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1U << 1) /* executor interrupt running (used to avoid nested interrupts) */
#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1U << 2) /* heap destruction ongoing, finalizer rescue no longer possible */
#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1U << 3) /* debugger is paused: talk with debug client until step/resume */
#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
(heap)->flags |= (bits); \
} while (0)
#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \
(heap)->flags &= ~(bits); \
} while (0)
#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
/*
* Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
*/
#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */
#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */
#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */
#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */
#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */
#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */
#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */
/*
* Mark-and-sweep flags
*
* These are separate from heap level flags now but could be merged.
* The heap structure only contains a 'base mark-and-sweep flags'
* field and the GC caller can impose further flags.
*/
/* Emergency mark-and-sweep: try extra hard, even at the cost of
* performance.
*/
#define DUK_MS_FLAG_EMERGENCY (1U << 0)
/* Postpone rescue decisions for reachable objects with FINALIZED set.
* Used during finalize_list processing to avoid incorrect rescue
* decisions due to finalize_list being a reachability root.
*/
#define DUK_MS_FLAG_POSTPONE_RESCUE (1U << 1)
/* Don't compact objects; needed during object property table resize
* to prevent a recursive resize. It would suffice to protect only the
* current object being resized, but this is not yet implemented.
*/
#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1U << 2)
/*
* Thread switching
*
* To switch heap->curr_thread, use the macro below so that interrupt counters
* get updated correctly. The macro allows a NULL target thread because that
* happens e.g. in call handling.
*/
#if defined(DUK_USE_INTERRUPT_COUNTER)
#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr))
#else
#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \
(heap)->curr_thread = (newthr); \
} while (0)
#endif
/*
* Stats
*/
#if defined(DUK_USE_DEBUG)
#define DUK_STATS_INC(heap,fieldname) do { \
(heap)->fieldname += 1; \
} while (0)
#else
#define DUK_STATS_INC(heap,fieldname) do {} while (0)
#endif
/*
* Other heap related defines
*/
/* Mark-and-sweep interval is relative to combined count of objects and
* strings kept in the heap during the latest mark-and-sweep pass.
* Fixed point .8 multiplier and .0 adder. Trigger count (interval) is
* decreased by each (re)allocation attempt (regardless of size), and each
* refzero processed object.
*
* 'SKIP' indicates how many (re)allocations to wait until a retry if
* GC is skipped because there is no thread do it with yet (happens
* only during init phases).
*/
#if defined(DUK_USE_REFERENCE_COUNTING)
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
#else
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
#endif
/* GC torture. */
#if defined(DUK_USE_GC_TORTURE)
#define DUK_GC_TORTURE(heap) do { duk_heap_mark_and_sweep((heap), 0); } while (0)
#else
#define DUK_GC_TORTURE(heap) do { } while (0)
#endif
/* Stringcache is used for speeding up char-offset-to-byte-offset
* translations for non-ASCII strings.
*/
#define DUK_HEAP_STRCACHE_SIZE 4
#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
/* Some list management macros. */
#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap), (hdr))
#if defined(DUK_USE_REFERENCE_COUNTING)
#define DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap,hdr) duk_heap_remove_from_heap_allocated((heap), (hdr))
#endif
#if defined(DUK_USE_FINALIZER_SUPPORT)
#define DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap,hdr) duk_heap_insert_into_finalize_list((heap), (hdr))
#define DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap,hdr) duk_heap_remove_from_finalize_list((heap), (hdr))
#endif
/*
* Built-in strings
*/
/* heap string indices are autogenerated in duk_strings.h */
#if defined(DUK_USE_ROM_STRINGS)
#define DUK_HEAP_GET_STRING(heap,idx) \
((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
#else /* DUK_USE_ROM_STRINGS */
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HEAP_GET_STRING(heap,idx) \
((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)]))
#else
#define DUK_HEAP_GET_STRING(heap,idx) \
((heap)->strs[(idx)])
#endif
#endif /* DUK_USE_ROM_STRINGS */
/*
* Raw memory calls: relative to heap, but no GC interaction
*/
#define DUK_ALLOC_RAW(heap,size) \
((heap)->alloc_func((heap)->heap_udata, (size)))
#define DUK_REALLOC_RAW(heap,ptr,newsize) \
((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize)))
#define DUK_FREE_RAW(heap,ptr) \
((heap)->free_func((heap)->heap_udata, (void *) (ptr)))
/*
* Memory calls: relative to heap, GC interaction, but no error throwing.
*
* XXX: Currently a mark-and-sweep triggered by memory allocation will run
* using the heap->heap_thread. This thread is also used for running
* mark-and-sweep finalization; this is not ideal because it breaks the
* isolation between multiple global environments.
*
* Notes:
*
* - DUK_FREE() is required to ignore NULL and any other possible return
* value of a zero-sized alloc/realloc (same as ANSI C free()).
*
* - There is no DUK_REALLOC_ZEROED because we don't assume to know the
* old size. Caller must zero the reallocated memory.
*
* - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
* by an allocation failure might invalidate the original 'ptr', thus
* causing a realloc retry to use an invalid pointer. Example: we're
* reallocating the value stack and a finalizer resizes the same value
* stack during mark-and-sweep. The indirect variant requests for the
* current location of the pointer being reallocated using a callback
* right before every realloc attempt; this circuitous approach is used
* to avoid strict aliasing issues in a more straightforward indirect
* pointer (void **) approach. Note: the pointer in the storage
* location is read but is NOT updated; the caller must do that.
*/
/* callback for indirect reallocs, request for current pointer */
typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size))
#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size))
#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize))
#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
/*
* Checked allocation, relative to a thread
*
* DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument
* for convenience.
*/
#define DUK_ALLOC_CHECKED(thr,size) duk_heap_mem_alloc_checked((thr), (size))
#define DUK_ALLOC_CHECKED_ZEROED(thr,size) duk_heap_mem_alloc_checked_zeroed((thr), (size))
#define DUK_FREE_CHECKED(thr,ptr) duk_heap_mem_free((thr)->heap, (ptr))
/*
* Memory constants
*/
#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 10 /* Retry allocation after mark-and-sweep for this
* many times. A single mark-and-sweep round is
* not guaranteed to free all unreferenced memory
* because of finalization (in fact, ANY number of
* rounds is strictly not enough).
*/
#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode
* for mark-and-sweep.
*/
/*
* Debugger support
*/
/* Maximum number of breakpoints. Only breakpoints that are set are
* consulted so increasing this has no performance impact.
*/
#define DUK_HEAP_MAX_BREAKPOINTS 16
/* Opcode interval for a Date-based status/peek rate limit check. Only
* relevant when debugger is attached. Requesting a timestamp may be a
* slow operation on some platforms so this shouldn't be too low. On the
* other hand a high value makes Duktape react to a pause request slowly.
*/
#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000
/* Milliseconds between status notify and transport peeks. */
#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
/* Debugger pause flags. */
#define DUK_PAUSE_FLAG_ONE_OPCODE (1U << 0) /* pause when a single opcode has been executed */
#define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1) /* one opcode pause actually active; artifact of current implementation */
#define DUK_PAUSE_FLAG_LINE_CHANGE (1U << 2) /* pause when current line number changes */
#define DUK_PAUSE_FLAG_FUNC_ENTRY (1U << 3) /* pause when entering a function */
#define DUK_PAUSE_FLAG_FUNC_EXIT (1U << 4) /* pause when exiting current function */
#define DUK_PAUSE_FLAG_CAUGHT_ERROR (1U << 5) /* pause when about to throw an error that is caught */
#define DUK_PAUSE_FLAG_UNCAUGHT_ERROR (1U << 6) /* pause when about to throw an error that won't be caught */
struct duk_breakpoint {
duk_hstring *filename;
duk_uint32_t line;
};
/*
* String cache should ideally be at duk_hthread level, but that would
* cause string finalization to slow down relative to the number of
* threads; string finalization must check the string cache for "weak"
* references to the string being finalized to avoid dead pointers.
*
* Thus, string caches are now at the heap level now.
*/
struct duk_strcache_entry {
duk_hstring *h;
duk_uint32_t bidx;
duk_uint32_t cidx;
};
/*
* Longjmp state, contains the information needed to perform a longjmp.
* Longjmp related values are written to value1, value2, and iserror.
*/
struct duk_ljstate {
duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
duk_small_uint_t type; /* longjmp type */
duk_bool_t iserror; /* isError flag for yield */
duk_tval value1; /* 1st related value (type specific) */
duk_tval value2; /* 2nd related value (type specific) */
};
#define DUK_ASSERT_LJSTATE_UNSET(heap) do { \
DUK_ASSERT(heap != NULL); \
DUK_ASSERT(heap->lj.type == DUK_LJ_TYPE_UNKNOWN); \
DUK_ASSERT(heap->lj.iserror == 0); \
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value1)); \
DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value2)); \
} while (0)
#define DUK_ASSERT_LJSTATE_SET(heap) do { \
DUK_ASSERT(heap != NULL); \
DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \
} while (0)
/*
* Literal intern cache
*/
struct duk_litcache_entry {
const duk_uint8_t *addr;
duk_hstring *h;
};
/*
* Main heap structure
*/
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_heap_assert_valid(duk_heap *heap);
#define DUK_HEAP_ASSERT_VALID(heap) do { duk_heap_assert_valid((heap)); } while (0)
#else
#define DUK_HEAP_ASSERT_VALID(heap) do {} while (0)
#endif
struct duk_heap {
duk_small_uint_t flags;
/* Allocator functions. */
duk_alloc_function alloc_func;
duk_realloc_function realloc_func;
duk_free_function free_func;
/* Heap udata, used for allocator functions but also for other heap
* level callbacks like fatal function, pointer compression, etc.
*/
void *heap_udata;
/* Fatal error handling, called e.g. when a longjmp() is needed but
* lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
* declared as "noreturn" because doing that for typedefs is a bit
* challenging portability-wise.
*/
duk_fatal_function fatal_func;
/* Main list of allocated heap objects. Objects are either here,
* in finalize_list waiting for processing, or in refzero_list
* temporarily while a DECREF refzero cascade finishes.
*/
duk_heaphdr *heap_allocated;
/* Temporary work list for freeing a cascade of objects when a DECREF
* (or DECREF_NORZ) encounters a zero refcount. Using a work list
* allows fixed C stack size when refcounts go to zero for a chain of
* objects. Outside of DECREF this is always a NULL because DECREF is
* processed without side effects (only memory free calls).
*/
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_heaphdr *refzero_list;
#endif
#if defined(DUK_USE_FINALIZER_SUPPORT)
/* Work list for objects to be finalized. */
duk_heaphdr *finalize_list;
#if defined(DUK_USE_ASSERTIONS)
/* Object whose finalizer is executing right now (no nesting). */
duk_heaphdr *currently_finalizing;
#endif
#endif
/* Freelist for duk_activations and duk_catchers. */
#if defined(DUK_USE_CACHE_ACTIVATION)
duk_activation *activation_free;
#endif
#if defined(DUK_USE_CACHE_CATCHER)
duk_catcher *catcher_free;
#endif
/* Voluntary mark-and-sweep trigger counter. Intentionally signed
* because we continue decreasing the value when voluntary GC cannot
* run.
*/
#if defined(DUK_USE_VOLUNTARY_GC)
duk_int_t ms_trigger_counter;
#endif
/* Mark-and-sweep recursion control: too deep recursion causes
* multi-pass processing to avoid growing C stack without bound.
*/
duk_uint_t ms_recursion_depth;
/* Mark-and-sweep flags automatically active (used for critical sections). */
duk_small_uint_t ms_base_flags;
/* Mark-and-sweep running flag. Prevents re-entry, and also causes
* refzero events to be ignored (= objects won't be queued to refzero_list).
*
* 0: mark-and-sweep not running
* 1: mark-and-sweep is running
* 2: heap destruction active or debugger active, prevent mark-and-sweep
* and refzero processing (but mark-and-sweep not itself running)
*/
duk_uint_t ms_running;
/* Mark-and-sweep prevent count, stacking. Used to avoid M&S side
* effects (besides finalizers which are controlled separately) such
* as compacting the string table or object property tables. This
* is also bumped when ms_running is set to prevent recursive re-entry.
* Can also be bumped when mark-and-sweep is not running.
*/
duk_uint_t ms_prevent_count;
/* Finalizer processing prevent count, stacking. Bumped when finalizers
* are processed to prevent recursive finalizer processing (first call site
* processing finalizers handles all finalizers until the list is empty).
* Can also be bumped explicitly to prevent finalizer execution.
*/
duk_uint_t pf_prevent_count;
/* When processing finalize_list, don't actually run finalizers but
* queue finalizable objects back to heap_allocated as is. This is
* used during heap destruction to deal with finalizers that keep
* on creating more finalizable garbage.
*/
duk_uint_t pf_skip_finalizers;
#if defined(DUK_USE_ASSERTIONS)
/* Set when we're in a critical path where an error throw would cause
* e.g. sandboxing/protected call violations or state corruption. This
* is just used for asserts.
*/
duk_bool_t error_not_allowed;
#endif
#if defined(DUK_USE_ASSERTIONS)
/* Set when heap is still being initialized, helps with writing
* some assertions.
*/
duk_bool_t heap_initializing;
#endif
/* Marker for detecting internal "double faults", errors thrown when
* we're trying to create an error object, see duk_error_throw.c.
*/
duk_bool_t creating_error;
/* Marker for indicating we're calling a user error augmentation
* (errCreate/errThrow) function. Errors created/thrown during
* such a call are not augmented.
*/
#if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
duk_bool_t augmenting_error;
#endif
/* Longjmp state. */
duk_ljstate lj;
/* Heap thread, used internally and for finalization. */
duk_hthread *heap_thread;
/* Current running thread. */
duk_hthread *curr_thread;
/* Heap level "stash" object (e.g., various reachability roots). */
duk_hobject *heap_object;
/* duk_handle_call / duk_handle_safe_call recursion depth limiting */
duk_int_t call_recursion_depth;
duk_int_t call_recursion_limit;
/* Mix-in value for computing string hashes; should be reasonably unpredictable. */
duk_uint32_t hash_seed;
/* Random number state for duk_util_tinyrandom.c. */
#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */
#else
duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */
#endif
#endif
/* Counter for unique local symbol creation. */
/* XXX: When 64-bit types are available, it would be more efficient to
* use a duk_uint64_t at least for incrementing but maybe also for
* string formatting in the Symbol constructor.
*/
duk_uint32_t sym_counter[2];
/* For manual debugging: instruction count based on executor and
* interrupt counter book-keeping. Inspect debug logs to see how
* they match up.
*/
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk_int_t inst_count_exec;
duk_int_t inst_count_interrupt;
#endif
/* Debugger state. */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
/* Callbacks and udata; dbg_read_cb != NULL is used to indicate attached state. */
duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
duk_debug_write_function dbg_write_cb; /* required */
duk_debug_peek_function dbg_peek_cb;
duk_debug_read_flush_function dbg_read_flush_cb;
duk_debug_write_flush_function dbg_write_flush_cb;
duk_debug_request_function dbg_request_cb;
duk_debug_detached_function dbg_detached_cb;
void *dbg_udata;
/* The following are only relevant when debugger is attached. */
duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
duk_small_uint_t dbg_pause_flags; /* flags for automatic pause behavior */
duk_activation *dbg_pause_act; /* activation related to pause behavior (pause on line change, function entry/exit) */
duk_uint32_t dbg_pause_startline; /* starting line number for line change related pause behavior */
duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
duk_small_uint_t dbg_breakpoint_count;
duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
/* XXX: make active breakpoints actual copies instead of pointers? */
/* These are for rate limiting Status notifications and transport peeking. */
duk_uint_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
duk_uint_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
/* Used to support single-byte stream lookahead. */
duk_bool_t dbg_have_next_byte;
duk_uint8_t dbg_next_byte;
#endif /* DUK_USE_DEBUGGER_SUPPORT */
#if defined(DUK_USE_ASSERTIONS)
duk_bool_t dbg_calling_transport; /* transport call in progress, calling into Duktape forbidden */
#endif
/* String intern table (weak refs). */
#if defined(DUK_USE_STRTAB_PTRCOMP)
duk_uint16_t *strtable16;
#else
duk_hstring **strtable;
#endif
duk_uint32_t st_mask; /* mask for lookup, st_size - 1 */
duk_uint32_t st_size; /* stringtable size */
#if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
duk_uint32_t st_count; /* string count for resize load factor checks */
#endif
duk_bool_t st_resizing; /* string table is being resized; avoid recursive resize */
/* String access cache (codepoint offset -> byte offset) for fast string
* character looping; 'weak' reference which needs special handling in GC.
*/
duk_strcache_entry strcache[DUK_HEAP_STRCACHE_SIZE];
#if defined(DUK_USE_LITCACHE_SIZE)
/* Literal intern cache. When enabled, strings interned as literals
* (e.g. duk_push_literal()) will be pinned and cached for the lifetime
* of the heap.
*/
duk_litcache_entry litcache[DUK_USE_LITCACHE_SIZE];
#endif
/* Built-in strings. */
#if defined(DUK_USE_ROM_STRINGS)
/* No field needed when strings are in ROM. */
#else
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS];
#else
duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
#endif
#endif
/* Stats. */
#if defined(DUK_USE_DEBUG)
duk_int_t stats_exec_opcodes;
duk_int_t stats_exec_interrupt;
duk_int_t stats_exec_throw;
duk_int_t stats_call_all;
duk_int_t stats_call_tailcall;
duk_int_t stats_call_ecmatoecma;
duk_int_t stats_safecall_all;
duk_int_t stats_safecall_nothrow;
duk_int_t stats_safecall_throw;
duk_int_t stats_ms_try_count;
duk_int_t stats_ms_skip_count;
duk_int_t stats_ms_emergency_count;
duk_int_t stats_strtab_intern_hit;
duk_int_t stats_strtab_intern_miss;
duk_int_t stats_strtab_resize_check;
duk_int_t stats_strtab_resize_grow;
duk_int_t stats_strtab_resize_shrink;
duk_int_t stats_strtab_litcache_hit;
duk_int_t stats_strtab_litcache_miss;
duk_int_t stats_strtab_litcache_pin;
duk_int_t stats_object_realloc_props;
duk_int_t stats_object_abandon_array;
duk_int_t stats_getownpropdesc_count;
duk_int_t stats_getownpropdesc_hit;
duk_int_t stats_getownpropdesc_miss;
duk_int_t stats_getpropdesc_count;
duk_int_t stats_getpropdesc_hit;
duk_int_t stats_getpropdesc_miss;
duk_int_t stats_getprop_all;
duk_int_t stats_getprop_arrayidx;
duk_int_t stats_getprop_bufobjidx;
duk_int_t stats_getprop_bufferidx;
duk_int_t stats_getprop_bufferlen;
duk_int_t stats_getprop_stringidx;
duk_int_t stats_getprop_stringlen;
duk_int_t stats_getprop_proxy;
duk_int_t stats_getprop_arguments;
duk_int_t stats_putprop_all;
duk_int_t stats_putprop_arrayidx;
duk_int_t stats_putprop_bufobjidx;
duk_int_t stats_putprop_bufferidx;
duk_int_t stats_putprop_proxy;
duk_int_t stats_getvar_all;
duk_int_t stats_putvar_all;
duk_int_t stats_envrec_delayedcreate;
duk_int_t stats_envrec_create;
duk_int_t stats_envrec_newenv;
duk_int_t stats_envrec_oldenv;
duk_int_t stats_envrec_pushclosure;
#endif
};
/*
* Prototypes
*/
DUK_INTERNAL_DECL
duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
duk_realloc_function realloc_func,
duk_free_function free_func,
void *heap_udata,
duk_fatal_function fatal_func);
DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h);
DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h);
DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h);
DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_INTERNAL_DECL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
#endif
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL_DECL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
DUK_INTERNAL_DECL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
#endif
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr);
#endif
#if defined(DUK_USE_INTERRUPT_COUNTER)
DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
#endif
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
#if defined(DUK_USE_LITCACHE_SIZE)
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen);
#endif
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val);
DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h);
#endif
DUK_INTERNAL_DECL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev);
DUK_INTERNAL_DECL void duk_heap_strtable_force_resize(duk_heap *heap);
DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap);
#if defined(DUK_USE_DEBUG)
DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap);
#endif
DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size);
DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize);
DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
#endif
DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size);
DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap);
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj);
DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap);
#endif /* DUK_USE_FINALIZER_SUPPORT */
DUK_INTERNAL_DECL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
#endif /* DUK_HEAP_H_INCLUDED */

File diff suppressed because it is too large Load diff

View file

@ -1,445 +0,0 @@
/*
* Finalizer handling.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_FINALIZER_SUPPORT)
/*
* Fake torture finalizer.
*/
#if defined(DUK_USE_FINALIZER_TORTURE)
DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_hthread *thr) {
DUK_DD(DUK_DDPRINT("fake global torture finalizer executed"));
/* Require a lot of stack to force a value stack grow/shrink. */
duk_require_stack(thr, 100000);
/* Force a reallocation with pointer change for value stack
* to maximize side effects.
*/
duk_hthread_valstack_torture_realloc(thr);
/* Inner function call, error throw. */
duk_eval_string_noresult(thr,
"(function dummy() {\n"
" dummy.prototype = null; /* break reference loop */\n"
" try {\n"
" throw 'fake-finalizer-dummy-error';\n"
" } catch (e) {\n"
" void e;\n"
" }\n"
"})()");
/* The above creates garbage (e.g. a function instance). Because
* the function/prototype reference loop is broken, it gets collected
* immediately by DECREF. If Function.prototype has a _Finalizer
* property (happens in some test cases), the garbage gets queued to
* finalize_list. This still won't cause an infinite loop because
* the torture finalizer is called once per finalize_list run and
* the garbage gets handled in the same run. (If the garbage needs
* mark-and-sweep collection, an infinite loop might ensue.)
*/
return 0;
}
DUK_LOCAL void duk__run_global_torture_finalizer(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
/* Avoid fake finalization when callstack limit is near. Otherwise
* a callstack limit error will be created, then refzero'ed. The
* +5 headroom is conservative.
*/
if (thr->heap->call_recursion_depth + 5 >= thr->heap->call_recursion_limit ||
thr->callstack_top + 5 >= DUK_USE_CALLSTACK_LIMIT) {
DUK_D(DUK_DPRINT("skip global torture finalizer, too little headroom for call recursion or call stack size"));
return;
}
/* Run fake finalizer. Avoid creating unnecessary garbage. */
duk_push_c_function(thr, duk__fake_global_finalizer, 0 /*nargs*/);
(void) duk_pcall(thr, 0 /*nargs*/);
duk_pop(thr);
}
#endif /* DUK_USE_FINALIZER_TORTURE */
/*
* Process the finalize_list to completion.
*
* An object may be placed on finalize_list by either refcounting or
* mark-and-sweep. The refcount of objects placed by refcounting will be
* zero; the refcount of objects placed by mark-and-sweep is > 0. In both
* cases the refcount is bumped by 1 artificially so that a REFZERO event
* can never happen while an object is waiting for finalization. Without
* this bump a REFZERO could now happen because user code may call
* duk_push_heapptr() and then pop a value even when it's on finalize_list.
*
* List processing assumes refcounts are kept up-to-date at all times, so
* that once the finalizer returns, a zero refcount is a reliable reason to
* free the object immediately rather than place it back to the heap. This
* is the case because we run outside of refzero_list processing so that
* DECREF cascades are handled fully inline.
*
* For mark-and-sweep queued objects (had_zero_refcount false) the object
* may be freed immediately if its refcount is zero after the finalizer call
* (i.e. finalizer removed the reference loop for the object). If not, the
* next mark-and-sweep will collect the object unless it has become reachable
* (i.e. rescued) by that time and its refcount hasn't fallen to zero before
* that. Mark-and-sweep detects these objects because their FINALIZED flag
* is set.
*
* There's an inherent limitation for mark-and-sweep finalizer rescuing: an
* object won't get refinalized if (1) it's rescued, but (2) becomes
* unreachable before mark-and-sweep has had time to notice it. The next
* mark-and-sweep round simply doesn't have any information of whether the
* object has been unreachable the whole time or not (the only way to get
* that information would be a mark-and-sweep pass for *every finalized
* object*). This is awkward for the application because the mark-and-sweep
* round is not generally visible or under full application control.
*
* For refcount queued objects (had_zero_refcount true) the object is either
* immediately freed or rescued, and waiting for a mark-and-sweep round is not
* necessary (or desirable); FINALIZED is cleared when a rescued object is
* queued back to heap_allocated. The object is eligible for finalization
* again (either via refcounting or mark-and-sweep) immediately after being
* rescued. If a refcount finalized object is placed into an unreachable
* reference loop by its finalizer, it will get collected by mark-and-sweep
* and currently the finalizer will execute again.
*
* There's a special case where:
*
* - Mark-and-sweep queues an object to finalize_list for finalization.
* - The finalizer is executed, FINALIZED is set, and object is queued
* back to heap_allocated, waiting for a new mark-and-sweep round.
* - The object's refcount drops to zero before mark-and-sweep has a
* chance to run another round and make a rescue/free decision.
*
* This is now handled by refzero code: if an object has a finalizer but
* FINALIZED is already set, the object is freed without finalizer processing.
* The outcome is the same as if mark-and-sweep was executed at that point;
* mark-and-sweep would also free the object without another finalizer run.
* This could also be changed so that the refzero-triggered finalizer *IS*
* executed: being refzero collected implies someone has operated on the
* object so it hasn't been totally unreachable the whole time. This would
* risk a finalizer loop however.
*/
DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) {
duk_heaphdr *curr;
#if defined(DUK_USE_DEBUG)
duk_size_t count = 0;
#endif
DUK_DDD(DUK_DDDPRINT("duk_heap_process_finalize_list: %p", (void *) heap));
if (heap->pf_prevent_count != 0) {
DUK_DDD(DUK_DDDPRINT("skip finalize_list processing: pf_prevent_count != 0"));
return;
}
/* Heap alloc prevents mark-and-sweep before heap_thread is ready. */
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(heap->heap_thread->valstack != NULL);
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_ASSERT(heap->refzero_list == NULL);
#endif
DUK_ASSERT(heap->pf_prevent_count == 0);
heap->pf_prevent_count = 1;
/* Mark-and-sweep no longer needs to be prevented when running
* finalizers: mark-and-sweep skips any rescue decisions if there
* are any objects in finalize_list when mark-and-sweep is entered.
* This protects finalized objects from incorrect rescue decisions
* caused by finalize_list being a reachability root and only
* partially processed. Freeing decisions are not postponed.
*/
/* When finalizer torture is enabled, make a fake finalizer call with
* maximum side effects regardless of whether finalize_list is empty.
*/
#if defined(DUK_USE_FINALIZER_TORTURE)
duk__run_global_torture_finalizer(heap->heap_thread);
#endif
/* Process finalize_list until it becomes empty. There's currently no
* protection against a finalizer always creating more garbage.
*/
while ((curr = heap->finalize_list) != NULL) {
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_bool_t queue_back;
#endif
DUK_DD(DUK_DDPRINT("processing finalize_list entry: %p -> %!iO", (void *) curr, curr));
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* Only objects have finalizers. */
DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr)); /* All objects on finalize_list will have this flag (except object being finalized right now). */
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr)); /* Queueing code ensures. */
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* ROM objects never get freed (or finalized). */
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(heap->currently_finalizing == NULL);
heap->currently_finalizing = curr;
#endif
/* Clear FINALIZABLE for object being finalized, so that
* duk_push_heapptr() can properly ignore the object.
*/
DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
if (DUK_LIKELY(!heap->pf_skip_finalizers)) {
/* Run the finalizer, duk_heap_run_finalizer() sets
* and checks for FINALIZED to prevent the finalizer
* from executing multiple times per finalization cycle.
* (This safeguard shouldn't be actually needed anymore).
*/
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_bool_t had_zero_refcount;
#endif
/* The object's refcount is >0 throughout so it won't be
* refzero processed prematurely.
*/
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
had_zero_refcount = (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1); /* Preincremented on finalize_list insert. */
#endif
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
duk_heap_run_finalizer(heap, (duk_hobject *) curr); /* must never longjmp */
DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
/* XXX: assert that object is still in finalize_list
* when duk_push_heapptr() allows automatic rescue.
*/
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_DD(DUK_DDPRINT("refcount after finalizer (includes bump): %ld", (long) DUK_HEAPHDR_GET_REFCOUNT(curr)));
if (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1) { /* Only artificial bump in refcount? */
#if defined(DUK_USE_DEBUG)
if (had_zero_refcount) {
DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (refcount queued)"));
} else {
DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (mark-and-sweep queued)"));
}
#endif
queue_back = 0;
} else
#endif
{
#if defined(DUK_USE_REFERENCE_COUNTING)
queue_back = 1;
if (had_zero_refcount) {
/* When finalization is triggered
* by refzero and we queue the object
* back, clear FINALIZED right away
* so that the object can be refinalized
* immediately if necessary.
*/
DUK_HEAPHDR_CLEAR_FINALIZED(curr);
}
#endif
}
} else {
/* Used during heap destruction: don't actually run finalizers
* because we're heading into forced finalization. Instead,
* queue finalizable objects back to the heap_allocated list.
*/
DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
#if defined(DUK_USE_REFERENCE_COUNTING)
queue_back = 1;
#endif
}
/* Dequeue object from finalize_list. Note that 'curr' may no
* longer be finalize_list head because new objects may have
* been queued to the list. As a result we can't optimize for
* the single-linked heap case and must scan the list for
* removal, typically the scan is very short however.
*/
DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap, curr);
/* Queue back to heap_allocated or free immediately. */
#if defined(DUK_USE_REFERENCE_COUNTING)
if (queue_back) {
/* FINALIZED is only cleared if object originally
* queued for finalization by refcounting. For
* mark-and-sweep FINALIZED is left set, so that
* next mark-and-sweep round can make a rescue/free
* decision.
*/
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
DUK_HEAPHDR_PREDEC_REFCOUNT(curr); /* Remove artificial refcount bump. */
DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
} else {
/* No need to remove the refcount bump here. */
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */
DUK_DD(DUK_DDPRINT("refcount finalize after finalizer call: %!O", curr));
duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
duk_free_hobject(heap, (duk_hobject *) curr);
DUK_DD(DUK_DDPRINT("freed hobject after finalization: %p", (void *) curr));
}
#else /* DUK_USE_REFERENCE_COUNTING */
DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
#endif /* DUK_USE_REFERENCE_COUNTING */
#if defined(DUK_USE_DEBUG)
count++;
#endif
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(heap->currently_finalizing != NULL);
heap->currently_finalizing = NULL;
#endif
}
/* finalize_list will always be processed completely. */
DUK_ASSERT(heap->finalize_list == NULL);
#if 0
/* While NORZ macros are used above, this is unnecessary because the
* only pending side effects are now finalizers, and finalize_list is
* empty.
*/
DUK_REFZERO_CHECK_SLOW(heap->heap_thread);
#endif
/* Prevent count may be bumped while finalizers run, but should always
* be reliably unbumped by the time we get here.
*/
DUK_ASSERT(heap->pf_prevent_count == 1);
heap->pf_prevent_count = 0;
#if defined(DUK_USE_DEBUG)
DUK_DD(DUK_DDPRINT("duk_heap_process_finalize_list: %ld finalizers called", (long) count));
#endif
}
/*
* Run an duk_hobject finalizer. Must never throw an uncaught error
* (but may throw caught errors).
*
* There is no return value. Any return value or error thrown by
* the finalizer is ignored (although errors are debug logged).
*
* Notes:
*
* - The finalizer thread 'top' assertions are there because it is
* critical that strict stack policy is observed (i.e. no cruft
* left on the finalizer stack).
*/
DUK_LOCAL duk_ret_t duk__finalize_helper(duk_hthread *thr, void *udata) {
DUK_ASSERT(thr != NULL);
DUK_UNREF(udata);
DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
/* [... obj] */
/* _Finalizer property is read without checking if the value is
* callable or even exists. This is intentional, and handled
* by throwing an error which is caught by the safe call wrapper.
*
* XXX: Finalizer lookup should traverse the prototype chain (to allow
* inherited finalizers) but should not invoke accessors or proxy object
* behavior. At the moment this lookup will invoke proxy behavior, so
* caller must ensure that this function is not called if the target is
* a Proxy.
*/
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
duk_dup_m2(thr);
duk_push_boolean(thr, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
DUK_DDD(DUK_DDDPRINT("calling finalizer"));
duk_call(thr, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
DUK_DDD(DUK_DDDPRINT("finalizer returned successfully"));
return 0;
/* Note: we rely on duk_safe_call() to fix up the stack for the caller,
* so we don't need to pop stuff here. There is no return value;
* caller determines rescued status based on object refcount.
*/
}
DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) {
duk_hthread *thr;
duk_ret_t rc;
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t entry_top;
#endif
DUK_DD(DUK_DDPRINT("running duk_hobject finalizer for object: %p", (void *) obj));
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
thr = heap->heap_thread;
DUK_ASSERT(obj != NULL);
DUK_ASSERT_VALSTACK_SPACE(heap->heap_thread, 1);
#if defined(DUK_USE_ASSERTIONS)
entry_top = duk_get_top(thr);
#endif
/*
* Get and call the finalizer. All of this must be wrapped
* in a protected call, because even getting the finalizer
* may trigger an error (getter may throw one, for instance).
*/
/* ROM objects could inherit a finalizer, but they are never deemed
* unreachable by mark-and-sweep, and their refcount never falls to 0.
*/
DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
/* Duktape 2.1: finalize_list never contains objects with FINALIZED
* set, so no need to check here.
*/
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj));
#if 0
if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
return;
}
#endif
DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
#if defined(DUK_USE_ES6_PROXY)
if (DUK_HOBJECT_IS_PROXY(obj)) {
/* This may happen if duk_set_finalizer() or Duktape.fin() is
* called for a Proxy object. In such cases the fast finalizer
* flag will be set on the Proxy, not the target, and neither
* will be finalized.
*/
DUK_D(DUK_DPRINT("object is a Proxy, skip finalizer call"));
return;
}
#endif /* DUK_USE_ES6_PROXY */
duk_push_hobject(thr, obj); /* this also increases refcount by one */
rc = duk_safe_call(thr, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
DUK_ASSERT_TOP(thr, entry_top + 2); /* duk_safe_call discipline */
if (rc != DUK_EXEC_SUCCESS) {
/* Note: we ask for one return value from duk_safe_call to get this
* error debugging here.
*/
DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
(void *) obj, (duk_tval *) duk_get_tval(thr, -1)));
}
duk_pop_2(thr); /* -> [...] */
DUK_ASSERT_TOP(thr, entry_top);
}
#else /* DUK_USE_FINALIZER_SUPPORT */
/* nothing */
#endif /* DUK_USE_FINALIZER_SUPPORT */

View file

@ -1,116 +0,0 @@
/*
* String hash computation (interning).
*
* String hashing is performance critical because a string hash is computed
* for all new strings which are candidates to be added to the string table.
* However, strings actually added to the string table go through a codepoint
* length calculation which dominates performance because it goes through
* every byte of the input string (but only for strings added).
*
* The string hash algorithm should be fast, but on the other hand provide
* good enough hashes to ensure both string table and object property table
* hash tables work reasonably well (i.e., there aren't too many collisions
* with real world inputs). Unless the hash is cryptographic, it's always
* possible to craft inputs with maximal hash collisions.
*
* NOTE: The hash algorithms must match tools/dukutil.py:duk_heap_hashstring()
* for ROM string support!
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_STRHASH_DENSE)
/* Constants for duk_hashstring(). */
#define DUK__STRHASH_SHORTSTRING 4096L
#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L)
#define DUK__STRHASH_BLOCKSIZE 256L
DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
duk_uint32_t hash;
/* Use Murmurhash2 directly for short strings, and use "block skipping"
* for long strings: hash an initial part and then sample the rest of
* the string with reasonably sized chunks. An initial offset for the
* sampling is computed based on a hash of the initial part of the string;
* this is done to (usually) avoid the case where all long strings have
* certain offset ranges which are never sampled.
*
* Skip should depend on length and bound the total time to roughly
* logarithmic. With current values:
*
* 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
* 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
*
* XXX: It would be better to compute the skip offset more "smoothly"
* instead of having a few boundary values.
*/
/* note: mixing len into seed improves hashing when skipping */
duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len);
if (len <= DUK__STRHASH_SHORTSTRING) {
hash = duk_util_hashbytes(str, len, str_seed);
} else {
duk_size_t off;
duk_size_t skip;
if (len <= DUK__STRHASH_MEDIUMSTRING) {
skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
} else {
skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
}
hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
/* XXX: inefficient loop */
while (off < len) {
duk_size_t left = len - off;
duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
hash ^= duk_util_hashbytes(str + off, now, str_seed);
off += skip;
}
}
#if defined(DUK_USE_STRHASH16)
/* Truncate to 16 bits here, so that a computed hash can be compared
* against a hash stored in a 16-bit field.
*/
hash &= 0x0000ffffUL;
#endif
return hash;
}
#else /* DUK_USE_STRHASH_DENSE */
DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
duk_uint32_t hash;
duk_size_t step;
duk_size_t off;
/* Slightly modified "Bernstein hash" from:
*
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
*
* Modifications: string skipping and reverse direction similar to
* Lua 5.1.5, and different hash initializer.
*
* The reverse direction ensures last byte it always included in the
* hash which is a good default as changing parts of the string are
* more often in the suffix than in the prefix.
*/
hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */
step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
for (off = len; off >= step; off -= step) {
DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */
hash = (hash * 33) + str[off - 1];
}
#if defined(DUK_USE_STRHASH16)
/* Truncate to 16 bits here, so that a computed hash can be compared
* against a hash stored in a 16-bit field.
*/
hash &= 0x0000ffffUL;
#endif
return hash;
}
#endif /* DUK_USE_STRHASH_DENSE */

File diff suppressed because it is too large Load diff

View file

@ -1,412 +0,0 @@
/*
* Memory allocation handling.
*/
#include "third_party/duktape/duk_internal.h"
/*
* Allocate memory with garbage collection.
*/
/* Slow path: voluntary GC triggered, first alloc attempt failed, or zero size. */
DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_alloc_slowpath(duk_heap *heap, duk_size_t size) {
void *res;
duk_small_int_t i;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->alloc_func != NULL);
DUK_ASSERT_DISABLE(size >= 0);
if (size == 0) {
DUK_D(DUK_DPRINT("zero size alloc in slow path, return NULL"));
return NULL;
}
DUK_D(DUK_DPRINT("first alloc attempt failed or voluntary GC limit reached, attempt to gc and retry"));
#if 0
/*
* If GC is already running there is no point in attempting a GC
* because it will be skipped. This could be checked for explicitly,
* but it isn't actually needed: the loop below will eventually
* fail resulting in a NULL.
*/
if (heap->ms_prevent_count != 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
return NULL;
}
#endif
/*
* Retry with several GC attempts. Initial attempts are made without
* emergency mode; later attempts use emergency mode which minimizes
* memory allocations forcibly.
*/
for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
duk_small_uint_t flags;
flags = 0;
if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
flags |= DUK_MS_FLAG_EMERGENCY;
}
duk_heap_mark_and_sweep(heap, flags);
DUK_ASSERT(size > 0);
res = heap->alloc_func(heap->heap_udata, size);
if (res != NULL) {
DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld",
(long) (i + 1), (long) size));
return res;
}
}
DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
return NULL;
}
DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
void *res;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->alloc_func != NULL);
DUK_ASSERT_DISABLE(size >= 0);
#if defined(DUK_USE_VOLUNTARY_GC)
/* Voluntary periodic GC (if enabled). */
if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
goto slowpath;
}
#endif
#if defined(DUK_USE_GC_TORTURE)
/* Simulate alloc failure on every alloc, except when mark-and-sweep
* is running.
*/
if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
res = NULL;
DUK_UNREF(res);
goto slowpath;
}
#endif
/* Zero-size allocation should happen very rarely (if at all), so
* don't check zero size on NULL; handle it in the slow path
* instead. This reduces size of inlined code.
*/
res = heap->alloc_func(heap->heap_udata, size);
if (DUK_LIKELY(res != NULL)) {
return res;
}
slowpath:
if (size == 0) {
DUK_D(DUK_DPRINT("first alloc attempt returned NULL for zero size alloc, use slow path to deal with it"));
} else {
DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
}
return duk__heap_mem_alloc_slowpath(heap, size);
}
DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
void *res;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->alloc_func != NULL);
DUK_ASSERT_DISABLE(size >= 0);
res = DUK_ALLOC(heap, size);
if (DUK_LIKELY(res != NULL)) {
duk_memzero(res, size);
}
return res;
}
DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) {
void *res;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(thr->heap->alloc_func != NULL);
res = duk_heap_mem_alloc(thr->heap, size);
if (DUK_LIKELY(res != NULL)) {
return res;
} else if (size == 0) {
DUK_ASSERT(res == NULL);
return res;
}
DUK_ERROR_ALLOC_FAILED(thr);
DUK_WO_NORETURN(return NULL;);
}
DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) {
void *res;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(thr->heap->alloc_func != NULL);
res = duk_heap_mem_alloc(thr->heap, size);
if (DUK_LIKELY(res != NULL)) {
duk_memzero(res, size);
return res;
} else if (size == 0) {
DUK_ASSERT(res == NULL);
return res;
}
DUK_ERROR_ALLOC_FAILED(thr);
DUK_WO_NORETURN(return NULL;);
}
/*
* Reallocate memory with garbage collection.
*/
/* Slow path: voluntary GC triggered, first realloc attempt failed, or zero size. */
DUK_LOCAL DUK_NOINLINE_PERF DUK_COLD void *duk__heap_mem_realloc_slowpath(duk_heap *heap, void *ptr, duk_size_t newsize) {
void *res;
duk_small_int_t i;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->realloc_func != NULL);
/* ptr may be NULL */
DUK_ASSERT_DISABLE(newsize >= 0);
/* Newsize was 0 and realloc() returned NULL, this has the semantics
* of free(oldptr), i.e. memory was successfully freed.
*/
if (newsize == 0) {
DUK_D(DUK_DPRINT("zero size realloc in slow path, return NULL"));
return NULL;
}
DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
#if 0
/*
* Avoid a GC if GC is already running. See duk_heap_mem_alloc().
*/
if (heap->ms_prevent_count != 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
return NULL;
}
#endif
/*
* Retry with several GC attempts. Initial attempts are made without
* emergency mode; later attempts use emergency mode which minimizes
* memory allocations forcibly.
*/
for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
duk_small_uint_t flags;
flags = 0;
if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
flags |= DUK_MS_FLAG_EMERGENCY;
}
duk_heap_mark_and_sweep(heap, flags);
DUK_ASSERT(newsize > 0);
res = heap->realloc_func(heap->heap_udata, ptr, newsize);
if (res || newsize == 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld",
(long) (i + 1), (long) newsize));
return res;
}
}
DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
return NULL;
}
DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
void *res;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->realloc_func != NULL);
/* ptr may be NULL */
DUK_ASSERT_DISABLE(newsize >= 0);
#if defined(DUK_USE_VOLUNTARY_GC)
/* Voluntary periodic GC (if enabled). */
if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
goto slowpath;
}
#endif
#if defined(DUK_USE_GC_TORTURE)
/* Simulate alloc failure on every realloc, except when mark-and-sweep
* is running.
*/
if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
res = NULL;
DUK_UNREF(res);
goto slowpath;
}
#endif
res = heap->realloc_func(heap->heap_udata, ptr, newsize);
if (DUK_LIKELY(res != NULL)) {
return res;
}
slowpath:
if (newsize == 0) {
DUK_D(DUK_DPRINT("first realloc attempt returned NULL for zero size realloc, use slow path to deal with it"));
} else {
DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
}
return duk__heap_mem_realloc_slowpath(heap, ptr, newsize);
}
/*
* Reallocate memory with garbage collection, using a callback to provide
* the current allocated pointer. This variant is used when a mark-and-sweep
* (e.g. finalizers) might change the original pointer.
*/
/* Slow path: voluntary GC triggered, first realloc attempt failed, or zero size. */
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) {
void *res;
duk_small_int_t i;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->realloc_func != NULL);
DUK_ASSERT_DISABLE(newsize >= 0);
if (newsize == 0) {
DUK_D(DUK_DPRINT("zero size indirect realloc in slow path, return NULL"));
return NULL;
}
DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
#if 0
/*
* Avoid a GC if GC is already running. See duk_heap_mem_alloc().
*/
if (heap->ms_prevent_count != 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
return NULL;
}
#endif
/*
* Retry with several GC attempts. Initial attempts are made without
* emergency mode; later attempts use emergency mode which minimizes
* memory allocations forcibly.
*/
for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
duk_small_uint_t flags;
#if defined(DUK_USE_DEBUG)
void *ptr_pre;
void *ptr_post;
#endif
#if defined(DUK_USE_DEBUG)
ptr_pre = cb(heap, ud);
#endif
flags = 0;
if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
flags |= DUK_MS_FLAG_EMERGENCY;
}
duk_heap_mark_and_sweep(heap, flags);
#if defined(DUK_USE_DEBUG)
ptr_post = cb(heap, ud);
if (ptr_pre != ptr_post) {
DUK_DD(DUK_DDPRINT("realloc base pointer changed by mark-and-sweep: %p -> %p",
(void *) ptr_pre, (void *) ptr_post));
}
#endif
/* Note: key issue here is to re-lookup the base pointer on every attempt.
* The pointer being reallocated may change after every mark-and-sweep.
*/
DUK_ASSERT(newsize > 0);
res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
if (res || newsize == 0) {
DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld",
(long) (i + 1), (long) newsize));
return res;
}
}
DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
return NULL;
}
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) {
void *res;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->realloc_func != NULL);
DUK_ASSERT_DISABLE(newsize >= 0);
#if defined(DUK_USE_VOLUNTARY_GC)
/* Voluntary periodic GC (if enabled). */
if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
goto slowpath;
}
#endif
#if defined(DUK_USE_GC_TORTURE)
/* Simulate alloc failure on every realloc, except when mark-and-sweep
* is running.
*/
if (heap->ms_prevent_count == 0) {
DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
res = NULL;
DUK_UNREF(res);
goto slowpath;
}
#endif
res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
if (DUK_LIKELY(res != NULL)) {
return res;
}
slowpath:
if (newsize == 0) {
DUK_D(DUK_DPRINT("first indirect realloc attempt returned NULL for zero size realloc, use slow path to deal with it"));
} else {
DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
}
return duk__heap_mem_realloc_indirect_slowpath(heap, cb, ud, newsize);
}
/*
* Free memory
*/
DUK_INTERNAL DUK_INLINE_PERF DUK_HOT void duk_heap_mem_free(duk_heap *heap, void *ptr) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->free_func != NULL);
/* ptr may be NULL */
/* Must behave like a no-op with NULL and any pointer returned from
* malloc/realloc with zero size.
*/
heap->free_func(heap->heap_udata, ptr);
/* Never perform a GC (even voluntary) in a memory free, otherwise
* all call sites doing frees would need to deal with the side effects.
* No need to update voluntary GC counter either.
*/
}

View file

@ -1,187 +0,0 @@
/*
* Support functions for duk_heap.
*/
#include "third_party/duktape/duk_internal.h"
DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
duk_heaphdr *root;
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
root = heap->heap_allocated;
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
if (root != NULL) {
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
DUK_HEAPHDR_SET_PREV(heap, root, hdr);
}
DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
#endif
DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
DUK_HEAPHDR_ASSERT_LINKS(heap, hdr);
DUK_HEAPHDR_ASSERT_LINKS(heap, root);
heap->heap_allocated = hdr;
}
#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_INTERNAL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
duk_heaphdr *prev;
duk_heaphdr *next;
/* Strings are in string table. */
DUK_ASSERT(hdr != NULL);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
/* Target 'hdr' must be in heap_allocated (not e.g. finalize_list).
* If not, heap lists will become corrupted so assert early for it.
*/
#if defined(DUK_USE_ASSERTIONS)
{
duk_heaphdr *tmp;
for (tmp = heap->heap_allocated; tmp != NULL; tmp = DUK_HEAPHDR_GET_NEXT(heap, tmp)) {
if (tmp == hdr) {
break;
}
}
DUK_ASSERT(tmp == hdr);
}
#endif
/* Read/write only once to minimize pointer compression calls. */
prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
if (prev != NULL) {
DUK_ASSERT(heap->heap_allocated != hdr);
DUK_HEAPHDR_SET_NEXT(heap, prev, next);
} else {
DUK_ASSERT(heap->heap_allocated == hdr);
heap->heap_allocated = next;
}
if (next != NULL) {
DUK_HEAPHDR_SET_PREV(heap, next, prev);
} else {
;
}
}
#endif /* DUK_USE_REFERENCE_COUNTING */
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
duk_heaphdr *root;
root = heap->finalize_list;
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
if (root != NULL) {
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
DUK_HEAPHDR_SET_PREV(heap, root, hdr);
}
#endif
DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
DUK_HEAPHDR_ASSERT_LINKS(heap, hdr);
DUK_HEAPHDR_ASSERT_LINKS(heap, root);
heap->finalize_list = hdr;
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
duk_heaphdr *next;
duk_heaphdr *prev;
next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
if (next != NULL) {
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, next) == hdr);
DUK_HEAPHDR_SET_PREV(heap, next, prev);
}
if (prev == NULL) {
DUK_ASSERT(hdr == heap->finalize_list);
heap->finalize_list = next;
} else {
DUK_ASSERT(hdr != heap->finalize_list);
DUK_HEAPHDR_SET_NEXT(heap, prev, next);
}
#else
duk_heaphdr *next;
duk_heaphdr *curr;
/* Random removal is expensive: we need to locate the previous element
* because we don't have a 'prev' pointer.
*/
curr = heap->finalize_list;
if (curr == hdr) {
heap->finalize_list = DUK_HEAPHDR_GET_NEXT(heap, curr);
} else {
DUK_ASSERT(hdr != heap->finalize_list);
for (;;) {
DUK_ASSERT(curr != NULL); /* Caller responsibility. */
next = DUK_HEAPHDR_GET_NEXT(heap, curr);
if (next == hdr) {
next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
DUK_HEAPHDR_SET_NEXT(heap, curr, next);
break;
}
}
}
#endif
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr) {
duk_heaphdr *curr;
DUK_ASSERT(heap != NULL);
for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
if (curr == ptr) {
return 1;
}
}
return 0;
}
#endif /* DUK_USE_ASSERTIONS */
#if defined(DUK_USE_INTERRUPT_COUNTER)
DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
duk_hthread *curr_thr;
DUK_ASSERT(heap != NULL);
if (new_thr != NULL) {
curr_thr = heap->curr_thread;
if (curr_thr == NULL) {
/* For initial entry use default value; zero forces an
* interrupt before executing the first insturction.
*/
DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter"));
new_thr->interrupt_counter = 0;
new_thr->interrupt_init = 0;
} else {
/* Copy interrupt counter/init value state to new thread (if any).
* It's OK for new_thr to be the same as curr_thr.
*/
#if defined(DUK_USE_DEBUG)
if (new_thr != curr_thr) {
DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter"));
}
#endif
new_thr->interrupt_counter = curr_thr->interrupt_counter;
new_thr->interrupt_init = curr_thr->interrupt_init;
}
} else {
DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes"));
}
heap->curr_thread = new_thr; /* may be NULL */
}
#endif /* DUK_USE_INTERRUPT_COUNTER */
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL void duk_heap_assert_valid(duk_heap *heap) {
DUK_ASSERT(heap != NULL);
}
#endif

View file

@ -1,833 +0,0 @@
/*
* Reference counting implementation.
*
* INCREF/DECREF, finalization and freeing of objects whose refcount reaches
* zero (refzero). These operations are very performance sensitive, so
* various small tricks are used in an attempt to maximize speed.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_REFERENCE_COUNTING)
#if !defined(DUK_USE_DOUBLE_LINKED_HEAP)
#error internal error, reference counting requires a double linked heap
#endif
/*
* Heap object refcount finalization.
*
* When an object is about to be freed, all other objects it refers to must
* be decref'd. Refcount finalization does NOT free the object or its inner
* allocations (mark-and-sweep shares these helpers), it just manipulates
* the refcounts.
*
* Note that any of the DECREFs may cause a refcount to drop to zero. If so,
* the object won't be refzero processed inline, but will just be queued to
* refzero_list and processed by an earlier caller working on refzero_list,
* eliminating C recursion from even long refzero cascades. If refzero
* finalization is triggered by mark-and-sweep, refzero conditions are ignored
* (objects are not even queued to refzero_list) because mark-and-sweep deals
* with them; refcounts are still updated so that they remain in sync with
* actual references.
*/
DUK_LOCAL void duk__decref_tvals_norz(duk_hthread *thr, duk_tval *tv, duk_idx_t count) {
DUK_ASSERT(count == 0 || tv != NULL);
while (count-- > 0) {
DUK_TVAL_DECREF_NORZ(thr, tv);
tv++;
}
}
DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h) {
duk_hthread *thr;
duk_uint_fast32_t i;
duk_uint_fast32_t n;
duk_propvalue *p_val;
duk_tval *p_tv;
duk_hstring **p_key;
duk_uint8_t *p_flag;
duk_hobject *h_proto;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(h);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
thr = heap->heap_thread;
DUK_ASSERT(thr != NULL);
p_key = DUK_HOBJECT_E_GET_KEY_BASE(heap, h);
p_val = DUK_HOBJECT_E_GET_VALUE_BASE(heap, h);
p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(heap, h);
n = DUK_HOBJECT_GET_ENEXT(h);
while (n-- > 0) {
duk_hstring *key;
key = p_key[n];
if (DUK_UNLIKELY(key == NULL)) {
continue;
}
DUK_HSTRING_DECREF_NORZ(thr, key);
if (DUK_UNLIKELY(p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR)) {
duk_hobject *h_getset;
h_getset = p_val[n].a.get;
DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
h_getset = p_val[n].a.set;
DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
} else {
duk_tval *tv_val;
tv_val = &p_val[n].v;
DUK_TVAL_DECREF_NORZ(thr, tv_val);
}
}
p_tv = DUK_HOBJECT_A_GET_BASE(heap, h);
n = DUK_HOBJECT_GET_ASIZE(h);
while (n-- > 0) {
duk_tval *tv_val;
tv_val = p_tv + n;
DUK_TVAL_DECREF_NORZ(thr, tv_val);
}
/* Hash part is a 'weak reference' and doesn't contribute to refcounts. */
h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(heap, h);
DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto));
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto);
/* XXX: Object subclass tests are quite awkward at present, ideally
* we should be able to switch-case here with a dense index (subtype
* number or something). For now, fast path plain objects and arrays
* and bit test the rest individually.
*/
if (DUK_HOBJECT_HAS_FASTREFS(h)) {
/* Plain object or array, nothing more to do. While a
* duk_harray has additional fields, none of them need
* DECREF updates.
*/
DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h));
return;
}
DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
/* Slow path: special object, start bit checks from most likely. */
/* XXX: reorg, more common first */
if (DUK_HOBJECT_IS_COMPFUNC(h)) {
duk_hcompfunc *f = (duk_hcompfunc *) h;
duk_tval *tv, *tv_end;
duk_hobject **funcs, **funcs_end;
DUK_HCOMPFUNC_ASSERT_VALID(f);
if (DUK_LIKELY(DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL)) {
tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
while (tv < tv_end) {
DUK_TVAL_DECREF_NORZ(thr, tv);
tv++;
}
funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
while (funcs < funcs_end) {
duk_hobject *h_func;
h_func = *funcs;
DUK_ASSERT(h_func != NULL);
DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_func));
DUK_HCOMPFUNC_DECREF_NORZ(thr, (duk_hcompfunc *) h_func);
funcs++;
}
} else {
/* May happen in some out-of-memory corner cases. */
DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref"));
}
DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(heap, f));
} else if (DUK_HOBJECT_IS_DECENV(h)) {
duk_hdecenv *e = (duk_hdecenv *) h;
DUK_HDECENV_ASSERT_VALID(e);
DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, e->thread);
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, e->varmap);
} else if (DUK_HOBJECT_IS_OBJENV(h)) {
duk_hobjenv *e = (duk_hobjenv *) h;
DUK_HOBJENV_ASSERT_VALID(e);
DUK_ASSERT(e->target != NULL); /* Required for object environments. */
DUK_HOBJECT_DECREF_NORZ(thr, e->target);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
} else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
duk_hbufobj *b = (duk_hbufobj *) h;
DUK_HBUFOBJ_ASSERT_VALID(b);
DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf);
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop);
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
} else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
DUK_HBOUNDFUNC_ASSERT_VALID(f);
DUK_TVAL_DECREF_NORZ(thr, &f->target);
DUK_TVAL_DECREF_NORZ(thr, &f->this_binding);
duk__decref_tvals_norz(thr, f->args, f->nargs);
#if defined(DUK_USE_ES6_PROXY)
} else if (DUK_HOBJECT_IS_PROXY(h)) {
duk_hproxy *p = (duk_hproxy *) h;
DUK_HPROXY_ASSERT_VALID(p);
DUK_HOBJECT_DECREF_NORZ(thr, p->target);
DUK_HOBJECT_DECREF_NORZ(thr, p->handler);
#endif /* DUK_USE_ES6_PROXY */
} else if (DUK_HOBJECT_IS_THREAD(h)) {
duk_hthread *t = (duk_hthread *) h;
duk_activation *act;
duk_tval *tv;
DUK_HTHREAD_ASSERT_VALID(t);
tv = t->valstack;
while (tv < t->valstack_top) {
DUK_TVAL_DECREF_NORZ(thr, tv);
tv++;
}
for (act = t->callstack_curr; act != NULL; act = act->parent) {
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act));
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env);
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env);
#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller);
#endif
#if 0 /* nothing now */
for (cat = act->cat; cat != NULL; cat = cat->parent) {
}
#endif
}
for (i = 0; i < DUK_NUM_BUILTINS; i++) {
DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]);
}
DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, (duk_hthread *) t->resumer);
} else {
/* We may come here if the object should have a FASTREFS flag
* but it's missing for some reason. Assert for never getting
* here; however, other than performance, this is harmless.
*/
DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h));
DUK_ASSERT(0);
}
}
DUK_INTERNAL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(hdr != NULL);
if (DUK_HEAPHDR_IS_OBJECT(hdr)) {
duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) hdr);
}
/* DUK_HTYPE_BUFFER: nothing to finalize */
/* DUK_HTYPE_STRING: nothing to finalize */
}
/*
* Refzero processing for duk_hobject: queue a refzero'ed object to either
* finalize_list or refzero_list and process the relevent list(s) if
* necessary.
*
* Refzero_list is single linked, with only 'prev' pointers set and valid.
* All 'next' pointers are intentionally left as garbage. This doesn't
* matter because refzero_list is processed to completion before any other
* code (like mark-and-sweep) might walk the list.
*
* In more detail:
*
* - On first insert refzero_list is NULL and the new object becomes the
* first and only element on the list; duk__refcount_free_pending() is
* called and it starts processing the list from the initial element,
* i.e. the list tail.
*
* - As each object is refcount finalized, new objects may be queued to
* refzero_list head. Their 'next' pointers are left as garbage, but
* 'prev' points are set correctly, with the element at refzero_list
* having a NULL 'prev' pointer. The fact that refzero_list is non-NULL
* is used to reject (1) recursive duk__refcount_free_pending() and
* (2) finalize_list processing calls.
*
* - When we're done with the current object, read its 'prev' pointer and
* free the object. If 'prev' is NULL, we've reached head of list and are
* done: set refzero_list to NULL and process pending finalizers. Otherwise
* continue processing the list.
*
* A refzero cascade is free of side effects because it only involves
* queueing more objects and freeing memory; finalizer execution is blocked
* in the code path queueing objects to finalize_list. As a result the
* initial refzero call (which triggers duk__refcount_free_pending()) must
* check finalize_list so that finalizers are executed snappily.
*
* If finalize_list processing starts first, refzero may occur while we're
* processing finalizers. That's fine: that particular refzero cascade is
* handled to completion without side effects. Once the cascade is complete,
* we'll run pending finalizers but notice that we're already doing that and
* return.
*
* This could be expanded to allow incremental freeing: just bail out
* early and resume at a future alloc/decref/refzero. However, if that
* were done, the list structure would need to be kept consistent at all
* times, mark-and-sweep would need to handle refzero_list, etc.
*/
DUK_LOCAL void duk__refcount_free_pending(duk_heap *heap) {
duk_heaphdr *curr;
#if defined(DUK_USE_DEBUG)
duk_int_t count = 0;
#endif
DUK_ASSERT(heap != NULL);
curr = heap->refzero_list;
DUK_ASSERT(curr != NULL);
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, curr) == NULL); /* We're called on initial insert only. */
/* curr->next is GARBAGE. */
do {
duk_heaphdr *prev;
DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr));
#if defined(DUK_USE_DEBUG)
count++;
#endif
DUK_ASSERT(curr != NULL);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* currently, always the case */
/* FINALIZED may be set; don't care about flags here. */
/* Refcount finalize 'curr'. Refzero_list must be non-NULL
* here to prevent recursive entry to duk__refcount_free_pending().
*/
DUK_ASSERT(heap->refzero_list != NULL);
duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
prev = DUK_HEAPHDR_GET_PREV(heap, curr);
DUK_ASSERT((prev == NULL && heap->refzero_list == curr) || \
(prev != NULL && heap->refzero_list != curr));
/* prev->next is intentionally not updated and is garbage. */
duk_free_hobject(heap, (duk_hobject *) curr); /* Invalidates 'curr'. */
curr = prev;
} while (curr != NULL);
heap->refzero_list = NULL;
DUK_DD(DUK_DDPRINT("refzero processed %ld objects", (long) count));
}
DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hobject(duk_heap *heap, duk_hobject *obj, duk_bool_t skip_free_pending) {
duk_heaphdr *hdr;
duk_heaphdr *root;
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(obj != NULL);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) obj) == DUK_HTYPE_OBJECT);
hdr = (duk_heaphdr *) obj;
/* Refzero'd objects must be in heap_allocated. They can't be in
* finalize_list because all objects on finalize_list have an
* artificial +1 refcount bump.
*/
#if defined(DUK_USE_ASSERTIONS)
DUK_ASSERT(duk_heap_in_heap_allocated(heap, (duk_heaphdr *) obj));
#endif
DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, hdr);
#if defined(DUK_USE_FINALIZER_SUPPORT)
/* This finalizer check MUST BE side effect free. It should also be
* as fast as possible because it's applied to every object freed.
*/
if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr) != 0U)) {
/* Special case: FINALIZED may be set if mark-and-sweep queued
* object for finalization, the finalizer was executed (and
* FINALIZED set), mark-and-sweep hasn't yet processed the
* object again, but its refcount drops to zero. Free without
* running the finalizer again.
*/
if (DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
DUK_D(DUK_DPRINT("refzero'd object has finalizer and FINALIZED is set -> free"));
} else {
/* Set FINALIZABLE flag so that all objects on finalize_list
* will have it set and are thus detectable based on the
* flag alone.
*/
DUK_HEAPHDR_SET_FINALIZABLE(hdr);
DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
#if defined(DUK_USE_REFERENCE_COUNTING)
/* Bump refcount on finalize_list insert so that a
* refzero can never occur when an object is waiting
* for its finalizer call. Refzero might otherwise
* now happen because we allow duk_push_heapptr() for
* objects pending finalization.
*/
DUK_HEAPHDR_PREINC_REFCOUNT(hdr);
#endif
DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, hdr);
/* Process finalizers unless skipping is explicitly
* requested (NORZ) or refzero_list is being processed
* (avoids side effects during a refzero cascade).
* If refzero_list is processed, the initial refzero
* call will run pending finalizers when refzero_list
* is done.
*/
if (!skip_free_pending && heap->refzero_list == NULL) {
duk_heap_process_finalize_list(heap);
}
return;
}
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/* No need to finalize, free object via refzero_list. */
root = heap->refzero_list;
DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
/* 'next' is left as GARBAGE. */
heap->refzero_list = hdr;
if (root == NULL) {
/* Object is now queued. Refzero_list was NULL so
* no-one is currently processing it; do it here.
* With refzero processing just doing a cascade of
* free calls, we can process it directly even when
* NORZ macros are used: there are no side effects.
*/
duk__refcount_free_pending(heap);
DUK_ASSERT(heap->refzero_list == NULL);
/* Process finalizers only after the entire cascade
* is finished. In most cases there's nothing to
* finalize, so fast path check to avoid a call.
*/
#if defined(DUK_USE_FINALIZER_SUPPORT)
if (!skip_free_pending && DUK_UNLIKELY(heap->finalize_list != NULL)) {
duk_heap_process_finalize_list(heap);
}
#endif
} else {
DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
DUK_HEAPHDR_SET_PREV(heap, root, hdr);
/* Object is now queued. Because refzero_list was
* non-NULL, it's already being processed by someone
* in the C call stack, so we're done.
*/
}
}
#if defined(DUK_USE_FINALIZER_SUPPORT)
DUK_INTERNAL DUK_ALWAYS_INLINE void duk_refzero_check_fast(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */
if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
duk_heap_process_finalize_list(thr->heap);
}
}
DUK_INTERNAL void duk_refzero_check_slow(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
DUK_ASSERT(thr->heap->refzero_list == NULL); /* Processed to completion inline. */
if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
duk_heap_process_finalize_list(thr->heap);
}
}
#endif /* DUK_USE_FINALIZER_SUPPORT */
/*
* Refzero processing for duk_hstring.
*/
DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hstring(duk_heap *heap, duk_hstring *str) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(str != NULL);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) str) == DUK_HTYPE_STRING);
duk_heap_strcache_string_remove(heap, str);
duk_heap_strtable_unlink(heap, str);
duk_free_hstring(heap, str);
}
/*
* Refzero processing for duk_hbuffer.
*/
DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hbuffer(duk_heap *heap, duk_hbuffer *buf) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(heap->heap_thread != NULL);
DUK_ASSERT(buf != NULL);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) buf) == DUK_HTYPE_BUFFER);
DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, (duk_heaphdr *) buf);
duk_free_hbuffer(heap, buf);
}
/*
* Incref and decref functions.
*
* Decref may trigger immediate refzero handling, which may free and finalize
* an arbitrary number of objects (a "DECREF cascade").
*
* Refzero handling is skipped entirely if (1) mark-and-sweep is running or
* (2) execution is paused in the debugger. The objects are left in the heap,
* and will be freed by mark-and-sweep or eventual heap destruction.
*
* This is necessary during mark-and-sweep because refcounts are also updated
* during the sweep phase (otherwise objects referenced by a swept object
* would have incorrect refcounts) which then calls here. This could be
* avoided by using separate decref macros in mark-and-sweep; however,
* mark-and-sweep also calls finalizers which would use the ordinary decref
* macros anyway.
*
* We can't process refzeros (= free objects) when the debugger is running
* as the debugger might make an object unreachable but still continue
* inspecting it (or even cause it to be pushed back). So we must rely on
* mark-and-sweep to collect them.
*
* The DUK__RZ_SUPPRESS_CHECK() condition is also used in heap destruction
* when running finalizers for remaining objects: the flag prevents objects
* from being moved around in heap linked lists while that's being done.
*
* The suppress condition is important to performance.
*/
#define DUK__RZ_SUPPRESS_ASSERT1() do { \
DUK_ASSERT(thr != NULL); \
DUK_ASSERT(thr->heap != NULL); \
/* When mark-and-sweep runs, heap_thread must exist. */ \
DUK_ASSERT(thr->heap->ms_running == 0 || thr->heap->heap_thread != NULL); \
/* In normal operation finalizers are executed with ms_running == 0 \
* so we should never see ms_running == 1 and thr != heap_thread. \
* In heap destruction finalizers are executed with ms_running != 0 \
* to e.g. prevent refzero; a special value ms_running == 2 is used \
* in that case so it can be distinguished from the normal runtime \
* case, and allows a stronger assertion here (GH-2030). \
*/ \
DUK_ASSERT(!(thr->heap->ms_running == 1 && thr != thr->heap->heap_thread)); \
/* We may be called when the heap is initializing and we process \
* refzeros normally, but mark-and-sweep and finalizers are prevented \
* if that's the case. \
*/ \
DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->ms_prevent_count > 0); \
DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->pf_prevent_count > 0); \
} while (0)
#if defined(DUK_USE_DEBUGGER_SUPPORT)
#define DUK__RZ_SUPPRESS_ASSERT2() do { \
/* When debugger is paused, ms_running is set. */ \
DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->ms_running != 0); \
} while (0)
#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0)
#else
#define DUK__RZ_SUPPRESS_ASSERT2() do { } while (0)
#define DUK__RZ_SUPPRESS_COND() (heap->ms_running != 0)
#endif /* DUK_USE_DEBUGGER_SUPPORT */
#define DUK__RZ_SUPPRESS_CHECK() do { \
DUK__RZ_SUPPRESS_ASSERT1(); \
DUK__RZ_SUPPRESS_ASSERT2(); \
if (DUK_UNLIKELY(DUK__RZ_SUPPRESS_COND())) { \
DUK_DDD(DUK_DDDPRINT("refzero handling suppressed (not even queued) when mark-and-sweep running, object: %p", (void *) h)); \
return; \
} \
} while (0)
#define DUK__RZ_STRING() do { \
duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \
} while (0)
#define DUK__RZ_BUFFER() do { \
duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \
} while (0)
#define DUK__RZ_OBJECT() do { \
duk__refcount_refzero_hobject(heap, (duk_hobject *) h, skip_free_pending); \
} while (0)
/* XXX: test the effect of inlining here vs. NOINLINE in refzero helpers */
#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
#define DUK__RZ_INLINE DUK_ALWAYS_INLINE
#else
#define DUK__RZ_INLINE /*nop*/
#endif
DUK_LOCAL DUK__RZ_INLINE void duk__hstring_refzero_helper(duk_hthread *thr, duk_hstring *h) {
duk_heap *heap;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(h != NULL);
heap = thr->heap;
DUK__RZ_SUPPRESS_CHECK();
DUK__RZ_STRING();
}
DUK_LOCAL DUK__RZ_INLINE void duk__hbuffer_refzero_helper(duk_hthread *thr, duk_hbuffer *h) {
duk_heap *heap;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(h != NULL);
heap = thr->heap;
DUK__RZ_SUPPRESS_CHECK();
DUK__RZ_BUFFER();
}
DUK_LOCAL DUK__RZ_INLINE void duk__hobject_refzero_helper(duk_hthread *thr, duk_hobject *h, duk_bool_t skip_free_pending) {
duk_heap *heap;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(h != NULL);
heap = thr->heap;
DUK__RZ_SUPPRESS_CHECK();
DUK__RZ_OBJECT();
}
DUK_LOCAL DUK__RZ_INLINE void duk__heaphdr_refzero_helper(duk_hthread *thr, duk_heaphdr *h, duk_bool_t skip_free_pending) {
duk_heap *heap;
duk_small_uint_t htype;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(h != NULL);
heap = thr->heap;
htype = (duk_small_uint_t) DUK_HEAPHDR_GET_TYPE(h);
DUK_DDD(DUK_DDDPRINT("ms_running=%ld, heap_thread=%p", (long) thr->heap->ms_running, thr->heap->heap_thread));
DUK__RZ_SUPPRESS_CHECK();
switch (htype) {
case DUK_HTYPE_STRING:
/* Strings have no internal references but do have "weak"
* references in the string cache. Also note that strings
* are not on the heap_allocated list like other heap
* elements.
*/
DUK__RZ_STRING();
break;
case DUK_HTYPE_OBJECT:
/* Objects have internal references. Must finalize through
* the "refzero" work list.
*/
DUK__RZ_OBJECT();
break;
default:
/* Buffers have no internal references. However, a dynamic
* buffer has a separate allocation for the buffer. This is
* freed by duk_heap_free_heaphdr_raw().
*/
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_BUFFER);
DUK__RZ_BUFFER();
break;
}
}
DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
duk__heaphdr_refzero_helper(thr, h, 0 /*skip_free_pending*/);
}
DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) {
duk__heaphdr_refzero_helper(thr, h, 1 /*skip_free_pending*/);
}
DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) {
duk__hstring_refzero_helper(thr, h);
}
DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) {
duk__hbuffer_refzero_helper(thr, h);
}
DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h) {
duk__hobject_refzero_helper(thr, h, 0 /*skip_free_pending*/);
}
DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) {
duk__hobject_refzero_helper(thr, h, 1 /*skip_free_pending*/);
}
#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT_DISABLE(h->h_refcount >= 0);
DUK_HEAPHDR_PREINC_REFCOUNT(h);
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) != 0); /* No wrapping. */
}
}
DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
#if 0
if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
return;
}
duk_heaphdr_refzero(thr, h);
#else
duk_heaphdr_decref(thr, h);
#endif
}
}
DUK_INTERNAL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(tv != NULL);
if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
#if 0
if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
return;
}
duk_heaphdr_refzero_norz(thr, h);
#else
duk_heaphdr_decref_norz(thr, h);
#endif
}
}
#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
#define DUK__DECREF_ASSERTS() do { \
DUK_ASSERT(thr != NULL); \
DUK_ASSERT(thr->heap != NULL); \
DUK_ASSERT(h != NULL); \
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((duk_heaphdr *) h)); \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) >= 1); \
} while (0)
#if defined(DUK_USE_ROM_OBJECTS)
#define DUK__INCREF_SHARED() do { \
if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
return; \
} \
DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \
} while (0)
#define DUK__DECREF_SHARED() do { \
if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
return; \
} \
if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
return; \
} \
} while (0)
#else
#define DUK__INCREF_SHARED() do { \
DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0); /* No wrapping. */ \
} while (0)
#define DUK__DECREF_SHARED() do { \
if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
return; \
} \
} while (0)
#endif
#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
/* This will in practice be inlined because it's just an INC instructions
* and a bit test + INC when ROM objects are enabled.
*/
DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
DUK__INCREF_SHARED();
}
DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_heaphdr_refzero(thr, h);
/* Forced mark-and-sweep when GC torture enabled; this could happen
* on any DECREF (but not DECREF_NORZ).
*/
DUK_GC_TORTURE(thr->heap);
}
DUK_INTERNAL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_heaphdr_refzero_norz(thr, h);
}
#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
#if 0 /* Not needed. */
DUK_INTERNAL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_hstring_refzero(thr, h);
}
DUK_INTERNAL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_hstring_refzero_norz(thr, h);
}
DUK_INTERNAL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_hbuffer_refzero(thr, h);
}
DUK_INTERNAL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_hbuffer_refzero_norz(thr, h);
}
DUK_INTERNAL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_hobject_refzero(thr, h);
}
DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) {
DUK__DECREF_ASSERTS();
DUK__DECREF_SHARED();
duk_hobject_refzero_norz(thr, h);
}
#endif
#else /* DUK_USE_REFERENCE_COUNTING */
/* no refcounting */
#endif /* DUK_USE_REFERENCE_COUNTING */

View file

@ -1,309 +0,0 @@
/*
* String cache.
*
* Provides a cache to optimize indexed string lookups. The cache keeps
* track of (byte offset, char offset) states for a fixed number of strings.
* Otherwise we'd need to scan from either end of the string, as we store
* strings in (extended) UTF-8.
*/
#include "third_party/duktape/duk_internal.h"
/*
* Delete references to given hstring from the heap string cache.
*
* String cache references are 'weak': they are not counted towards
* reference counts, nor serve as roots for mark-and-sweep. When an
* object is about to be freed, such references need to be removed.
*/
DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
duk_uint_t i;
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache_entry *c = heap->strcache + i;
if (c->h == h) {
DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
(void *) h, (void *) heap));
c->h = NULL;
/* XXX: the string shouldn't appear twice, but we now loop to the
* end anyway; if fixed, add a looping assertion to ensure there
* is no duplicate.
*/
}
}
}
/*
* String scanning helpers
*
* All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
* considered to contribute a character. This must match how string
* character length is computed.
*/
DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
while (n > 0) {
for (;;) {
p++;
if (p >= q) {
return NULL;
}
if ((*p & 0xc0) != 0x80) {
break;
}
}
n--;
}
return p;
}
DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
while (n > 0) {
for (;;) {
p--;
if (p < q) {
return NULL;
}
if ((*p & 0xc0) != 0x80) {
break;
}
}
n--;
}
return p;
}
/*
* Convert char offset to byte offset
*
* Avoid using the string cache if possible: for ASCII strings byte and
* char offsets are equal and for short strings direct scanning may be
* better than using the string cache (which may evict a more important
* entry).
*
* Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
* Better typing might be to use duk_size_t.
*
* Caller should ensure 'char_offset' is within the string bounds [0,charlen]
* (endpoint is inclusive). If this is not the case, no memory unsafe
* behavior will happen but an error will be thrown.
*/
DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
duk_heap *heap;
duk_strcache_entry *sce;
duk_uint_fast32_t byte_offset;
duk_uint_t i;
duk_bool_t use_cache;
duk_uint_fast32_t dist_start, dist_end, dist_sce;
duk_uint_fast32_t char_length;
const duk_uint8_t *p_start;
const duk_uint8_t *p_end;
const duk_uint8_t *p_found;
/*
* For ASCII strings, the answer is simple.
*/
if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
return char_offset;
}
char_length = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h);
DUK_ASSERT(char_offset <= char_length);
if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
/* Must recheck because the 'is ascii' flag may be set
* lazily. Alternatively, we could just compare charlen
* to bytelen.
*/
return char_offset;
}
/*
* For non-ASCII strings, we need to scan forwards or backwards
* from some starting point. The starting point may be the start
* or end of the string, or some cached midpoint in the string
* cache.
*
* For "short" strings we simply scan without checking or updating
* the cache. For longer strings we check and update the cache as
* necessary, inserting a new cache entry if none exists.
*/
DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
(void *) h, (long) char_offset,
(long) DUK_HSTRING_GET_CHARLEN(h),
(long) DUK_HSTRING_GET_BYTELEN(h)));
heap = thr->heap;
sce = NULL;
use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
if (use_cache) {
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache_entry *c = heap->strcache + i;
DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
(long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
}
#endif
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache_entry *c = heap->strcache + i;
if (c->h == h) {
sce = c;
break;
}
}
}
/*
* Scan from shortest distance:
* - start of string
* - end of string
* - cache entry (if exists)
*/
DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
dist_start = char_offset;
dist_end = char_length - char_offset;
dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
p_found = NULL;
if (sce) {
if (char_offset >= sce->cidx) {
dist_sce = char_offset - sce->cidx;
if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
"dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
"scan forwards from sce",
(long) use_cache, (void *) (sce ? sce->h : NULL),
(sce ? (long) sce->cidx : (long) -1),
(sce ? (long) sce->bidx : (long) -1),
(long) dist_start, (long) dist_end, (long) dist_sce));
p_found = duk__scan_forwards(p_start + sce->bidx,
p_end,
dist_sce);
goto scan_done;
}
} else {
dist_sce = sce->cidx - char_offset;
if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
"dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
"scan backwards from sce",
(long) use_cache, (void *) (sce ? sce->h : NULL),
(sce ? (long) sce->cidx : (long) -1),
(sce ? (long) sce->bidx : (long) -1),
(long) dist_start, (long) dist_end, (long) dist_sce));
p_found = duk__scan_backwards(p_start + sce->bidx,
p_start,
dist_sce);
goto scan_done;
}
}
}
/* no sce, or sce scan not best */
if (dist_start <= dist_end) {
DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
"dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
"scan forwards from string start",
(long) use_cache, (void *) (sce ? sce->h : NULL),
(sce ? (long) sce->cidx : (long) -1),
(sce ? (long) sce->bidx : (long) -1),
(long) dist_start, (long) dist_end, (long) dist_sce));
p_found = duk__scan_forwards(p_start,
p_end,
dist_start);
} else {
DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
"dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
"scan backwards from string end",
(long) use_cache, (void *) (sce ? sce->h : NULL),
(sce ? (long) sce->cidx : (long) -1),
(sce ? (long) sce->bidx : (long) -1),
(long) dist_start, (long) dist_end, (long) dist_sce));
p_found = duk__scan_backwards(p_end,
p_start,
dist_end);
}
scan_done:
if (DUK_UNLIKELY(p_found == NULL)) {
/* Scan error: this shouldn't normally happen; it could happen if
* string is not valid UTF-8 data, and clen/blen are not consistent
* with the scanning algorithm.
*/
goto scan_error;
}
DUK_ASSERT(p_found >= p_start);
DUK_ASSERT(p_found <= p_end); /* may be equal */
byte_offset = (duk_uint32_t) (p_found - p_start);
DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
(void *) h, (long) char_offset, (long) byte_offset));
/*
* Update cache entry (allocating if necessary), and move the
* cache entry to the first place (in an "LRU" policy).
*/
if (use_cache) {
/* update entry, allocating if necessary */
if (!sce) {
sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */
sce->h = h;
}
DUK_ASSERT(sce != NULL);
sce->bidx = (duk_uint32_t) (p_found - p_start);
sce->cidx = (duk_uint32_t) char_offset;
/* LRU: move our entry to first */
if (sce > &heap->strcache[0]) {
/*
* A C
* B A
* C <- sce ==> B
* D D
*/
duk_strcache_entry tmp;
tmp = *sce;
duk_memmove((void *) (&heap->strcache[1]),
(const void *) (&heap->strcache[0]),
(size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
heap->strcache[0] = tmp;
/* 'sce' points to the wrong entry here, but is no longer used */
}
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache_entry *c = heap->strcache + i;
DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
(long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
}
#endif
}
return byte_offset;
scan_error:
DUK_ERROR_INTERNAL(thr);
DUK_WO_NORETURN(return 0;);
}

File diff suppressed because it is too large Load diff

View file

@ -1,297 +0,0 @@
/*
* Heap header definition and assorted macros, including ref counting.
* Access all fields through the accessor macros.
*/
#if !defined(DUK_HEAPHDR_H_INCLUDED)
#define DUK_HEAPHDR_H_INCLUDED
/*
* Common heap header
*
* All heap objects share the same flags and refcount fields. Objects other
* than strings also need to have a single or double linked list pointers
* for insertion into the "heap allocated" list. Strings have single linked
* list pointers for string table chaining.
*
* Technically, 'h_refcount' must be wide enough to guarantee that it cannot
* wrap; otherwise objects might be freed incorrectly after wrapping. The
* default refcount field is 32 bits even on 64-bit systems: while that's in
* theory incorrect, the Duktape heap needs to be larger than 64GB for the
* count to actually wrap (assuming 16-byte duk_tvals). This is very unlikely
* to ever be an issue, but if it is, disabling DUK_USE_REFCOUNT32 causes
* Duktape to use size_t for refcounts which should always be safe.
*
* Heap header size on 32-bit platforms: 8 bytes without reference counting,
* 16 bytes with reference counting.
*
* Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
* defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined()
* around them.
*/
/* XXX: macro for shared header fields (avoids some padding issues) */
struct duk_heaphdr {
duk_uint32_t h_flags;
#if defined(DUK_USE_REFERENCE_COUNTING)
#if defined(DUK_USE_ASSERTIONS)
/* When assertions enabled, used by mark-and-sweep for refcount
* validation. Largest reasonable type; also detects overflows.
*/
duk_size_t h_assert_refcount;
#endif
#if defined(DUK_USE_REFCOUNT16)
duk_uint16_t h_refcount;
#elif defined(DUK_USE_REFCOUNT32)
duk_uint32_t h_refcount;
#else
duk_size_t h_refcount;
#endif
#endif /* DUK_USE_REFERENCE_COUNTING */
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t h_next16;
#else
duk_heaphdr *h_next;
#endif
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
/* refcounting requires direct heap frees, which in turn requires a dual linked heap */
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t h_prev16;
#else
duk_heaphdr *h_prev;
#endif
#endif
/* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
* struct won't align nicely to 4 bytes. This 16-bit extra field
* is added to make the alignment clean; the field can be used by
* heap objects when 16-bit packing is used. This field is now
* conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
* used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
* this only matter to low memory environments anyway.
*/
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t h_extra16;
#endif
};
struct duk_heaphdr_string {
/* 16 bits would be enough for shared heaphdr flags and duk_hstring
* flags. The initial parts of duk_heaphdr_string and duk_heaphdr
* must match so changing the flags field size here would be quite
* awkward. However, to minimize struct size, we can pack at least
* 16 bits of duk_hstring data into the flags field.
*/
duk_uint32_t h_flags;
#if defined(DUK_USE_REFERENCE_COUNTING)
#if defined(DUK_USE_ASSERTIONS)
/* When assertions enabled, used by mark-and-sweep for refcount
* validation. Largest reasonable type; also detects overflows.
*/
duk_size_t h_assert_refcount;
#endif
#if defined(DUK_USE_REFCOUNT16)
duk_uint16_t h_refcount;
duk_uint16_t h_strextra16; /* round out to 8 bytes */
#elif defined(DUK_USE_REFCOUNT32)
duk_uint32_t h_refcount;
#else
duk_size_t h_refcount;
#endif
#else
duk_uint16_t h_strextra16;
#endif /* DUK_USE_REFERENCE_COUNTING */
duk_hstring *h_next;
/* No 'h_prev' pointer for strings. */
};
#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
/* 2 bits for heap type */
#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */
#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */
#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n))
#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */
#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */
#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */
#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
#define DUK_HTYPE_MIN 0
#define DUK_HTYPE_STRING 0
#define DUK_HTYPE_OBJECT 1
#define DUK_HTYPE_BUFFER 2
#define DUK_HTYPE_MAX 2
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HEAPHDR_GET_NEXT(heap,h) \
((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
(h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
} while (0)
#else
#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next)
#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
(h)->h_next = (val); \
} while (0)
#endif
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HEAPHDR_GET_PREV(heap,h) \
((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
(h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
} while (0)
#else
#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev)
#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
(h)->h_prev = (val); \
} while (0)
#endif
#endif
#if defined(DUK_USE_REFERENCE_COUNTING)
#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
(h)->h_refcount = (val); \
DUK_ASSERT((h)->h_refcount == (val)); /* No truncation. */ \
} while (0)
#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
#else
/* refcount macros not defined without refcounting, caller must #if defined() now */
#endif /* DUK_USE_REFERENCE_COUNTING */
/*
* Note: type is treated as a field separate from flags, so some masking is
* involved in the macros below.
*/
#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
#define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \
(h)->h_flags = (val); } \
}
#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
} while (0)
#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
(h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
} while (0)
/* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero
* and the comparison is unsigned, it's always true and generates warnings.
*/
#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
)
#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \
(h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
} while (0)
#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \
DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
(h)->h_flags |= (bits); \
} while (0)
#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \
DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
(h)->h_flags &= ~((bits)); \
} while (0)
#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0)
#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
/* get or set a range of flags; m=first bit number, n=number of bits */
#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \
(h)->h_flags = \
((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
| ((v) << (m)); \
} while (0)
/* init pointer fields to null */
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
#define DUK_HEAPHDR_INIT_NULLS(h) do { \
DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
} while (0)
#else
#define DUK_HEAPHDR_INIT_NULLS(h) do { \
DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
} while (0)
#endif
#define DUK_HEAPHDR_STRING_INIT_NULLS(h) do { \
(h)->h_next = NULL; \
} while (0)
/*
* Type tests
*/
/* Take advantage of the fact that for DUK_HTYPE_xxx numbers the lowest bit
* is only set for DUK_HTYPE_OBJECT (= 1).
*/
#if 0
#define DUK_HEAPHDR_IS_OBJECT(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT)
#endif
#define DUK_HEAPHDR_IS_OBJECT(h) ((h)->h_flags & 0x01UL)
#define DUK_HEAPHDR_IS_STRING(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING)
#define DUK_HEAPHDR_IS_BUFFER(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER)
/*
* Assert helpers
*/
/* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
* h->prev->next should point back to h.
*/
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_heaphdr_assert_valid_subclassed(duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_heaphdr_assert_valid(duk_heaphdr *h);
#define DUK_HEAPHDR_ASSERT_LINKS(heap,h) do { duk_heaphdr_assert_links((heap), (h)); } while (0)
#define DUK_HEAPHDR_ASSERT_VALID(h) do { duk_heaphdr_assert_valid((h)); } while (0)
#else
#define DUK_HEAPHDR_ASSERT_LINKS(heap,h) do {} while (0)
#define DUK_HEAPHDR_ASSERT_VALID(h) do {} while (0)
#endif
#endif /* DUK_HEAPHDR_H_INCLUDED */

View file

@ -1,78 +0,0 @@
/*
* duk_heaphdr assertion helpers
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_ASSERTIONS)
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
DUK_INTERNAL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h) {
DUK_UNREF(heap);
if (h != NULL) {
duk_heaphdr *h_prev, *h_next;
h_prev = DUK_HEAPHDR_GET_PREV(heap, h);
h_next = DUK_HEAPHDR_GET_NEXT(heap, h);
DUK_ASSERT(h_prev == NULL || (DUK_HEAPHDR_GET_NEXT(heap, h_prev) == h));
DUK_ASSERT(h_next == NULL || (DUK_HEAPHDR_GET_PREV(heap, h_next) == h));
}
}
#else
DUK_INTERNAL void duk_heaphdr_assert_links(duk_heap *heap, duk_heaphdr *h) {
DUK_UNREF(heap);
DUK_UNREF(h);
}
#endif
DUK_INTERNAL void duk_heaphdr_assert_valid(duk_heaphdr *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
}
/* Assert validity of a heaphdr, including all subclasses. */
DUK_INTERNAL void duk_heaphdr_assert_valid_subclassed(duk_heaphdr *h) {
switch (DUK_HEAPHDR_GET_TYPE(h)) {
case DUK_HTYPE_OBJECT: {
duk_hobject *h_obj = (duk_hobject *) h;
DUK_HOBJECT_ASSERT_VALID(h_obj);
if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
DUK_HCOMPFUNC_ASSERT_VALID((duk_hcompfunc *) h_obj);
} else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
DUK_HNATFUNC_ASSERT_VALID((duk_hnatfunc *) h_obj);
} else if (DUK_HOBJECT_IS_DECENV(h_obj)) {
DUK_HDECENV_ASSERT_VALID((duk_hdecenv *) h_obj);
} else if (DUK_HOBJECT_IS_OBJENV(h_obj)) {
DUK_HOBJENV_ASSERT_VALID((duk_hobjenv *) h_obj);
} else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_HBUFOBJ_ASSERT_VALID((duk_hbufobj *) h_obj);
#endif
} else if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) {
DUK_HBOUNDFUNC_ASSERT_VALID((duk_hboundfunc *) h_obj);
} else if (DUK_HOBJECT_IS_PROXY(h_obj)) {
DUK_HPROXY_ASSERT_VALID((duk_hproxy *) h_obj);
} else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
DUK_HTHREAD_ASSERT_VALID((duk_hthread *) h_obj);
} else {
/* Just a plain object. */
;
}
break;
}
case DUK_HTYPE_STRING: {
duk_hstring *h_str = (duk_hstring *) h;
DUK_HSTRING_ASSERT_VALID(h_str);
break;
}
case DUK_HTYPE_BUFFER: {
duk_hbuffer *h_buf = (duk_hbuffer *) h;
DUK_HBUFFER_ASSERT_VALID(h_buf);
break;
}
default: {
DUK_ASSERT(0);
}
}
}
#endif /* DUK_USE_ASSERTIONS */

View file

@ -1,45 +0,0 @@
/*
* Environment object representation.
*/
#if !defined(DUK_HENV_H_INCLUDED)
#define DUK_HENV_H_INCLUDED
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_hdecenv_assert_valid(duk_hdecenv *h);
DUK_INTERNAL_DECL void duk_hobjenv_assert_valid(duk_hobjenv *h);
#define DUK_HDECENV_ASSERT_VALID(h) do { duk_hdecenv_assert_valid((h)); } while (0)
#define DUK_HOBJENV_ASSERT_VALID(h) do { duk_hobjenv_assert_valid((h)); } while (0)
#else
#define DUK_HDECENV_ASSERT_VALID(h) do {} while (0)
#define DUK_HOBJENV_ASSERT_VALID(h) do {} while (0)
#endif
struct duk_hdecenv {
/* Shared object part. */
duk_hobject obj;
/* These control variables provide enough information to access live
* variables for a closure that is still open. If thread == NULL,
* the record is closed and the identifiers are in the property table.
*/
duk_hthread *thread;
duk_hobject *varmap;
duk_size_t regbase_byteoff;
};
struct duk_hobjenv {
/* Shared object part. */
duk_hobject obj;
/* Target object and 'this' binding for object binding. */
duk_hobject *target;
/* The 'target' object is used as a this binding in only some object
* environments. For example, the global environment does not provide
* a this binding, but a with statement does.
*/
duk_bool_t has_this;
};
#endif /* DUK_HENV_H_INCLUDED */

View file

@ -1,39 +0,0 @@
/*
* Heap native function representation.
*/
#if !defined(DUK_HNATFUNC_H_INCLUDED)
#define DUK_HNATFUNC_H_INCLUDED
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_hnatfunc_assert_valid(duk_hnatfunc *h);
#define DUK_HNATFUNC_ASSERT_VALID(h) do { duk_hnatfunc_assert_valid((h)); } while (0)
#else
#define DUK_HNATFUNC_ASSERT_VALID(h) do {} while (0)
#endif
#define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1)
#define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff)
struct duk_hnatfunc {
/* shared object part */
duk_hobject obj;
duk_c_function func;
duk_int16_t nargs;
duk_int16_t magic;
/* The 'magic' field allows an opaque 16-bit field to be accessed by the
* Duktape/C function. This allows, for instance, the same native function
* to be used for a set of very similar functions, with the 'magic' field
* providing the necessary non-argument flags / values to guide the behavior
* of the native function. The value is signed on purpose: it is easier to
* convert a signed value to unsigned (simply AND with 0xffff) than vice
* versa.
*
* Note: cannot place nargs/magic into the heaphdr flags, because
* duk_hobject takes almost all flags already.
*/
};
#endif /* DUK_HNATFUNC_H_INCLUDED */

View file

@ -1,981 +0,0 @@
/*
* Heap object representation.
*
* Heap objects are used for ECMAScript objects, arrays, and functions,
* but also for internal control like declarative and object environment
* records. Compiled functions, native functions, and threads are also
* objects but with an extended C struct.
*
* Objects provide the required ECMAScript semantics and exotic behaviors
* especially for property access.
*
* Properties are stored in three conceptual parts:
*
* 1. A linear 'entry part' contains ordered key-value-attributes triples
* and is the main method of string properties.
*
* 2. An optional linear 'array part' is used for array objects to store a
* (dense) range of [0,N[ array indexed entries with default attributes
* (writable, enumerable, configurable). If the array part would become
* sparse or non-default attributes are required, the array part is
* abandoned and moved to the 'entry part'.
*
* 3. An optional 'hash part' is used to optimize lookups of the entry
* part; it is used only for objects with sufficiently many properties
* and can be abandoned without loss of information.
*
* These three conceptual parts are stored in a single memory allocated area.
* This minimizes memory allocation overhead but also means that all three
* parts are resized together, and makes property access a bit complicated.
*/
#if !defined(DUK_HOBJECT_H_INCLUDED)
#define DUK_HOBJECT_H_INCLUDED
/* Object flags. Make sure this stays in sync with debugger object
* inspection code.
*/
/* XXX: some flags are object subtype specific (e.g. common to all function
* subtypes, duk_harray, etc) and could be reused for different subtypes.
*/
#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
#define DUK_HOBJECT_FLAG_CALLABLE DUK_HEAPHDR_USER_FLAG(2) /* object is callable */
#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(3) /* object established using Function.prototype.bind() */
#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */
#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */
#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */
#define DUK_HOBJECT_FLAG_FASTREFS DUK_HEAPHDR_USER_FLAG(7) /* object has no fields needing DECREF/marking beyond base duk_hobject header */
#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */
#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
#define DUK_HOBJECT_FLAG_HAVE_FINALIZER DUK_HEAPHDR_USER_FLAG(14) /* object has a callable (own) finalizer property */
#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */
#define DUK_HOBJECT_FLAG_SPECIAL_CALL DUK_HEAPHDR_USER_FLAG(19) /* special casing in call behavior, for .call(), .apply(), etc. */
#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
#define DUK_HOBJECT_FLAG_CLASS_BITS 5
#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \
DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \
DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
#define DUK_HOBJECT_GET_CLASS_MASK(h) \
(1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS))
/* Macro for creating flag initializer from a class number.
* Unsigned type cast is needed to avoid warnings about coercing
* a signed integer to an unsigned one; the largest class values
* have the highest bit (bit 31) set which causes this.
*/
#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
/* E5 Section 8.6.2 + custom classes */
#define DUK_HOBJECT_CLASS_NONE 0
#define DUK_HOBJECT_CLASS_OBJECT 1
#define DUK_HOBJECT_CLASS_ARRAY 2
#define DUK_HOBJECT_CLASS_FUNCTION 3
#define DUK_HOBJECT_CLASS_ARGUMENTS 4
#define DUK_HOBJECT_CLASS_BOOLEAN 5
#define DUK_HOBJECT_CLASS_DATE 6
#define DUK_HOBJECT_CLASS_ERROR 7
#define DUK_HOBJECT_CLASS_JSON 8
#define DUK_HOBJECT_CLASS_MATH 9
#define DUK_HOBJECT_CLASS_NUMBER 10
#define DUK_HOBJECT_CLASS_REGEXP 11
#define DUK_HOBJECT_CLASS_STRING 12
#define DUK_HOBJECT_CLASS_GLOBAL 13
#define DUK_HOBJECT_CLASS_SYMBOL 14
#define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */
#define DUK_HOBJECT_CLASS_DECENV 16 /* custom */
#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
#define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19
#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */
#define DUK_HOBJECT_CLASS_DATAVIEW 20
#define DUK_HOBJECT_CLASS_INT8ARRAY 21
#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23
#define DUK_HOBJECT_CLASS_INT16ARRAY 24
#define DUK_HOBJECT_CLASS_UINT16ARRAY 25
#define DUK_HOBJECT_CLASS_INT32ARRAY 26
#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
#define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29
#define DUK_HOBJECT_CLASS_MAX 29
/* Class masks. */
#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
#define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE)
#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE)
#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR)
#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION)
#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON)
#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH)
#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER)
#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT)
#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
#define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL)
#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY)
#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY)
#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY)
#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY)
#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY)
#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY)
#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
#define DUK_HOBJECT_CMASK_ALL_BUFOBJS \
(DUK_HOBJECT_CMASK_ARRAYBUFFER | \
DUK_HOBJECT_CMASK_DATAVIEW | \
DUK_HOBJECT_CMASK_INT8ARRAY | \
DUK_HOBJECT_CMASK_UINT8ARRAY | \
DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \
DUK_HOBJECT_CMASK_INT16ARRAY | \
DUK_HOBJECT_CMASK_UINT16ARRAY | \
DUK_HOBJECT_CMASK_INT32ARRAY | \
DUK_HOBJECT_CMASK_UINT32ARRAY | \
DUK_HOBJECT_CMASK_FLOAT32ARRAY | \
DUK_HOBJECT_CMASK_FLOAT64ARRAY)
#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
#define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */
#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
#else
#define DUK_HOBJECT_IS_BUFOBJ(h) 0
#endif
#define DUK_HOBJECT_IS_THREAD(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD)
#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_IS_PROXY(h) DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h))
#else
#define DUK_HOBJECT_IS_PROXY(h) 0
#endif
#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
DUK_HOBJECT_FLAG_COMPFUNC | \
DUK_HOBJECT_FLAG_NATFUNC)
#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
DUK_HOBJECT_FLAG_BOUNDFUNC | \
DUK_HOBJECT_FLAG_COMPFUNC | \
DUK_HOBJECT_FLAG_NATFUNC)
#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HOBJECT_HAS_CALLABLE((h))
/* Object has any exotic behavior(s). */
#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
DUK_HOBJECT_FLAG_BUFOBJ | \
DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
/* Object has any virtual properties (not counting Proxy behavior). */
#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
DUK_HOBJECT_FLAG_BUFOBJ)
#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS)
#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
#define DUK_HOBJECT_HAS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
#else
#define DUK_HOBJECT_HAS_BUFOBJ(h) 0
#endif
#define DUK_HOBJECT_HAS_FASTREFS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
#define DUK_HOBJECT_HAS_HAVE_FINALIZER(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
#else
#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) 0
#endif
#define DUK_HOBJECT_HAS_SPECIAL_CALL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
#define DUK_HOBJECT_SET_CALLABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
#endif
#define DUK_HOBJECT_SET_FASTREFS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
#define DUK_HOBJECT_SET_HAVE_FINALIZER(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
#endif
#define DUK_HOBJECT_SET_SPECIAL_CALL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
#define DUK_HOBJECT_CLEAR_CALLABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
#endif
#define DUK_HOBJECT_CLEAR_FASTREFS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
#define DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
#if defined(DUK_USE_ES6_PROXY)
#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
#endif
#define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
/* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond
* duk_hobject base header. This is used just for asserts so doesn't need to
* be optimized.
*/
#define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \
(DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \
DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \
DUK_HOBJECT_IS_BOUNDFUNC((h)))
#define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h)))
/* Flags used for property attributes in duk_propdesc and packed flags.
* Must fit into 8 bits.
*/
#define DUK_PROPDESC_FLAG_WRITABLE (1U << 0) /* E5 Section 8.6.1 */
#define DUK_PROPDESC_FLAG_ENUMERABLE (1U << 1) /* E5 Section 8.6.1 */
#define DUK_PROPDESC_FLAG_CONFIGURABLE (1U << 2) /* E5 Section 8.6.1 */
#define DUK_PROPDESC_FLAG_ACCESSOR (1U << 3) /* accessor */
#define DUK_PROPDESC_FLAG_VIRTUAL (1U << 4) /* property is virtual: used in duk_propdesc, never stored
* (used by e.g. buffer virtual properties)
*/
#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
DUK_PROPDESC_FLAG_ENUMERABLE | \
DUK_PROPDESC_FLAG_CONFIGURABLE | \
DUK_PROPDESC_FLAG_ACCESSOR)
/* Additional flags which are passed in the same flags argument as property
* flags but are not stored in object properties.
*/
#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1U << 4) /* internal define property: skip write silently if exists */
/* Convenience defines for property attributes. */
#define DUK_PROPDESC_FLAGS_NONE 0
#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE)
#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \
DUK_PROPDESC_FLAG_ENUMERABLE | \
DUK_PROPDESC_FLAG_CONFIGURABLE)
/* Flags for duk_hobject_get_own_propdesc() and variants. */
#define DUK_GETDESC_FLAG_PUSH_VALUE (1U << 0) /* push value to stack */
#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1U << 1) /* don't throw for prototype loop */
/*
* Macro for object validity check
*
* Assert for currently guaranteed relations between flags, for instance.
*/
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL_DECL void duk_hobject_assert_valid(duk_hobject *h);
#define DUK_HOBJECT_ASSERT_VALID(h) do { duk_hobject_assert_valid((h)); } while (0)
#else
#define DUK_HOBJECT_ASSERT_VALID(h) do {} while (0)
#endif
/*
* Macros to access the 'props' allocation.
*/
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HOBJECT_GET_PROPS(heap,h) \
((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16))
#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
} while (0)
#else
#define DUK_HOBJECT_GET_PROPS(heap,h) \
((h)->props)
#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
(h)->props = (duk_uint8_t *) (x); \
} while (0)
#endif
#if defined(DUK_USE_HOBJECT_LAYOUT_1)
/* LAYOUT 1 */
#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
((duk_hstring **) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) \
))
#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
((duk_propvalue *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \
))
#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
((duk_uint8_t *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
))
#define DUK_HOBJECT_A_GET_BASE(heap,h) \
((duk_tval *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
))
#define DUK_HOBJECT_H_GET_BASE(heap,h) \
((duk_uint32_t *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
))
#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
( \
(n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
(n_arr) * sizeof(duk_tval) + \
(n_hash) * sizeof(duk_uint32_t) \
)
#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 { \
(set_e_k) = (duk_hstring **) (void *) (p_base); \
(set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \
(set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \
(set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \
(set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
} while (0)
#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
/* LAYOUT 2 */
#if (DUK_USE_ALIGN_BY == 4)
#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
#elif (DUK_USE_ALIGN_BY == 8)
#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
#elif (DUK_USE_ALIGN_BY == 1)
#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
#else
#error invalid DUK_USE_ALIGN_BY
#endif
#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
((duk_hstring **) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
))
#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
((duk_propvalue *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) \
))
#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
((duk_uint8_t *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
))
#define DUK_HOBJECT_A_GET_BASE(heap,h) \
((duk_tval *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \
))
#define DUK_HOBJECT_H_GET_BASE(heap,h) \
((duk_uint32_t *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \
DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
))
#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
( \
(n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
(n_arr) * sizeof(duk_tval) + \
(n_hash) * sizeof(duk_uint32_t) \
)
#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 { \
(set_e_pv) = (duk_propvalue *) (void *) (p_base); \
(set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \
(set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \
(set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \
sizeof(duk_uint8_t) * (n_ent) + \
DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
(set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
} while (0)
#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
/* LAYOUT 3 */
#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
((duk_hstring **) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \
DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
))
#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
((duk_propvalue *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) \
))
#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
((duk_uint8_t *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \
DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \
))
#define DUK_HOBJECT_A_GET_BASE(heap,h) \
((duk_tval *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
))
#define DUK_HOBJECT_H_GET_BASE(heap,h) \
((duk_uint32_t *) (void *) ( \
DUK_HOBJECT_GET_PROPS((heap), (h)) + \
DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
))
#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
( \
(n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
(n_arr) * sizeof(duk_tval) + \
(n_hash) * sizeof(duk_uint32_t) \
)
#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 { \
(set_e_pv) = (duk_propvalue *) (void *) (p_base); \
(set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \
(set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \
(set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \
(set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \
} while (0)
#else
#error invalid hobject layout defines
#endif /* hobject property layout */
#define DUK_HOBJECT_P_ALLOC_SIZE(h) \
DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h)))
#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \
DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \
} while (0)
#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \
DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \
DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \
DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \
DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
} while (0)
#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
} while (0)
#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \
DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */
#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \
DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \
DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \
} while (0)
#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \
DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \
} while (0)
#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL
#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL
/*
* Macros for accessing size fields
*/
#if defined(DUK_USE_OBJSIZES16)
#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16)
#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0)
#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16)
#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0)
#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++)
#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16)
#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0)
#if defined(DUK_USE_HOBJECT_HASH_PART)
#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16)
#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0)
#else
#define DUK_HOBJECT_GET_HSIZE(h) 0
#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
#endif
#else
#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size)
#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0)
#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next)
#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0)
#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++)
#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size)
#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0)
#if defined(DUK_USE_HOBJECT_HASH_PART)
#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size)
#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0)
#else
#define DUK_HOBJECT_GET_HSIZE(h) 0
#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
#endif
#endif
/*
* Misc
*/
/* Maximum prototype traversal depth. Sanity limit which handles e.g.
* prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
*/
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
/*
* ECMAScript [[Class]]
*/
/* range check not necessary because all 4-bit values are mapped */
#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)]
#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \
DUK_HEAP_GET_STRING( \
(heap), \
DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
)
/*
* Macros for property handling
*/
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
(h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
} while (0)
#else
#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
((h)->prototype)
#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
(h)->prototype = (x); \
} while (0)
#endif
/* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
/* Set initial prototype, assume NULL previous prototype, INCREF new value,
* tolerate NULL.
*/
#define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \
duk_hthread *duk__thr = (thr); \
duk_hobject *duk__obj = (h); \
duk_hobject *duk__proto = (proto); \
DUK_UNREF(duk__thr); \
DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \
DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \
DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \
} while (0)
/*
* Finalizer check
*/
#if defined(DUK_USE_HEAPPTR16)
#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((heap), (h))
#else
#define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((h))
#endif
/*
* Resizing and hash behavior
*/
/* Sanity limit on max number of properties (allocated, not necessarily used).
* This is somewhat arbitrary, but if we're close to 2**32 properties some
* algorithms will fail (e.g. hash size selection, next prime selection).
* Also, we use negative array/entry table indices to indicate 'not found',
* so anything above 0x80000000 will cause trouble now.
*/
#if defined(DUK_USE_OBJSIZES16)
#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
#else
#define DUK_HOBJECT_MAX_PROPERTIES 0x3fffffffUL /* 2**30-1 ~= 1G properties */
#endif
/* internal align target for props allocation, must be 2*n for some n */
#if (DUK_USE_ALIGN_BY == 4)
#define DUK_HOBJECT_ALIGN_TARGET 4
#elif (DUK_USE_ALIGN_BY == 8)
#define DUK_HOBJECT_ALIGN_TARGET 8
#elif (DUK_USE_ALIGN_BY == 1)
#define DUK_HOBJECT_ALIGN_TARGET 1
#else
#error invalid DUK_USE_ALIGN_BY
#endif
/*
* PC-to-line constants
*/
#define DUK_PC2LINE_SKIP 64
/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
/*
* Struct defs
*/
struct duk_propaccessor {
duk_hobject *get;
duk_hobject *set;
};
union duk_propvalue {
/* The get/set pointers could be 16-bit pointer compressed but it
* would make no difference on 32-bit platforms because duk_tval is
* 8 bytes or more anyway.
*/
duk_tval v;
duk_propaccessor a;
};
struct duk_propdesc {
/* read-only values 'lifted' for ease of use */
duk_small_uint_t flags;
duk_hobject *get;
duk_hobject *set;
/* for updating (all are set to < 0 for virtual properties) */
duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */
duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */
duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */
};
struct duk_hobject {
duk_heaphdr hdr;
/*
* 'props' contains {key,value,flags} entries, optional array entries, and
* an optional hash lookup table for non-array entries in a single 'sliced'
* allocation. There are several layout options, which differ slightly in
* generated code size/speed and alignment/padding; duk_features.h selects
* the layout used.
*
* Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
*
* e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
* e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
* e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
* a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
* h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
* 0xffffffffUL = unused, 0xfffffffeUL = deleted
*
* Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
*
* e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
* e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
* e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable)
* a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
* h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
* 0xffffffffUL = unused, 0xfffffffeUL = deleted
*
* Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
*
* e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
* a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
* e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
* h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
* 0xffffffffUL = unused, 0xfffffffeUL = deleted
* e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
*
* In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms
* requiring 4 or 8 byte alignment. This ensures proper alignment
* for the entries, at the cost of memory footprint. However, it's
* probably preferable to use another layout on such platforms instead.
*
* In layout 2, the key and value parts are swapped to avoid padding
* the key array on platforms requiring alignment by 8. The flags part
* is padded to get alignment for array entries. The 'e_next' count does
* not need to be rounded as in layout 1.
*
* In layout 3, entry values and array values are always aligned properly,
* and assuming pointers are at most 8 bytes, so are the entry keys. Hash
* indices will be properly aligned (assuming pointers are at least 4 bytes).
* Finally, flags don't need additional alignment. This layout provides
* compact allocations without padding (even on platforms with alignment
* requirements) at the cost of a bit slower lookups.
*
* Objects with few keys don't have a hash index; keys are looked up linearly,
* which is cache efficient because the keys are consecutive. Larger objects
* have a hash index part which contains integer indexes to the entries part.
*
* A single allocation reduces memory allocation overhead but requires more
* work when any part needs to be resized. A sliced allocation for entries
* makes linear key matching faster on most platforms (more locality) and
* skimps on flags size (which would be followed by 3 bytes of padding in
* most architectures if entries were placed in a struct).
*
* 'props' also contains internal properties distinguished with a non-BMP
* prefix. Often used properties should be placed early in 'props' whenever
* possible to make accessing them as fast a possible.
*/
#if defined(DUK_USE_HEAPPTR16)
/* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
* duk_hcompfunc) are not free to use h_extra16 for this reason.
*/
#else
duk_uint8_t *props;
#endif
/* prototype: the only internal property lifted outside 'e' as it is so central */
#if defined(DUK_USE_HEAPPTR16)
duk_uint16_t prototype16;
#else
duk_hobject *prototype;
#endif
#if defined(DUK_USE_OBJSIZES16)
duk_uint16_t e_size16;
duk_uint16_t e_next16;
duk_uint16_t a_size16;
#if defined(DUK_USE_HOBJECT_HASH_PART)
duk_uint16_t h_size16;
#endif
#else
duk_uint32_t e_size; /* entry part size */
duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */
duk_uint32_t a_size; /* array part size (entirely gc reachable) */
#if defined(DUK_USE_HOBJECT_HASH_PART)
duk_uint32_t h_size; /* hash part size or 0 if unused */
#endif
#endif
};
/*
* Exposed data
*/
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
#endif /* !DUK_SINGLE_FILE */
/*
* Prototypes
*/
/* alloc and init */
DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
#endif
DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
/* resize */
DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
duk_hobject *obj,
duk_uint32_t new_e_size,
duk_uint32_t new_a_size,
duk_uint32_t new_h_size,
duk_bool_t abandon_array);
DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr,
duk_hobject *obj,
duk_uint32_t new_e_size);
#if 0 /*unused*/
DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr,
duk_hobject *obj,
duk_uint32_t new_a_size);
#endif
/* low-level property functions */
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);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_entry_tval_ptr_stridx(duk_heap *heap, duk_hobject *obj, duk_small_uint_t stridx);
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);
DUK_INTERNAL_DECL duk_tval *duk_hobject_find_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
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);
/* core property functions */
DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
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);
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);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
/* internal property functions */
#define DUK_DELPROP_FLAG_THROW (1U << 0)
#define DUK_DELPROP_FLAG_FORCE (1U << 1)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
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);
DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
#if defined(DUK_USE_HEAPPTR16)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj);
#else
DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj);
#endif
/* helpers for defineProperty() and defineProperties() */
DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
duk_idx_t idx_in,
duk_uint_t *out_defprop_flags,
duk_idx_t *out_idx_value,
duk_hobject **out_getter,
duk_hobject **out_setter);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
duk_uint_t defprop_flags,
duk_hobject *obj,
duk_hstring *key,
duk_idx_t idx_value,
duk_hobject *get,
duk_hobject *set,
duk_bool_t throw_flag);
/* Object built-in methods */
DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx);
DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags);
/* internal properties */
DUK_INTERNAL_DECL duk_tval *duk_hobject_get_internal_value_tval_ptr(duk_heap *heap, duk_hobject *obj);
DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
DUK_INTERNAL_DECL duk_harray *duk_hobject_get_formals(duk_hthread *thr, duk_hobject *obj);
DUK_INTERNAL_DECL duk_hobject *duk_hobject_get_varmap(duk_hthread *thr, duk_hobject *obj);
/* hobject management functions */
DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
/* ES2015 proxy */
#if defined(DUK_USE_ES6_PROXY)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj);
#endif
/* enumeration */
DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags);
DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags);
DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value);
/* macros */
DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
/* pc2line */
#if defined(DUK_USE_PC2LINE)
DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc);
#endif
/* misc */
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);
#if !defined(DUK_USE_OBJECT_BUILTIN)
/* These declarations are needed when related built-in is disabled and
* genbuiltins.py won't automatically emit the declerations.
*/
DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr);
#endif
#endif /* DUK_HOBJECT_H_INCLUDED */

View file

@ -1,271 +0,0 @@
/*
* Hobject allocation.
*
* Provides primitive allocation functions for all object types (plain object,
* compiled function, native function, thread). The object return is not yet
* in "heap allocated" list and has a refcount of zero, so caller must careful.
*/
/* XXX: In most cases there's no need for plain allocation without pushing
* to the value stack. Maybe rework contract?
*/
#include "third_party/duktape/duk_internal.h"
/*
* Helpers.
*/
DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_uint_t hobject_flags, duk_hobject *obj) {
DUK_ASSERT(obj != NULL);
/* Zeroed by caller. */
obj->hdr.h_flags = hobject_flags | DUK_HTYPE_OBJECT;
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(&obj->hdr) == DUK_HTYPE_OBJECT); /* Assume zero shift. */
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
DUK_HOBJECT_SET_PROTOTYPE(heap, obj, NULL);
DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
#endif
#if defined(DUK_USE_HEAPPTR16)
/* Zero encoded pointer is required to match NULL. */
DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
#endif
#endif
DUK_HEAPHDR_ASSERT_LINKS(heap, &obj->hdr);
DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
/* obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
* with this properly. This is intentional: empty objects consume a minimum
* amount of memory. Further, an initial allocation might fail and cause
* 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
*/
}
DUK_LOCAL void *duk__hobject_alloc_init(duk_hthread *thr, duk_uint_t hobject_flags, duk_size_t size) {
void *res;
res = (void *) DUK_ALLOC_CHECKED_ZEROED(thr, size);
DUK_ASSERT(res != NULL);
duk__init_object_parts(thr->heap, hobject_flags, (duk_hobject *) res);
return res;
}
/*
* Allocate an duk_hobject.
*
* The allocated object has no allocation for properties; the caller may
* want to force a resize if a desired size is known.
*
* The allocated object has zero reference count and is not reachable.
* The caller MUST make the object reachable and increase its reference
* count before invoking any operation that might require memory allocation.
*/
DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
duk_hobject *res;
DUK_ASSERT(heap != NULL);
/* different memory layout, alloc size, and init */
DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0);
DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0);
DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_BOUNDFUNC) == 0);
res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject));
if (DUK_UNLIKELY(res == NULL)) {
return NULL;
}
DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
duk__init_object_parts(heap, hobject_flags, res);
DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
return res;
}
DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hobject *res;
res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject));
return res;
}
DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hcompfunc *res;
res = (duk_hcompfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hcompfunc));
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
/* NULL pointer is required to encode to zero, so memset is enough. */
#else
res->data = NULL;
res->funcs = NULL;
res->bytecode = NULL;
#endif
res->lex_env = NULL;
res->var_env = NULL;
#endif
return res;
}
DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hnatfunc *res;
res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc));
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->func = NULL;
#endif
return res;
}
DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
duk_hboundfunc *res;
res = (duk_hboundfunc *) DUK_ALLOC(heap, sizeof(duk_hboundfunc));
if (!res) {
return NULL;
}
duk_memzero(res, sizeof(duk_hboundfunc));
duk__init_object_parts(heap, hobject_flags, &res->obj);
DUK_TVAL_SET_UNDEFINED(&res->target);
DUK_TVAL_SET_UNDEFINED(&res->this_binding);
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->args = NULL;
#endif
return res;
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hbufobj *res;
res = (duk_hbufobj *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hbufobj));
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->buf = NULL;
res->buf_prop = NULL;
#endif
DUK_HBUFOBJ_ASSERT_VALID(res);
return res;
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
/* Allocate a new thread.
*
* Leaves the built-ins array uninitialized. The caller must either
* initialize a new global context or share existing built-ins from
* another thread.
*/
DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
duk_hthread *res;
res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
if (DUK_UNLIKELY(res == NULL)) {
return NULL;
}
duk_memzero(res, sizeof(duk_hthread));
duk__init_object_parts(heap, hobject_flags, &res->obj);
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->ptr_curr_pc = NULL;
res->heap = NULL;
res->valstack = NULL;
res->valstack_end = NULL;
res->valstack_alloc_end = NULL;
res->valstack_bottom = NULL;
res->valstack_top = NULL;
res->callstack_curr = NULL;
res->resumer = NULL;
res->compile_ctx = NULL,
#if defined(DUK_USE_HEAPPTR16)
res->strs16 = NULL;
#else
res->strs = NULL;
#endif
{
duk_small_uint_t i;
for (i = 0; i < DUK_NUM_BUILTINS; i++) {
res->builtins[i] = NULL;
}
}
#endif
/* When nothing is running, API calls are in non-strict mode. */
DUK_ASSERT(res->strict == 0);
res->heap = heap;
/* XXX: Any reason not to merge duk_hthread_alloc.c here? */
return res;
}
DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hthread *res;
res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags);
if (res == NULL) {
DUK_ERROR_ALLOC_FAILED(thr);
DUK_WO_NORETURN(return NULL;);
}
return res;
}
DUK_INTERNAL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_harray *res;
res = (duk_harray *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_harray));
DUK_ASSERT(res->length == 0);
return res;
}
DUK_INTERNAL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hdecenv *res;
res = (duk_hdecenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hdecenv));
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->thread = NULL;
res->varmap = NULL;
#endif
DUK_ASSERT(res->thread == NULL);
DUK_ASSERT(res->varmap == NULL);
DUK_ASSERT(res->regbase_byteoff == 0);
return res;
}
DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hobjenv *res;
res = (duk_hobjenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobjenv));
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
res->target = NULL;
#endif
DUK_ASSERT(res->target == NULL);
return res;
}
DUK_INTERNAL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
duk_hproxy *res;
res = (duk_hproxy *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hproxy));
/* Leave ->target and ->handler uninitialized, as caller will always
* explicitly initialize them before any side effects are possible.
*/
return res;
}

View file

@ -1,127 +0,0 @@
/*
* duk_hobject and subclass assertion helpers
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_ASSERTIONS)
DUK_INTERNAL void duk_hobject_assert_valid(duk_hobject *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h) ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FUNCTION);
DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ(h) ||
(DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_DATAVIEW ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT8ARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT8ARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT16ARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT16ARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_INT32ARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_UINT32ARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FLOAT32ARRAY ||
DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_FLOAT64ARRAY));
/* Object is an Array <=> object has exotic array behavior */
DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) ||
(DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)));
}
DUK_INTERNAL void duk_harray_assert_valid(duk_harray *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) h));
}
DUK_INTERNAL void duk_hboundfunc_assert_valid(duk_hboundfunc *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) h));
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h->target) ||
(DUK_TVAL_IS_OBJECT(&h->target) &&
DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h->target))));
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&h->this_binding));
DUK_ASSERT(h->nargs == 0 || h->args != NULL);
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
DUK_INTERNAL void duk_hbufobj_assert_valid(duk_hbufobj *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(h->shift <= 3);
DUK_ASSERT(h->elem_type <= DUK_HBUFOBJ_ELEM_MAX);
DUK_ASSERT((h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT8) ||
(h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) ||
(h->shift == 0 && h->elem_type == DUK_HBUFOBJ_ELEM_INT8) ||
(h->shift == 1 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT16) ||
(h->shift == 1 && h->elem_type == DUK_HBUFOBJ_ELEM_INT16) ||
(h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_UINT32) ||
(h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_INT32) ||
(h->shift == 2 && h->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) ||
(h->shift == 3 && h->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64));
DUK_ASSERT(h->is_typedarray == 0 || h->is_typedarray == 1);
DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h));
if (h->buf == NULL) {
DUK_ASSERT(h->offset == 0);
DUK_ASSERT(h->length == 0);
} else {
/* No assertions for offset or length; in particular,
* it's OK for length to be longer than underlying
* buffer. Just ensure they don't wrap when added.
*/
DUK_ASSERT(h->offset + h->length >= h->offset);
}
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
DUK_INTERNAL void duk_hcompfunc_assert_valid(duk_hcompfunc *h) {
DUK_ASSERT(h != NULL);
}
DUK_INTERNAL void duk_hnatfunc_assert_valid(duk_hnatfunc *h) {
DUK_ASSERT(h != NULL);
}
DUK_INTERNAL void duk_hdecenv_assert_valid(duk_hdecenv *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) h));
DUK_ASSERT(h->thread == NULL || h->varmap != NULL);
}
DUK_INTERNAL void duk_hobjenv_assert_valid(duk_hobjenv *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_OBJENV((duk_hobject *) h));
DUK_ASSERT(h->target != NULL);
DUK_ASSERT(h->has_this == 0 || h->has_this == 1);
}
DUK_INTERNAL void duk_hproxy_assert_valid(duk_hproxy *h) {
DUK_ASSERT(h != NULL);
DUK_ASSERT(h->target != NULL);
DUK_ASSERT(h->handler != NULL);
DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) h));
}
DUK_INTERNAL void duk_hthread_assert_valid(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) thr) == DUK_HTYPE_OBJECT);
DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) thr));
DUK_ASSERT(thr->unused1 == 0);
DUK_ASSERT(thr->unused2 == 0);
}
DUK_INTERNAL void duk_ctx_assert_valid(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
DUK_HTHREAD_ASSERT_VALID(thr);
DUK_ASSERT(thr->valstack != NULL);
DUK_ASSERT(thr->valstack_bottom != NULL);
DUK_ASSERT(thr->valstack_top != NULL);
DUK_ASSERT(thr->valstack_end != NULL);
DUK_ASSERT(thr->valstack_alloc_end != NULL);
DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack);
DUK_ASSERT(thr->valstack_end >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack);
DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
}
#endif /* DUK_USE_ASSERTIONS */

View file

@ -1,129 +0,0 @@
/*
* Hobject ECMAScript [[Class]].
*/
#include "third_party/duktape/duk_internal.h"
#if (DUK_STRIDX_UC_ARGUMENTS > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_BOOLEAN > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_DATE > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_ERROR > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_FUNCTION > 255)
#error constant too large
#endif
#if (DUK_STRIDX_JSON > 255)
#error constant too large
#endif
#if (DUK_STRIDX_MATH > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_NUMBER > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_OBJECT > 255)
#error constant too large
#endif
#if (DUK_STRIDX_REG_EXP > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_STRING > 255)
#error constant too large
#endif
#if (DUK_STRIDX_GLOBAL > 255)
#error constant too large
#endif
#if (DUK_STRIDX_OBJ_ENV > 255)
#error constant too large
#endif
#if (DUK_STRIDX_DEC_ENV > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_POINTER > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UC_THREAD > 255)
#error constant too large
#endif
#if (DUK_STRIDX_ARRAY_BUFFER > 255)
#error constant too large
#endif
#if (DUK_STRIDX_DATA_VIEW > 255)
#error constant too large
#endif
#if (DUK_STRIDX_INT8_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UINT8_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_INT16_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UINT16_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_INT32_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_UINT32_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_FLOAT32_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_FLOAT64_ARRAY > 255)
#error constant too large
#endif
#if (DUK_STRIDX_EMPTY_STRING > 255)
#error constant too large
#endif
/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */
DUK_STRIDX_UC_OBJECT,
DUK_STRIDX_UC_ARRAY,
DUK_STRIDX_UC_FUNCTION,
DUK_STRIDX_UC_ARGUMENTS,
DUK_STRIDX_UC_BOOLEAN,
DUK_STRIDX_UC_DATE,
DUK_STRIDX_UC_ERROR,
DUK_STRIDX_JSON,
DUK_STRIDX_MATH,
DUK_STRIDX_UC_NUMBER,
DUK_STRIDX_REG_EXP,
DUK_STRIDX_UC_STRING,
DUK_STRIDX_GLOBAL,
DUK_STRIDX_UC_SYMBOL,
DUK_STRIDX_OBJ_ENV,
DUK_STRIDX_DEC_ENV,
DUK_STRIDX_UC_POINTER,
DUK_STRIDX_UC_THREAD,
DUK_STRIDX_ARRAY_BUFFER,
DUK_STRIDX_DATA_VIEW,
DUK_STRIDX_INT8_ARRAY,
DUK_STRIDX_UINT8_ARRAY,
DUK_STRIDX_UINT8_CLAMPED_ARRAY,
DUK_STRIDX_INT16_ARRAY,
DUK_STRIDX_UINT16_ARRAY,
DUK_STRIDX_INT32_ARRAY,
DUK_STRIDX_UINT32_ARRAY,
DUK_STRIDX_FLOAT32_ARRAY,
DUK_STRIDX_FLOAT64_ARRAY,
DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
};

View file

@ -1,706 +0,0 @@
/*
* Object enumeration support.
*
* Creates an internal enumeration state object to be used e.g. with for-in
* enumeration. The state object contains a snapshot of target object keys
* and internal control state for enumeration. Enumerator flags allow caller
* to e.g. request internal/non-enumerable properties, and to enumerate only
* "own" properties.
*
* Also creates the result value for e.g. Object.keys() based on the same
* internal structure.
*
* This snapshot-based enumeration approach is used to simplify enumeration:
* non-snapshot-based approaches are difficult to reconcile with mutating
* the enumeration target, running multiple long-lived enumerators at the
* same time, garbage collection details, etc. The downside is that the
* enumerator object is memory inefficient especially for iterating arrays.
*/
#include "third_party/duktape/duk_internal.h"
/* XXX: identify enumeration target with an object index (not top of stack) */
/* First enumerated key index in enumerator object, must match exactly the
* number of control properties inserted to the enumerator.
*/
#define DUK__ENUM_START_INDEX 2
/* Current implementation suffices for ES2015 for now because there's no symbol
* sorting, so commented out for now.
*/
/*
* Helper to sort enumeration keys using a callback for pairwise duk_hstring
* comparisons. The keys are in the enumeration object entry part, starting
* from DUK__ENUM_START_INDEX, and the entry part is dense. Entry part values
* are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true, "2" -> true,
* so it suffices to just switch keys without switching values.
*
* ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects:
* (1) array indices in ascending order,
* (2) non-array-index keys in insertion order, and
* (3) symbols in insertion order.
* http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys.
*
* This rule is applied to "own properties" at each inheritance level;
* non-duplicate parent keys always follow child keys. For example,
* an inherited array index will enumerate -after- a symbol in the
* child.
*
* Insertion sort is used because (1) it's simple and compact, (2) works
* in-place, (3) minimizes operations if data is already nearly sorted,
* (4) doesn't reorder elements considered equal.
* http://en.wikipedia.org/wiki/Insertion_sort
*/
/* Sort key, must hold array indices, "not array index" marker, and one more
* higher value for symbols.
*/
#if !defined(DUK_USE_SYMBOL_BUILTIN)
typedef duk_uint32_t duk__sort_key_t;
#elif defined(DUK_USE_64BIT_OPS)
typedef duk_uint64_t duk__sort_key_t;
#else
typedef duk_double_t duk__sort_key_t;
#endif
/* Get sort key for a duk_hstring. */
DUK_LOCAL duk__sort_key_t duk__hstring_sort_key(duk_hstring *x) {
duk__sort_key_t val;
/* For array indices [0,0xfffffffe] use the array index as is.
* For strings, use 0xffffffff, the marker 'arridx' already in
* duk_hstring. For symbols, any value above 0xffffffff works,
* as long as it is the same for all symbols; currently just add
* the masked flag field into the arridx temporary.
*/
DUK_ASSERT(x != NULL);
DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(x) || DUK_HSTRING_GET_ARRIDX_FAST(x) == DUK_HSTRING_NO_ARRAY_INDEX);
val = (duk__sort_key_t) DUK_HSTRING_GET_ARRIDX_FAST(x);
#if defined(DUK_USE_SYMBOL_BUILTIN)
val = val + (duk__sort_key_t) (DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) x) & DUK_HSTRING_FLAG_SYMBOL);
#endif
return (duk__sort_key_t) val;
}
/* Insert element 'b' after element 'a'? */
DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk__sort_key_t val_b) {
duk__sort_key_t val_a;
DUK_ASSERT(a != NULL);
DUK_ASSERT(b != NULL);
DUK_UNREF(b); /* Not actually needed now, val_b suffices. */
val_a = duk__hstring_sort_key(a);
if (val_a > val_b) {
return 0;
} else {
return 1;
}
}
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) {
duk_hstring **keys;
duk_int_fast32_t idx;
DUK_ASSERT(h_obj != NULL);
DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX);
DUK_ASSERT(idx_end >= idx_start);
DUK_UNREF(thr);
if (idx_end <= idx_start + 1) {
return; /* Zero or one element(s). */
}
keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
for (idx = idx_start + 1; idx < idx_end; idx++) {
duk_hstring *h_curr;
duk_int_fast32_t idx_insert;
duk__sort_key_t val_curr;
h_curr = keys[idx];
DUK_ASSERT(h_curr != NULL);
/* Scan backwards for insertion place. This works very well
* when the elements are nearly in order which is the common
* (and optimized for) case.
*/
val_curr = duk__hstring_sort_key(h_curr); /* Remains same during scanning. */
for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) {
duk_hstring *h_insert;
h_insert = keys[idx_insert];
DUK_ASSERT(h_insert != NULL);
if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) {
break;
}
}
/* If we're out of indices, idx_insert == idx_start - 1 and idx_insert++
* brings us back to idx_start.
*/
idx_insert++;
DUK_ASSERT(idx_insert >= 0 && idx_insert <= idx);
/* .-- p_insert .-- p_curr
* v v
* | ... | insert | ... | curr
*/
/* This could also done when the keys are in order, i.e.
* idx_insert == idx. The result would be an unnecessary
* memmove() but we use an explicit check because the keys
* are very often in order already.
*/
if (idx != idx_insert) {
duk_memmove((void *) (keys + idx_insert + 1),
(const void *) (keys + idx_insert),
((size_t) (idx - idx_insert) * sizeof(duk_hstring *)));
keys[idx_insert] = h_curr;
}
}
}
/*
* Create an internal enumerator object E, which has its keys ordered
* to match desired enumeration ordering. Also initialize internal control
* properties for enumeration.
*
* Note: if an array was used to hold enumeration keys instead, an array
* scan would be needed to eliminate duplicates found in the prototype chain.
*/
DUK_LOCAL void duk__add_enum_key(duk_hthread *thr, duk_hstring *k) {
/* 'k' may be unreachable on entry so must push without any
* potential for GC.
*/
duk_push_hstring(thr, k);
duk_push_true(thr);
duk_put_prop(thr, -3);
}
DUK_LOCAL void duk__add_enum_key_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
duk__add_enum_key(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
}
DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags) {
duk_hobject *enum_target;
duk_hobject *curr;
duk_hobject *res;
#if defined(DUK_USE_ES6_PROXY)
duk_hobject *h_proxy_target;
duk_hobject *h_proxy_handler;
duk_hobject *h_trap_result;
#endif
duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
duk_uint_fast32_t sort_start_index;
DUK_ASSERT(thr != NULL);
enum_target = duk_require_hobject(thr, -1);
DUK_ASSERT(enum_target != NULL);
duk_push_bare_object(thr);
res = duk_known_hobject(thr, -1);
/* [enum_target res] */
/* Target must be stored so that we can recheck whether or not
* keys still exist when we enumerate. This is not done if the
* enumeration result comes from a proxy trap as there is no
* real object to check against.
*/
duk_push_hobject(thr, enum_target);
duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_TARGET); /* Target is bare, plain put OK. */
/* Initialize index so that we skip internal control keys. */
duk_push_int(thr, DUK__ENUM_START_INDEX);
duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT); /* Target is bare, plain put OK. */
/*
* Proxy object handling
*/
#if defined(DUK_USE_ES6_PROXY)
if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
goto skip_proxy;
}
if (DUK_LIKELY(!duk_hobject_proxy_check(enum_target,
&h_proxy_target,
&h_proxy_handler))) {
goto skip_proxy;
}
/* XXX: share code with Object.keys() Proxy handling */
/* In ES2015 for-in invoked the "enumerate" trap; in ES2016 "enumerate"
* has been obsoleted and "ownKeys" is used instead.
*/
DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
duk_push_hobject(thr, h_proxy_handler);
if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
/* No need to replace the 'enum_target' value in stack, only the
* enum_target reference. This also ensures that the original
* enum target is reachable, which keeps the proxy and the proxy
* target reachable. We do need to replace the internal _Target.
*/
DUK_DDD(DUK_DDDPRINT("no ownKeys trap, enumerate proxy target instead"));
DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
enum_target = h_proxy_target;
duk_push_hobject(thr, enum_target); /* -> [ ... enum_target res handler undefined target ] */
duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_INT_TARGET); /* Target is bare, plain put OK. */
duk_pop_2(thr); /* -> [ ... enum_target res ] */
goto skip_proxy;
}
/* [ ... enum_target res handler trap ] */
duk_insert(thr, -2);
duk_push_hobject(thr, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
duk_call_method(thr, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
h_trap_result = duk_require_hobject(thr, -1);
DUK_UNREF(h_trap_result);
duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
/* -> [ ... enum_target res trap_result keys_array ] */
/* Copy cleaned up trap result keys into the enumerator object. */
/* XXX: result is a dense array; could make use of that. */
DUK_ASSERT(duk_is_array(thr, -1));
len = (duk_uint_fast32_t) duk_get_length(thr, -1);
for (i = 0; i < len; i++) {
(void) duk_get_prop_index(thr, -1, (duk_uarridx_t) i);
DUK_ASSERT(duk_is_string(thr, -1)); /* postprocess cleaned up */
/* [ ... enum_target res trap_result keys_array val ] */
duk_push_true(thr);
/* [ ... enum_target res trap_result keys_array val true ] */
duk_put_prop(thr, -5);
}
/* [ ... enum_target res trap_result keys_array ] */
duk_pop_2(thr);
duk_remove_m2(thr);
/* [ ... res ] */
/* The internal _Target property is kept pointing to the original
* enumeration target (the proxy object), so that the enumerator
* 'next' operation can read property values if so requested. The
* fact that the _Target is a proxy disables key existence check
* during enumeration.
*/
DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res));
goto compact_and_return;
skip_proxy:
#endif /* DUK_USE_ES6_PROXY */
curr = enum_target;
sort_start_index = DUK__ENUM_START_INDEX;
DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(res) == DUK__ENUM_START_INDEX);
while (curr) {
duk_uint_fast32_t sort_end_index;
#if !defined(DUK_USE_PREFER_SIZE)
duk_bool_t need_sort = 0;
#endif
duk_bool_t cond;
/* Enumeration proceeds by inheritance level. Virtual
* properties need to be handled specially, followed by
* array part, and finally entry part.
*
* If there are array index keys in the entry part or any
* other risk of the ES2015 [[OwnPropertyKeys]] order being
* violated, need_sort is set and an explicit ES2015 sort is
* done for the inheritance level.
*/
/* XXX: inheriting from proxy */
/*
* Virtual properties.
*
* String and buffer indices are virtual and always enumerable,
* 'length' is virtual and non-enumerable. Array and arguments
* object props have special behavior but are concrete.
*
* String and buffer objects don't have an array part so as long
* as virtual array index keys are enumerated first, we don't
* need to set need_sort.
*/
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
cond = DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) || DUK_HOBJECT_IS_BUFOBJ(curr);
#else
cond = DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr);
#endif
cond = cond && !(enum_flags & DUK_ENUM_EXCLUDE_STRINGS);
if (cond) {
duk_bool_t have_length = 1;
/* String and buffer enumeration behavior is identical now,
* so use shared handler.
*/
if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
duk_hstring *h_val;
h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
}
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
else {
duk_hbufobj *h_bufobj;
DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(curr));
h_bufobj = (duk_hbufobj *) curr;
if (h_bufobj == NULL || !h_bufobj->is_typedarray) {
/* Zero length seems like a good behavior for neutered buffers.
* ArrayBuffer (non-view) and DataView don't have index properties
* or .length property.
*/
len = 0;
have_length = 0;
} else {
/* There's intentionally no check for
* current underlying buffer length.
*/
len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
}
}
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
for (i = 0; i < len; i++) {
duk_hstring *k;
/* This is a bit fragile: the string is not
* reachable until it is pushed by the helper.
*/
k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i);
DUK_ASSERT(k);
duk__add_enum_key(thr, k);
/* [enum_target res] */
}
/* 'length' and other virtual properties are not
* enumerable, but are included if non-enumerable
* properties are requested.
*/
if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
}
}
/*
* Array part
*/
cond = !(enum_flags & DUK_ENUM_EXCLUDE_STRINGS);
if (cond) {
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
duk_hstring *k;
duk_tval *tv;
tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i);
if (DUK_TVAL_IS_UNUSED(tv)) {
continue;
}
k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i); /* Fragile reachability. */
DUK_ASSERT(k);
duk__add_enum_key(thr, k);
/* [enum_target res] */
}
if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) {
/* Array .length comes after numeric indices. */
if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
}
}
}
/*
* Entries part
*/
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) {
duk_hstring *k;
k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i);
if (!k) {
continue;
}
if (!(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) &&
!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) {
continue;
}
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) &&
DUK_HSTRING_HAS_HIDDEN(k)) {
continue;
}
if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
continue;
}
#if !defined(DUK_USE_PREFER_SIZE)
need_sort = 1;
#endif
} else {
DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k)); /* would also have symbol flag */
if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) {
continue;
}
}
if (DUK_HSTRING_HAS_ARRIDX(k)) {
/* This in currently only possible if the
* object has no array part: the array part
* is exhaustive when it is present.
*/
#if !defined(DUK_USE_PREFER_SIZE)
need_sort = 1;
#endif
} else {
if (enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) {
continue;
}
}
DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
duk__add_enum_key(thr, k);
/* [enum_target res] */
}
/* Sort enumerated keys according to ES2015 requirements for
* the "inheritance level" just processed. This is far from
* optimal, ES2015 semantics could be achieved more efficiently
* by handling array index string keys (and symbol keys)
* specially above in effect doing the sort inline.
*
* Skip the sort if array index sorting is requested because
* we must consider all keys, also inherited, so an explicit
* sort is done for the whole result after we're done with the
* prototype chain.
*
* Also skip the sort if need_sort == 0, i.e. we know for
* certain that the enumerated order is already correct.
*/
sort_end_index = DUK_HOBJECT_GET_ENEXT(res);
if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) {
#if defined(DUK_USE_PREFER_SIZE)
duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
#else
if (need_sort) {
DUK_DDD(DUK_DDDPRINT("need to sort"));
duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
} else {
DUK_DDD(DUK_DDDPRINT("no need to sort"));
}
#endif
}
sort_start_index = sort_end_index;
if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
break;
}
curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
}
/* [enum_target res] */
duk_remove_m2(thr);
/* [res] */
if (enum_flags & DUK_ENUM_SORT_ARRAY_INDICES) {
/* Some E5/E5.1 algorithms require that array indices are iterated
* in a strictly ascending order. This is the case for e.g.
* Array.prototype.forEach() and JSON.stringify() PropertyList
* handling. The caller can request an explicit sort in these
* cases.
*/
/* Sort to ES2015 order which works for pure array incides but
* also for mixed keys.
*/
duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) DUK__ENUM_START_INDEX, (duk_int_fast32_t) DUK_HOBJECT_GET_ENEXT(res));
}
#if defined(DUK_USE_ES6_PROXY)
compact_and_return:
#endif
/* compact; no need to seal because object is internal */
duk_hobject_compact_props(thr, res);
DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
}
/*
* Returns non-zero if a key and/or value was enumerated, and:
*
* [enum] -> [key] (get_value == 0)
* [enum] -> [key value] (get_value == 1)
*
* Returns zero without pushing anything on the stack otherwise.
*/
DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value) {
duk_hobject *e;
duk_hobject *enum_target;
duk_hstring *res = NULL;
duk_uint_fast32_t idx;
duk_bool_t check_existence;
DUK_ASSERT(thr != NULL);
/* [... enum] */
e = duk_require_hobject(thr, -1);
/* XXX use get tval ptr, more efficient */
duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_NEXT);
idx = (duk_uint_fast32_t) duk_require_uint(thr, -1);
duk_pop(thr);
DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
/* Enumeration keys are checked against the enumeration target (to see
* that they still exist). In the proxy enumeration case _Target will
* be the proxy, and checking key existence against the proxy is not
* required (or sensible, as the keys may be fully virtual).
*/
duk_xget_owndataprop_stridx_short(thr, -1, DUK_STRIDX_INT_TARGET);
enum_target = duk_require_hobject(thr, -1);
DUK_ASSERT(enum_target != NULL);
#if defined(DUK_USE_ES6_PROXY)
check_existence = (!DUK_HOBJECT_IS_PROXY(enum_target));
#else
check_existence = 1;
#endif
duk_pop(thr); /* still reachable */
DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
(duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(thr, -1)));
/* no array part */
for (;;) {
duk_hstring *k;
if (idx >= DUK_HOBJECT_GET_ENEXT(e)) {
DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements"));
break;
}
/* we know these because enum objects are internally created */
k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx);
DUK_ASSERT(k != NULL);
DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx));
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v));
idx++;
/* recheck that the property still exists */
if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) {
DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip"));
continue;
}
DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k));
res = k;
break;
}
DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
duk_push_u32(thr, (duk_uint32_t) idx);
duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
/* [... enum] */
if (res) {
duk_push_hstring(thr, res);
if (get_value) {
duk_push_hobject(thr, enum_target);
duk_dup_m2(thr); /* -> [... enum key enum_target key] */
duk_get_prop(thr, -2); /* -> [... enum key enum_target val] */
duk_remove_m2(thr); /* -> [... enum key val] */
duk_remove(thr, -3); /* -> [... key val] */
} else {
duk_remove_m2(thr); /* -> [... key] */
}
return 1;
} else {
duk_pop(thr); /* -> [...] */
return 0;
}
}
/*
* Get enumerated keys in an ECMAScript array. Matches Object.keys() behavior
* described in E5 Section 15.2.3.14.
*/
DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags) {
duk_hobject *e;
duk_hstring **keys;
duk_tval *tv;
duk_uint_fast32_t count;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(duk_get_hobject(thr, -1) != NULL);
/* Create a temporary enumerator to get the (non-duplicated) key list;
* the enumerator state is initialized without being needed, but that
* has little impact.
*/
duk_hobject_enumerator_create(thr, enum_flags);
e = duk_known_hobject(thr, -1);
/* [enum_target enum res] */
/* Create dense result array to exact size. */
DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX);
count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX);
/* XXX: uninit would be OK */
tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count);
DUK_ASSERT(count == 0 || tv != NULL);
DUK_ASSERT(!duk_is_bare_object(thr, -1));
/* Fill result array, no side effects. */
keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, e);
keys += DUK__ENUM_START_INDEX;
while (count-- > 0) {
duk_hstring *k;
k = *keys++;
DUK_ASSERT(k != NULL); /* enumerator must have no keys deleted */
DUK_TVAL_SET_STRING(tv, k);
tv++;
DUK_HSTRING_INCREF(thr, k);
}
/* [enum_target enum res] */
duk_remove_m2(thr);
/* [enum_target res] */
return 1; /* return 1 to allow callers to tail call */
}

View file

@ -1,53 +0,0 @@
/*
* Misc support functions
*/
#include "third_party/duktape/duk_internal.h"
DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
duk_uint_t sanity;
DUK_ASSERT(thr != NULL);
/* False if the object is NULL or the prototype 'p' is NULL.
* In particular, false if both are NULL (don't compare equal).
*/
if (h == NULL || p == NULL) {
return 0;
}
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
do {
if (h == p) {
return 1;
}
if (sanity-- == 0) {
if (ignore_loop) {
break;
} else {
DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
DUK_WO_NORETURN(return 0;);
}
}
h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
} while (h);
return 0;
}
DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
#if defined(DUK_USE_REFERENCE_COUNTING)
duk_hobject *tmp;
DUK_ASSERT(h);
tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
#else
DUK_ASSERT(h);
DUK_UNREF(thr);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
#endif
}

View file

@ -1,244 +0,0 @@
/*
* Helpers for creating and querying pc2line debug data, which
* converts a bytecode program counter to a source line number.
*
* The run-time pc2line data is bit-packed, and documented in:
*
* doc/function-objects.rst
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_PC2LINE)
/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
duk_hbuffer_dynamic *h_buf;
duk_bitencoder_ctx be_ctx_alloc;
duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
duk_uint32_t *hdr;
duk_size_t new_size;
duk_uint_fast32_t num_header_entries;
duk_uint_fast32_t curr_offset;
duk_int_fast32_t curr_line, next_line, diff_line;
duk_uint_fast32_t curr_pc;
duk_uint_fast32_t hdr_index;
DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
duk_push_dynamic_buffer(thr, (duk_size_t) curr_offset);
h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
DUK_ASSERT(hdr != NULL);
hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */
curr_pc = 0U;
while (curr_pc < length) {
new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
duk_hbuffer_resize(thr, h_buf, new_size);
hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
DUK_ASSERT(hdr != NULL);
DUK_ASSERT(curr_pc < length);
hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
#if 0
DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld",
(long) (curr_pc / DUK_PC2LINE_SKIP),
(long) curr_pc,
(long) hdr[hdr_index + 0],
(long) hdr[hdr_index + 1]));
#endif
duk_memzero(be_ctx, sizeof(*be_ctx));
be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
for (;;) {
curr_pc++;
if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */
(curr_pc >= length) ) { /* end of bytecode */
break;
}
DUK_ASSERT(curr_pc < length);
next_line = (duk_int32_t) instrs[curr_pc].line;
diff_line = next_line - curr_line;
#if 0
DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld",
(long) curr_line, (long) next_line, (long) diff_line));
#endif
if (diff_line == 0) {
/* 0 */
duk_be_encode(be_ctx, 0, 1);
} else if (diff_line >= 1 && diff_line <= 4) {
/* 1 0 <2 bits> */
duk_be_encode(be_ctx, (duk_uint32_t) ((0x02 << 2) + (diff_line - 1)), 4);
} else if (diff_line >= -0x80 && diff_line <= 0x7f) {
/* 1 1 0 <8 bits> */
DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
duk_be_encode(be_ctx, (duk_uint32_t) ((0x06 << 8) + (diff_line + 0x80)), 11);
} else {
/* 1 1 1 <32 bits>
* Encode in two parts to avoid bitencode 24-bit limitation
*/
duk_be_encode(be_ctx, (duk_uint32_t) ((0x07 << 16) + ((next_line >> 16) & 0xffff)), 19);
duk_be_encode(be_ctx, (duk_uint32_t) (next_line & 0xffff), 16);
}
curr_line = next_line;
}
duk_be_finish(be_ctx);
DUK_ASSERT(!be_ctx->truncated);
/* be_ctx->offset == length of encoded bitstream */
curr_offset += (duk_uint_fast32_t) be_ctx->offset;
}
/* compact */
new_size = (duk_size_t) curr_offset;
duk_hbuffer_resize(thr, h_buf, new_size);
(void) duk_to_fixed_buffer(thr, -1, NULL);
DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
(long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
(duk_tval *) duk_get_tval(thr, -1)));
}
/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
* it will map to a large PC which is out of bounds and causes a zero to be
* returned.
*/
DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
duk_bitdecoder_ctx bd_ctx_alloc;
duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
duk_uint32_t *hdr;
duk_uint_fast32_t start_offset;
duk_uint_fast32_t pc_limit;
duk_uint_fast32_t hdr_index;
duk_uint_fast32_t pc_base;
duk_uint_fast32_t n;
duk_uint_fast32_t curr_line;
DUK_ASSERT(buf != NULL);
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf));
DUK_UNREF(thr);
/*
* Use the index in the header to find the right starting point
*/
hdr_index = pc / DUK_PC2LINE_SKIP;
pc_base = hdr_index * DUK_PC2LINE_SKIP;
n = pc - pc_base;
if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
goto pc2line_error;
}
hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
pc_limit = hdr[0];
if (pc >= pc_limit) {
/* Note: pc is unsigned and cannot be negative */
DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
(long) pc, (long) pc_limit));
goto pc2line_error;
}
curr_line = hdr[1 + hdr_index * 2];
start_offset = hdr[1 + hdr_index * 2 + 1];
if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
(long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
goto pc2line_error;
}
/*
* Iterate the bitstream (line diffs) until PC is reached
*/
duk_memzero(bd_ctx, sizeof(*bd_ctx));
bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
#if 0
DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld",
(long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset));
#endif
while (n > 0) {
#if 0
DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line));
#endif
if (duk_bd_decode_flag(bd_ctx)) {
if (duk_bd_decode_flag(bd_ctx)) {
if (duk_bd_decode_flag(bd_ctx)) {
/* 1 1 1 <32 bits> */
duk_uint_fast32_t t;
t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */
t = (t << 16) + duk_bd_decode(bd_ctx, 16);
curr_line = t;
} else {
/* 1 1 0 <8 bits> */
duk_uint_fast32_t t;
t = duk_bd_decode(bd_ctx, 8);
curr_line = curr_line + t - 0x80;
}
} else {
/* 1 0 <2 bits> */
duk_uint_fast32_t t;
t = duk_bd_decode(bd_ctx, 2);
curr_line = curr_line + t + 1;
}
} else {
/* 0: no change */
}
n--;
}
DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
return curr_line;
pc2line_error:
DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
return 0;
}
DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc) {
duk_hbuffer_fixed *pc2line;
duk_uint_fast32_t line;
/* XXX: now that pc2line is used by the debugger quite heavily in
* checked execution, this should be optimized to avoid value stack
* and perhaps also implement some form of pc2line caching (see
* future work in debugger.rst).
*/
duk_xget_owndataprop_stridx_short(thr, idx_func, DUK_STRIDX_INT_PC2LINE);
pc2line = (duk_hbuffer_fixed *) (void *) duk_get_hbuffer(thr, -1);
if (pc2line != NULL) {
DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc);
} else {
line = 0;
}
duk_pop(thr);
return line;
}
#endif /* DUK_USE_PC2LINE */

Some files were not shown because too many files have changed in this diff Show more