mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Delete Duktape (#97)
This commit is contained in:
parent
0a61fe4ea0
commit
2a3037d4e8
157 changed files with 2 additions and 103725 deletions
1
Makefile
1
Makefile
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
console.log('Hello world!\n');
|
||||
console.log('2+3=' + NativeAdd(2, 3) + '\n');
|
|
@ -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;
|
||||
}
|
|
@ -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.:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
25
third_party/duktape/LICENSE.txt
vendored
25
third_party/duktape/LICENSE.txt
vendored
|
@ -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.
|
110
third_party/duktape/authors.rst
vendored
110
third_party/duktape/authors.rst
vendored
|
@ -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.
|
34
third_party/duktape/duk_alloc_default.c
vendored
34
third_party/duktape/duk_alloc_default.c
vendored
|
@ -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 */
|
73
third_party/duktape/duk_api_buffer.c
vendored
73
third_party/duktape/duk_api_buffer.c
vendored
|
@ -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);
|
||||
}
|
760
third_party/duktape/duk_api_bytecode.c
vendored
760
third_party/duktape/duk_api_bytecode.c
vendored
|
@ -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 */
|
516
third_party/duktape/duk_api_call.c
vendored
516
third_party/duktape/duk_api_call.c
vendored
|
@ -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.
|
||||
*/
|
||||
}
|
926
third_party/duktape/duk_api_codec.c
vendored
926
third_party/duktape/duk_api_codec.c
vendored
|
@ -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 */
|
172
third_party/duktape/duk_api_compile.c
vendored
172
third_party/duktape/duk_api_compile.c
vendored
|
@ -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;
|
||||
}
|
261
third_party/duktape/duk_api_debug.c
vendored
261
third_party/duktape/duk_api_debug.c
vendored
|
@ -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 */
|
205
third_party/duktape/duk_api_heap.c
vendored
205
third_party/duktape/duk_api_heap.c
vendored
|
@ -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);
|
||||
|
||||
/* [ ... ] */
|
||||
}
|
229
third_party/duktape/duk_api_inspect.c
vendored
229
third_party/duktape/duk_api_inspect.c
vendored
|
@ -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.
|
||||
*/
|
||||
}
|
386
third_party/duktape/duk_api_internal.h
vendored
386
third_party/duktape/duk_api_internal.h
vendored
|
@ -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 */
|
80
third_party/duktape/duk_api_memory.c
vendored
80
third_party/duktape/duk_api_memory.c
vendored
|
@ -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);
|
||||
}
|
1050
third_party/duktape/duk_api_object.c
vendored
1050
third_party/duktape/duk_api_object.c
vendored
File diff suppressed because it is too large
Load diff
9
third_party/duktape/duk_api_random.c
vendored
9
third_party/duktape/duk_api_random.c
vendored
|
@ -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);
|
||||
}
|
6822
third_party/duktape/duk_api_stack.c
vendored
6822
third_party/duktape/duk_api_stack.c
vendored
File diff suppressed because it is too large
Load diff
378
third_party/duktape/duk_api_string.c
vendored
378
third_party/duktape/duk_api_string.c
vendored
|
@ -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;
|
||||
}
|
110
third_party/duktape/duk_api_time.c
vendored
110
third_party/duktape/duk_api_time.c
vendored
|
@ -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;
|
||||
}
|
1647
third_party/duktape/duk_bi_array.c
vendored
1647
third_party/duktape/duk_bi_array.c
vendored
File diff suppressed because it is too large
Load diff
69
third_party/duktape/duk_bi_boolean.c
vendored
69
third_party/duktape/duk_bi_boolean.c
vendored
|
@ -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 */
|
2982
third_party/duktape/duk_bi_buffer.c
vendored
2982
third_party/duktape/duk_bi_buffer.c
vendored
File diff suppressed because it is too large
Load diff
1662
third_party/duktape/duk_bi_cbor.c
vendored
1662
third_party/duktape/duk_bi_cbor.c
vendored
File diff suppressed because it is too large
Load diff
1771
third_party/duktape/duk_bi_date.c
vendored
1771
third_party/duktape/duk_bi_date.c
vendored
File diff suppressed because it is too large
Load diff
325
third_party/duktape/duk_bi_date_unix.c
vendored
325
third_party/duktape/duk_bi_date_unix.c
vendored
|
@ -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
|
193
third_party/duktape/duk_bi_date_windows.c
vendored
193
third_party/duktape/duk_bi_date_windows.c
vendored
|
@ -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 */
|
158
third_party/duktape/duk_bi_duktape.c
vendored
158
third_party/duktape/duk_bi_duktape.c
vendored
|
@ -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 */
|
533
third_party/duktape/duk_bi_encoding.c
vendored
533
third_party/duktape/duk_bi_encoding.c
vendored
|
@ -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);
|
||||
}
|
387
third_party/duktape/duk_bi_error.c
vendored
387
third_party/duktape/duk_bi_error.c
vendored
|
@ -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);
|
||||
}
|
453
third_party/duktape/duk_bi_function.c
vendored
453
third_party/duktape/duk_bi_function.c
vendored
|
@ -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 */
|
785
third_party/duktape/duk_bi_global.c
vendored
785
third_party/duktape/duk_bi_global.c
vendored
|
@ -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 */
|
3255
third_party/duktape/duk_bi_json.c
vendored
3255
third_party/duktape/duk_bi_json.c
vendored
File diff suppressed because it is too large
Load diff
519
third_party/duktape/duk_bi_math.c
vendored
519
third_party/duktape/duk_bi_math.c
vendored
|
@ -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 */
|
280
third_party/duktape/duk_bi_number.c
vendored
280
third_party/duktape/duk_bi_number.c
vendored
|
@ -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 */
|
803
third_party/duktape/duk_bi_object.c
vendored
803
third_party/duktape/duk_bi_object.c
vendored
|
@ -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 */
|
31
third_party/duktape/duk_bi_performance.c
vendored
31
third_party/duktape/duk_bi_performance.c
vendored
|
@ -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 */
|
75
third_party/duktape/duk_bi_pointer.c
vendored
75
third_party/duktape/duk_bi_pointer.c
vendored
|
@ -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);
|
||||
}
|
44
third_party/duktape/duk_bi_promise.c
vendored
44
third_party/duktape/duk_bi_promise.c
vendored
|
@ -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 */
|
81
third_party/duktape/duk_bi_protos.h
vendored
81
third_party/duktape/duk_bi_protos.h
vendored
|
@ -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 */
|
96
third_party/duktape/duk_bi_proxy.c
vendored
96
third_party/duktape/duk_bi_proxy.c
vendored
|
@ -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 */
|
99
third_party/duktape/duk_bi_reflect.c
vendored
99
third_party/duktape/duk_bi_reflect.c
vendored
|
@ -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 */
|
226
third_party/duktape/duk_bi_regexp.c
vendored
226
third_party/duktape/duk_bi_regexp.c
vendored
|
@ -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 */
|
1634
third_party/duktape/duk_bi_string.c
vendored
1634
third_party/duktape/duk_bi_string.c
vendored
File diff suppressed because it is too large
Load diff
170
third_party/duktape/duk_bi_symbol.c
vendored
170
third_party/duktape/duk_bi_symbol.c
vendored
|
@ -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 */
|
326
third_party/duktape/duk_bi_thread.c
vendored
326
third_party/duktape/duk_bi_thread.c
vendored
|
@ -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
|
9
third_party/duktape/duk_bi_thrower.c
vendored
9
third_party/duktape/duk_bi_thrower.c
vendored
|
@ -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);
|
||||
}
|
861
third_party/duktape/duk_builtins.c
vendored
861
third_party/duktape/duk_builtins.c
vendored
|
@ -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 */
|
791
third_party/duktape/duk_builtins.h
vendored
791
third_party/duktape/duk_builtins.h
vendored
|
@ -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 */
|
2181
third_party/duktape/duk_config.h
vendored
2181
third_party/duktape/duk_config.h
vendored
File diff suppressed because it is too large
Load diff
424
third_party/duktape/duk_dblunion.h
vendored
424
third_party/duktape/duk_dblunion.h
vendored
|
@ -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 */
|
184
third_party/duktape/duk_debug.h
vendored
184
third_party/duktape/duk_debug.h
vendored
|
@ -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 */
|
69
third_party/duktape/duk_debug_fixedbuffer.c
vendored
69
third_party/duktape/duk_debug_fixedbuffer.c
vendored
|
@ -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 */
|
85
third_party/duktape/duk_debug_macros.c
vendored
85
third_party/duktape/duk_debug_macros.c
vendored
|
@ -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 */
|
1090
third_party/duktape/duk_debug_vsnprintf.c
vendored
1090
third_party/duktape/duk_debug_vsnprintf.c
vendored
File diff suppressed because it is too large
Load diff
2909
third_party/duktape/duk_debugger.c
vendored
2909
third_party/duktape/duk_debugger.c
vendored
File diff suppressed because it is too large
Load diff
151
third_party/duktape/duk_debugger.h
vendored
151
third_party/duktape/duk_debugger.h
vendored
|
@ -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 */
|
525
third_party/duktape/duk_error.h
vendored
525
third_party/duktape/duk_error.h
vendored
|
@ -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 */
|
588
third_party/duktape/duk_error_augment.c
vendored
588
third_party/duktape/duk_error_augment.c
vendored
|
@ -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 */
|
103
third_party/duktape/duk_error_longjmp.c
vendored
103
third_party/duktape/duk_error_longjmp.c
vendored
|
@ -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();
|
||||
}
|
152
third_party/duktape/duk_error_macros.c
vendored
152
third_party/duktape/duk_error_macros.c
vendored
|
@ -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. */
|
||||
}
|
||||
}
|
174
third_party/duktape/duk_error_misc.c
vendored
174
third_party/duktape/duk_error_misc.c
vendored
|
@ -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);
|
||||
}
|
162
third_party/duktape/duk_error_throw.c
vendored
162
third_party/duktape/duk_error_throw.c
vendored
|
@ -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;);
|
||||
}
|
30
third_party/duktape/duk_exception.h
vendored
30
third_party/duktape/duk_exception.h
vendored
|
@ -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 */
|
39
third_party/duktape/duk_fltunion.h
vendored
39
third_party/duktape/duk_fltunion.h
vendored
|
@ -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 */
|
134
third_party/duktape/duk_forwdecl.h
vendored
134
third_party/duktape/duk_forwdecl.h
vendored
|
@ -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 */
|
48
third_party/duktape/duk_harray.h
vendored
48
third_party/duktape/duk_harray.h
vendored
|
@ -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 */
|
37
third_party/duktape/duk_hboundfunc.h
vendored
37
third_party/duktape/duk_hboundfunc.h
vendored
|
@ -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 */
|
336
third_party/duktape/duk_hbuffer.h
vendored
336
third_party/duktape/duk_hbuffer.h
vendored
|
@ -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 */
|
132
third_party/duktape/duk_hbuffer_alloc.c
vendored
132
third_party/duktape/duk_hbuffer_alloc.c
vendored
|
@ -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);
|
||||
}
|
13
third_party/duktape/duk_hbuffer_assert.c
vendored
13
third_party/duktape/duk_hbuffer_assert.c
vendored
|
@ -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 */
|
78
third_party/duktape/duk_hbuffer_ops.c
vendored
78
third_party/duktape/duk_hbuffer_ops.c
vendored
|
@ -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);
|
||||
}
|
127
third_party/duktape/duk_hbufobj.h
vendored
127
third_party/duktape/duk_hbufobj.h
vendored
|
@ -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 */
|
20
third_party/duktape/duk_hbufobj_misc.c
vendored
20
third_party/duktape/duk_hbufobj_misc.c
vendored
|
@ -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 */
|
273
third_party/duktape/duk_hcompfunc.h
vendored
273
third_party/duktape/duk_hcompfunc.h
vendored
|
@ -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 */
|
723
third_party/duktape/duk_heap.h
vendored
723
third_party/duktape/duk_heap.h
vendored
|
@ -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 */
|
1217
third_party/duktape/duk_heap_alloc.c
vendored
1217
third_party/duktape/duk_heap_alloc.c
vendored
File diff suppressed because it is too large
Load diff
445
third_party/duktape/duk_heap_finalize.c
vendored
445
third_party/duktape/duk_heap_finalize.c
vendored
|
@ -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 */
|
116
third_party/duktape/duk_heap_hashstring.c
vendored
116
third_party/duktape/duk_heap_hashstring.c
vendored
|
@ -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 */
|
1482
third_party/duktape/duk_heap_markandsweep.c
vendored
1482
third_party/duktape/duk_heap_markandsweep.c
vendored
File diff suppressed because it is too large
Load diff
412
third_party/duktape/duk_heap_memory.c
vendored
412
third_party/duktape/duk_heap_memory.c
vendored
|
@ -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.
|
||||
*/
|
||||
}
|
187
third_party/duktape/duk_heap_misc.c
vendored
187
third_party/duktape/duk_heap_misc.c
vendored
|
@ -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
|
833
third_party/duktape/duk_heap_refcount.c
vendored
833
third_party/duktape/duk_heap_refcount.c
vendored
|
@ -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 */
|
309
third_party/duktape/duk_heap_stringcache.c
vendored
309
third_party/duktape/duk_heap_stringcache.c
vendored
|
@ -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;);
|
||||
}
|
1043
third_party/duktape/duk_heap_stringtable.c
vendored
1043
third_party/duktape/duk_heap_stringtable.c
vendored
File diff suppressed because it is too large
Load diff
297
third_party/duktape/duk_heaphdr.h
vendored
297
third_party/duktape/duk_heaphdr.h
vendored
|
@ -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 */
|
78
third_party/duktape/duk_heaphdr_assert.c
vendored
78
third_party/duktape/duk_heaphdr_assert.c
vendored
|
@ -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 */
|
45
third_party/duktape/duk_henv.h
vendored
45
third_party/duktape/duk_henv.h
vendored
|
@ -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 */
|
39
third_party/duktape/duk_hnatfunc.h
vendored
39
third_party/duktape/duk_hnatfunc.h
vendored
|
@ -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 */
|
981
third_party/duktape/duk_hobject.h
vendored
981
third_party/duktape/duk_hobject.h
vendored
|
@ -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 */
|
271
third_party/duktape/duk_hobject_alloc.c
vendored
271
third_party/duktape/duk_hobject_alloc.c
vendored
|
@ -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;
|
||||
}
|
127
third_party/duktape/duk_hobject_assert.c
vendored
127
third_party/duktape/duk_hobject_assert.c
vendored
|
@ -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 */
|
129
third_party/duktape/duk_hobject_class.c
vendored
129
third_party/duktape/duk_hobject_class.c
vendored
|
@ -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 */
|
||||
};
|
706
third_party/duktape/duk_hobject_enum.c
vendored
706
third_party/duktape/duk_hobject_enum.c
vendored
|
@ -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 */
|
||||
}
|
53
third_party/duktape/duk_hobject_misc.c
vendored
53
third_party/duktape/duk_hobject_misc.c
vendored
|
@ -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
|
||||
}
|
244
third_party/duktape/duk_hobject_pc2line.c
vendored
244
third_party/duktape/duk_hobject_pc2line.c
vendored
|
@ -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
Loading…
Reference in a new issue